diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-07-28 09:30:12 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-28 09:30:12 -0400 |
commit | 53069f1403587d230e8f2c6adb61daa7c5e022b7 (patch) | |
tree | 67b966d2736ba19540b0102381710f9fb5316e61 | |
parent | Merge pull request #2368 from RyanDwyer/handle-out-of-fds (diff) | |
parent | Focus child when showing a scratchpad container (diff) | |
download | sway-53069f1403587d230e8f2c6adb61daa7c5e022b7.tar.gz sway-53069f1403587d230e8f2c6adb61daa7c5e022b7.tar.zst sway-53069f1403587d230e8f2c6adb61daa7c5e022b7.zip |
Merge pull request #2360 from RyanDwyer/floating-containers
Allow containers to float
-rw-r--r-- | include/sway/input/seat.h | 3 | ||||
-rw-r--r-- | include/sway/tree/container.h | 11 | ||||
-rw-r--r-- | include/sway/tree/view.h | 5 | ||||
-rw-r--r-- | sway/commands/floating.c | 21 | ||||
-rw-r--r-- | sway/commands/focus.c | 25 | ||||
-rw-r--r-- | sway/commands/move.c | 19 | ||||
-rw-r--r-- | sway/commands/scratchpad.c | 12 | ||||
-rw-r--r-- | sway/commands/split.c | 4 | ||||
-rw-r--r-- | sway/desktop/render.c | 2 | ||||
-rw-r--r-- | sway/input/cursor.c | 16 | ||||
-rw-r--r-- | sway/input/seat.c | 28 | ||||
-rw-r--r-- | sway/scratchpad.c | 18 | ||||
-rw-r--r-- | sway/tree/container.c | 90 | ||||
-rw-r--r-- | sway/tree/layout.c | 19 | ||||
-rw-r--r-- | sway/tree/view.c | 58 |
15 files changed, 218 insertions, 113 deletions
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index ab25788f..07febe2c 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -124,6 +124,9 @@ struct sway_container *seat_get_focus(struct sway_seat *seat); | |||
124 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | 124 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, |
125 | struct sway_container *container); | 125 | struct sway_container *container); |
126 | 126 | ||
127 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, | ||
128 | struct sway_container *container); | ||
129 | |||
127 | /** | 130 | /** |
128 | * Descend into the focus stack to find the focus-inactive view. Useful for | 131 | * Descend into the focus stack to find the focus-inactive view. Useful for |
129 | * container placement when they change position in the tree. | 132 | * container placement when they change position in the tree. |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index c584cd92..d91b3bf1 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -297,6 +297,11 @@ void container_notify_subtree_changed(struct sway_container *container); | |||
297 | */ | 297 | */ |
298 | size_t container_titlebar_height(void); | 298 | size_t container_titlebar_height(void); |
299 | 299 | ||
300 | /** | ||
301 | * Resize and center the container in its workspace. | ||
302 | */ | ||
303 | void container_init_floating(struct sway_container *container); | ||
304 | |||
300 | void container_set_floating(struct sway_container *container, bool enable); | 305 | void container_set_floating(struct sway_container *container, bool enable); |
301 | 306 | ||
302 | void container_set_geometry_from_floating_view(struct sway_container *con); | 307 | void container_set_geometry_from_floating_view(struct sway_container *con); |
@@ -341,6 +346,12 @@ void container_end_mouse_operation(struct sway_container *container); | |||
341 | void container_set_fullscreen(struct sway_container *container, bool enable); | 346 | void container_set_fullscreen(struct sway_container *container, bool enable); |
342 | 347 | ||
343 | /** | 348 | /** |
349 | * Return true if the container is floating, or a child of a floating split | ||
350 | * container. | ||
351 | */ | ||
352 | bool container_is_floating_or_child(struct sway_container *container); | ||
353 | |||
354 | /** | ||
344 | * Return true if the container is fullscreen, or a child of a fullscreen split | 355 | * Return true if the container is fullscreen, or a child of a fullscreen split |
345 | * container. | 356 | * container. |
346 | */ | 357 | */ |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 7086314f..0152ed55 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -235,11 +235,6 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, | |||
235 | int height); | 235 | int height); |
236 | 236 | ||
237 | /** | 237 | /** |
238 | * Center the view in its workspace and build the swayc decorations around it. | ||
239 | */ | ||
240 | void view_init_floating(struct sway_view *view); | ||
241 | |||
242 | /** | ||
243 | * Configure the view's position and size based on the swayc's position and | 238 | * Configure the view's position and size based on the swayc's position and |
244 | * size, taking borders into consideration. | 239 | * size, taking borders into consideration. |
245 | */ | 240 | */ |
diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 6ab56c3b..31de5ec3 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c | |||
@@ -17,9 +17,24 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
17 | } | 17 | } |
18 | struct sway_container *container = | 18 | struct sway_container *container = |
19 | config->handler_context.current_container; | 19 | config->handler_context.current_container; |
20 | if (container->type != C_VIEW) { | 20 | if (container->type == C_WORKSPACE && container->children->length == 0) { |
21 | // TODO: This doesn't strictly speaking have to be true | 21 | return cmd_results_new(CMD_INVALID, "floating", |
22 | return cmd_results_new(CMD_INVALID, "float", "Only views can float"); | 22 | "Can't float an empty workspace"); |
23 | } | ||
24 | if (container->type == C_WORKSPACE) { | ||
25 | // Wrap the workspace's children in a container so we can float it | ||
26 | struct sway_container *workspace = container; | ||
27 | container = container_wrap_children(container); | ||
28 | workspace->layout = L_HORIZ; | ||
29 | seat_set_focus(config->handler_context.seat, container); | ||
30 | } | ||
31 | |||
32 | // If the container is in a floating split container, | ||
33 | // operate on the split container instead of the child. | ||
34 | if (container_is_floating_or_child(container)) { | ||
35 | while (container->parent->layout != L_FLOATING) { | ||
36 | container = container->parent; | ||
37 | } | ||
23 | } | 38 | } |
24 | 39 | ||
25 | bool wants_floating; | 40 | bool wants_floating; |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 9cd8bfae..76d3f1dc 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -35,14 +35,25 @@ static struct cmd_results *focus_mode(struct sway_container *con, | |||
35 | struct sway_seat *seat, bool floating) { | 35 | struct sway_seat *seat, bool floating) { |
36 | struct sway_container *ws = con->type == C_WORKSPACE ? | 36 | struct sway_container *ws = con->type == C_WORKSPACE ? |
37 | con : container_parent(con, C_WORKSPACE); | 37 | con : container_parent(con, C_WORKSPACE); |
38 | struct sway_container *new_focus = ws; | 38 | |
39 | if (floating) { | 39 | // If the container is in a floating split container, |
40 | new_focus = ws->sway_workspace->floating; | 40 | // operate on the split container instead of the child. |
41 | if (new_focus->children->length == 0) { | 41 | if (container_is_floating_or_child(con)) { |
42 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 42 | while (con->parent->layout != L_FLOATING) { |
43 | con = con->parent; | ||
43 | } | 44 | } |
44 | } | 45 | } |
45 | seat_set_focus(seat, seat_get_active_child(seat, new_focus)); | 46 | |
47 | struct sway_container *new_focus = NULL; | ||
48 | if (floating) { | ||
49 | new_focus = seat_get_focus_inactive(seat, ws->sway_workspace->floating); | ||
50 | } else { | ||
51 | new_focus = seat_get_focus_inactive_tiling(seat, ws); | ||
52 | } | ||
53 | if (!new_focus) { | ||
54 | new_focus = ws; | ||
55 | } | ||
56 | seat_set_focus(seat, new_focus); | ||
46 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 57 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
47 | } | 58 | } |
48 | 59 | ||
@@ -97,7 +108,7 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
97 | } else if (strcmp(argv[0], "tiling") == 0) { | 108 | } else if (strcmp(argv[0], "tiling") == 0) { |
98 | return focus_mode(con, seat, false); | 109 | return focus_mode(con, seat, false); |
99 | } else if (strcmp(argv[0], "mode_toggle") == 0) { | 110 | } else if (strcmp(argv[0], "mode_toggle") == 0) { |
100 | return focus_mode(con, seat, !container_is_floating(con)); | 111 | return focus_mode(con, seat, !container_is_floating_or_child(con)); |
101 | } | 112 | } |
102 | 113 | ||
103 | if (strcmp(argv[0], "output") == 0) { | 114 | if (strcmp(argv[0], "output") == 0) { |
diff --git a/sway/commands/move.c b/sway/commands/move.c index aede3d6c..1aae3838 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -298,10 +298,25 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
298 | } | 298 | } |
299 | 299 | ||
300 | static struct cmd_results *move_to_scratchpad(struct sway_container *con) { | 300 | static struct cmd_results *move_to_scratchpad(struct sway_container *con) { |
301 | if (con->type != C_CONTAINER && con->type != C_VIEW) { | 301 | if (con->type == C_WORKSPACE && con->children->length == 0) { |
302 | return cmd_results_new(CMD_INVALID, "move", | 302 | return cmd_results_new(CMD_INVALID, "move", |
303 | "Only views and containers can be moved to the scratchpad"); | 303 | "Can't move an empty workspace to the scratchpad"); |
304 | } | 304 | } |
305 | if (con->type == C_WORKSPACE) { | ||
306 | // Wrap the workspace's children in a container | ||
307 | struct sway_container *workspace = con; | ||
308 | con = container_wrap_children(con); | ||
309 | workspace->layout = L_HORIZ; | ||
310 | } | ||
311 | |||
312 | // If the container is in a floating split container, | ||
313 | // operate on the split container instead of the child. | ||
314 | if (container_is_floating_or_child(con)) { | ||
315 | while (con->parent->layout != L_FLOATING) { | ||
316 | con = con->parent; | ||
317 | } | ||
318 | } | ||
319 | |||
305 | if (con->scratchpad) { | 320 | if (con->scratchpad) { |
306 | return cmd_results_new(CMD_INVALID, "move", | 321 | return cmd_results_new(CMD_INVALID, "move", |
307 | "Container is already in the scratchpad"); | 322 | "Container is already in the scratchpad"); |
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index ccc07c87..01a91d65 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c | |||
@@ -19,11 +19,19 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | if (config->handler_context.using_criteria) { | 21 | if (config->handler_context.using_criteria) { |
22 | struct sway_container *con = config->handler_context.current_container; | ||
23 | |||
24 | // If the container is in a floating split container, | ||
25 | // operate on the split container instead of the child. | ||
26 | if (container_is_floating_or_child(con)) { | ||
27 | while (con->parent->layout != L_FLOATING) { | ||
28 | con = con->parent; | ||
29 | } | ||
30 | } | ||
31 | |||
22 | // If using criteria, this command is executed for every container which | 32 | // If using criteria, this command is executed for every container which |
23 | // matches the criteria. If this container isn't in the scratchpad, | 33 | // matches the criteria. If this container isn't in the scratchpad, |
24 | // we'll just silently return a success. | 34 | // we'll just silently return a success. |
25 | struct sway_container *con = config->handler_context.current_container; | ||
26 | wlr_log(WLR_INFO, "cmd_scratchpad(%s)", con->name); | ||
27 | if (!con->scratchpad) { | 35 | if (!con->scratchpad) { |
28 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
29 | } | 37 | } |
diff --git a/sway/commands/split.c b/sway/commands/split.c index 313799da..a8eddf54 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c | |||
@@ -10,10 +10,6 @@ | |||
10 | 10 | ||
11 | static struct cmd_results *do_split(int layout) { | 11 | static struct cmd_results *do_split(int layout) { |
12 | struct sway_container *con = config->handler_context.current_container; | 12 | struct sway_container *con = config->handler_context.current_container; |
13 | if (container_is_floating(con)) { | ||
14 | return cmd_results_new(CMD_FAILURE, "split", | ||
15 | "Can't split a floating view"); | ||
16 | } | ||
17 | struct sway_container *parent = container_split(con, layout); | 13 | struct sway_container *parent = container_split(con, layout); |
18 | container_create_notify(parent); | 14 | container_create_notify(parent); |
19 | arrange_windows(parent->parent); | 15 | arrange_windows(parent->parent); |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index d2f1c9f2..c9fdfd95 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -779,7 +779,7 @@ static void render_floating_container(struct sway_output *soutput, | |||
779 | } | 779 | } |
780 | render_view(soutput, damage, con, colors); | 780 | render_view(soutput, damage, con, colors); |
781 | } else { | 781 | } else { |
782 | render_container(soutput, damage, con, false); | 782 | render_container(soutput, damage, con, con->current.focused); |
783 | } | 783 | } |
784 | } | 784 | } |
785 | 785 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index cc0dbe99..96ac7b33 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -437,18 +437,22 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | |||
437 | seat_pointer_notify_button(seat, time_msec, button, state); | 437 | seat_pointer_notify_button(seat, time_msec, button, state); |
438 | return; | 438 | return; |
439 | } | 439 | } |
440 | struct sway_container *floater = cont; | ||
441 | while (floater->parent->layout != L_FLOATING) { | ||
442 | floater = floater->parent; | ||
443 | } | ||
440 | 444 | ||
441 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | 445 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); |
442 | bool mod_pressed = keyboard && | 446 | bool mod_pressed = keyboard && |
443 | (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); | 447 | (wlr_keyboard_get_modifiers(keyboard) & config->floating_mod); |
444 | enum wlr_edges edge = find_resize_edge(cont, cursor); | 448 | enum wlr_edges edge = find_resize_edge(floater, cursor); |
445 | bool over_title = edge == WLR_EDGE_NONE && !surface; | 449 | bool over_title = edge == WLR_EDGE_NONE && !surface; |
446 | 450 | ||
447 | // Check for beginning move | 451 | // Check for beginning move |
448 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; | 452 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; |
449 | if (button == btn_move && state == WLR_BUTTON_PRESSED && | 453 | if (button == btn_move && state == WLR_BUTTON_PRESSED && |
450 | (mod_pressed || over_title)) { | 454 | (mod_pressed || over_title)) { |
451 | seat_begin_move(seat, cont, button); | 455 | seat_begin_move(seat, floater, button); |
452 | return; | 456 | return; |
453 | } | 457 | } |
454 | 458 | ||
@@ -459,12 +463,12 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | |||
459 | if ((resizing_via_border || resizing_via_mod) && | 463 | if ((resizing_via_border || resizing_via_mod) && |
460 | state == WLR_BUTTON_PRESSED) { | 464 | state == WLR_BUTTON_PRESSED) { |
461 | if (edge == WLR_EDGE_NONE) { | 465 | if (edge == WLR_EDGE_NONE) { |
462 | edge |= cursor->cursor->x > cont->x + cont->width / 2 ? | 466 | edge |= cursor->cursor->x > floater->x + floater->width / 2 ? |
463 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | 467 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; |
464 | edge |= cursor->cursor->y > cont->y + cont->height / 2 ? | 468 | edge |= cursor->cursor->y > floater->y + floater->height / 2 ? |
465 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | 469 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; |
466 | } | 470 | } |
467 | seat_begin_resize(seat, cont, button, edge); | 471 | seat_begin_resize(seat, floater, button, edge); |
468 | return; | 472 | return; |
469 | } | 473 | } |
470 | 474 | ||
@@ -598,7 +602,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
598 | seat_set_focus_layer(cursor->seat, layer); | 602 | seat_set_focus_layer(cursor->seat, layer); |
599 | } | 603 | } |
600 | seat_pointer_notify_button(cursor->seat, time_msec, button, state); | 604 | seat_pointer_notify_button(cursor->seat, time_msec, button, state); |
601 | } else if (cont && container_is_floating(cont)) { | 605 | } else if (cont && container_is_floating_or_child(cont)) { |
602 | dispatch_cursor_button_floating(cursor, time_msec, button, state, | 606 | dispatch_cursor_button_floating(cursor, time_msec, button, state, |
603 | surface, sx, sy, cont); | 607 | surface, sx, sy, cont); |
604 | } else if (surface && cont && cont->type != C_VIEW) { | 608 | } else if (surface && cont && cont->type != C_VIEW) { |
diff --git a/sway/input/seat.c b/sway/input/seat.c index b783a84f..53a92989 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -125,12 +125,14 @@ static void seat_send_focus(struct sway_container *con, | |||
125 | } | 125 | } |
126 | 126 | ||
127 | static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | 127 | static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, |
128 | struct sway_container *container, enum sway_container_type type) { | 128 | struct sway_container *container, enum sway_container_type type, |
129 | bool only_tiling) { | ||
129 | if (container->type == C_VIEW) { | 130 | if (container->type == C_VIEW) { |
130 | return container; | 131 | return container; |
131 | } | 132 | } |
132 | 133 | ||
133 | struct sway_container *floating = container->type == C_WORKSPACE ? | 134 | struct sway_container *floating = |
135 | container->type == C_WORKSPACE && !only_tiling ? | ||
134 | container->sway_workspace->floating : NULL; | 136 | container->sway_workspace->floating : NULL; |
135 | if (container->children->length == 0 && | 137 | if (container->children->length == 0 && |
136 | (!floating || floating->children->length == 0)) { | 138 | (!floating || floating->children->length == 0)) { |
@@ -144,6 +146,10 @@ static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | |||
144 | } | 146 | } |
145 | 147 | ||
146 | if (container_has_child(container, current->container)) { | 148 | if (container_has_child(container, current->container)) { |
149 | if (only_tiling && | ||
150 | container_is_floating_or_child(current->container)) { | ||
151 | continue; | ||
152 | } | ||
147 | return current->container; | 153 | return current->container; |
148 | } | 154 | } |
149 | if (floating && container_has_child(floating, current->container)) { | 155 | if (floating && container_has_child(floating, current->container)) { |
@@ -170,7 +176,7 @@ void seat_focus_inactive_children_for_each(struct sway_seat *seat, | |||
170 | 176 | ||
171 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, | 177 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, |
172 | struct sway_container *container) { | 178 | struct sway_container *container) { |
173 | return seat_get_focus_by_type(seat, container, C_VIEW); | 179 | return seat_get_focus_by_type(seat, container, C_VIEW, false); |
174 | } | 180 | } |
175 | 181 | ||
176 | static void handle_seat_container_destroy(struct wl_listener *listener, | 182 | static void handle_seat_container_destroy(struct wl_listener *listener, |
@@ -185,7 +191,6 @@ static void handle_seat_container_destroy(struct wl_listener *listener, | |||
185 | bool set_focus = | 191 | bool set_focus = |
186 | focus != NULL && | 192 | focus != NULL && |
187 | (focus == con || container_has_child(con, focus)) && | 193 | (focus == con || container_has_child(con, focus)) && |
188 | con->parent && con->parent->children->length > 1 && | ||
189 | con->type != C_WORKSPACE; | 194 | con->type != C_WORKSPACE; |
190 | 195 | ||
191 | seat_container_destroy(seat_con); | 196 | seat_container_destroy(seat_con); |
@@ -193,7 +198,7 @@ static void handle_seat_container_destroy(struct wl_listener *listener, | |||
193 | if (set_focus) { | 198 | if (set_focus) { |
194 | struct sway_container *next_focus = NULL; | 199 | struct sway_container *next_focus = NULL; |
195 | while (next_focus == NULL) { | 200 | while (next_focus == NULL) { |
196 | next_focus = seat_get_focus_by_type(seat, parent, C_VIEW); | 201 | next_focus = seat_get_focus_by_type(seat, parent, C_VIEW, false); |
197 | 202 | ||
198 | if (next_focus == NULL && parent->type == C_WORKSPACE) { | 203 | if (next_focus == NULL && parent->type == C_WORKSPACE) { |
199 | next_focus = parent; | 204 | next_focus = parent; |
@@ -650,7 +655,7 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
650 | struct sway_container *new_output_last_ws = NULL; | 655 | struct sway_container *new_output_last_ws = NULL; |
651 | if (last_output && new_output && last_output != new_output) { | 656 | if (last_output && new_output && last_output != new_output) { |
652 | new_output_last_ws = | 657 | new_output_last_ws = |
653 | seat_get_focus_by_type(seat, new_output, C_WORKSPACE); | 658 | seat_get_focus_by_type(seat, new_output, C_WORKSPACE, false); |
654 | } | 659 | } |
655 | 660 | ||
656 | if (container && container->parent) { | 661 | if (container && container->parent) { |
@@ -761,10 +766,6 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
761 | } | 766 | } |
762 | } | 767 | } |
763 | 768 | ||
764 | if (last_focus != NULL) { | ||
765 | cursor_send_pointer_motion(seat->cursor, 0, true); | ||
766 | } | ||
767 | |||
768 | seat->has_focus = (container != NULL); | 769 | seat->has_focus = (container != NULL); |
769 | 770 | ||
770 | update_debug_tree(); | 771 | update_debug_tree(); |
@@ -865,7 +866,12 @@ void seat_set_exclusive_client(struct sway_seat *seat, | |||
865 | 866 | ||
866 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | 867 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, |
867 | struct sway_container *container) { | 868 | struct sway_container *container) { |
868 | return seat_get_focus_by_type(seat, container, C_TYPES); | 869 | return seat_get_focus_by_type(seat, container, C_TYPES, false); |
870 | } | ||
871 | |||
872 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, | ||
873 | struct sway_container *container) { | ||
874 | return seat_get_focus_by_type(seat, container, C_TYPES, true); | ||
869 | } | 875 | } |
870 | 876 | ||
871 | struct sway_container *seat_get_active_child(struct sway_seat *seat, | 877 | struct sway_container *seat_get_active_child(struct sway_seat *seat, |
diff --git a/sway/scratchpad.c b/sway/scratchpad.c index 64636c77..b7d6fd99 100644 --- a/sway/scratchpad.c +++ b/sway/scratchpad.c | |||
@@ -72,11 +72,7 @@ static void scratchpad_show(struct sway_container *con) { | |||
72 | if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { | 72 | if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { |
73 | // Maybe resize it | 73 | // Maybe resize it |
74 | if (con->width > ws->width || con->height > ws->height) { | 74 | if (con->width > ws->width || con->height > ws->height) { |
75 | // TODO: Do this properly once we can float C_CONTAINERs | 75 | container_init_floating(con); |
76 | if (con->type == C_VIEW) { | ||
77 | view_init_floating(con->sway_view); | ||
78 | arrange_windows(con); | ||
79 | } | ||
80 | } | 76 | } |
81 | 77 | ||
82 | // Center it | 78 | // Center it |
@@ -85,7 +81,8 @@ static void scratchpad_show(struct sway_container *con) { | |||
85 | container_floating_move_to(con, new_lx, new_ly); | 81 | container_floating_move_to(con, new_lx, new_ly); |
86 | } | 82 | } |
87 | 83 | ||
88 | seat_set_focus(seat, con); | 84 | arrange_windows(ws); |
85 | seat_set_focus(seat, seat_get_focus_inactive(seat, con)); | ||
89 | 86 | ||
90 | container_set_dirty(con->parent); | 87 | container_set_dirty(con->parent); |
91 | } | 88 | } |
@@ -113,6 +110,15 @@ void scratchpad_toggle_auto(void) { | |||
113 | struct sway_container *ws = focus->type == C_WORKSPACE ? | 110 | struct sway_container *ws = focus->type == C_WORKSPACE ? |
114 | focus : container_parent(focus, C_WORKSPACE); | 111 | focus : container_parent(focus, C_WORKSPACE); |
115 | 112 | ||
113 | // If the focus is in a floating split container, | ||
114 | // operate on the split container instead of the child. | ||
115 | if (container_is_floating_or_child(focus)) { | ||
116 | while (focus->parent->layout != L_FLOATING) { | ||
117 | focus = focus->parent; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | |||
116 | // Check if the currently focused window is a scratchpad window and should | 122 | // Check if the currently focused window is a scratchpad window and should |
117 | // be hidden again. | 123 | // be hidden again. |
118 | if (focus->scratchpad) { | 124 | if (focus->scratchpad) { |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 01387636..b7442002 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -410,6 +410,10 @@ struct sway_container *container_flatten(struct sway_container *container) { | |||
410 | * This function just wraps container_destroy_noreaping(), then does reaping. | 410 | * This function just wraps container_destroy_noreaping(), then does reaping. |
411 | */ | 411 | */ |
412 | struct sway_container *container_destroy(struct sway_container *con) { | 412 | struct sway_container *container_destroy(struct sway_container *con) { |
413 | if (con->is_fullscreen) { | ||
414 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | ||
415 | ws->sway_workspace->fullscreen = NULL; | ||
416 | } | ||
413 | struct sway_container *parent = container_destroy_noreaping(con); | 417 | struct sway_container *parent = container_destroy_noreaping(con); |
414 | 418 | ||
415 | if (!parent) { | 419 | if (!parent) { |
@@ -948,37 +952,100 @@ size_t container_titlebar_height() { | |||
948 | return config->font_height + TITLEBAR_V_PADDING * 2; | 952 | return config->font_height + TITLEBAR_V_PADDING * 2; |
949 | } | 953 | } |
950 | 954 | ||
955 | void container_init_floating(struct sway_container *con) { | ||
956 | if (!sway_assert(con->type == C_VIEW || con->type == C_CONTAINER, | ||
957 | "Expected a view or container")) { | ||
958 | return; | ||
959 | } | ||
960 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | ||
961 | int min_width, min_height; | ||
962 | int max_width, max_height; | ||
963 | |||
964 | if (config->floating_minimum_width == -1) { // no minimum | ||
965 | min_width = 0; | ||
966 | } else if (config->floating_minimum_width == 0) { // automatic | ||
967 | min_width = 75; | ||
968 | } else { | ||
969 | min_width = config->floating_minimum_width; | ||
970 | } | ||
971 | |||
972 | if (config->floating_minimum_height == -1) { // no minimum | ||
973 | min_height = 0; | ||
974 | } else if (config->floating_minimum_height == 0) { // automatic | ||
975 | min_height = 50; | ||
976 | } else { | ||
977 | min_height = config->floating_minimum_height; | ||
978 | } | ||
979 | |||
980 | if (config->floating_maximum_width == -1) { // no maximum | ||
981 | max_width = INT_MAX; | ||
982 | } else if (config->floating_maximum_width == 0) { // automatic | ||
983 | max_width = ws->width * 0.6666; | ||
984 | } else { | ||
985 | max_width = config->floating_maximum_width; | ||
986 | } | ||
987 | |||
988 | if (config->floating_maximum_height == -1) { // no maximum | ||
989 | max_height = INT_MAX; | ||
990 | } else if (config->floating_maximum_height == 0) { // automatic | ||
991 | max_height = ws->height * 0.6666; | ||
992 | } else { | ||
993 | max_height = config->floating_maximum_height; | ||
994 | } | ||
995 | |||
996 | if (con->type == C_CONTAINER) { | ||
997 | con->width = max_width; | ||
998 | con->height = max_height; | ||
999 | con->x = ws->x + (ws->width - con->width) / 2; | ||
1000 | con->y = ws->y + (ws->height - con->height) / 2; | ||
1001 | } else { | ||
1002 | struct sway_view *view = con->sway_view; | ||
1003 | view->width = fmax(min_width, fmin(view->natural_width, max_width)); | ||
1004 | view->height = fmax(min_height, fmin(view->natural_height, max_height)); | ||
1005 | view->x = ws->x + (ws->width - view->width) / 2; | ||
1006 | view->y = ws->y + (ws->height - view->height) / 2; | ||
1007 | |||
1008 | // If the view's border is B_NONE then these properties are ignored. | ||
1009 | view->border_top = view->border_bottom = true; | ||
1010 | view->border_left = view->border_right = true; | ||
1011 | |||
1012 | container_set_geometry_from_floating_view(view->swayc); | ||
1013 | } | ||
1014 | } | ||
1015 | |||
951 | void container_set_floating(struct sway_container *container, bool enable) { | 1016 | void container_set_floating(struct sway_container *container, bool enable) { |
952 | if (container_is_floating(container) == enable) { | 1017 | if (container_is_floating(container) == enable) { |
953 | return; | 1018 | return; |
954 | } | 1019 | } |
955 | 1020 | ||
956 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | ||
957 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 1021 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
1022 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | ||
958 | 1023 | ||
959 | if (enable) { | 1024 | if (enable) { |
960 | container_remove_child(container); | 1025 | container_remove_child(container); |
961 | container_add_child(workspace->sway_workspace->floating, container); | 1026 | container_add_child(workspace->sway_workspace->floating, container); |
1027 | container_init_floating(container); | ||
962 | if (container->type == C_VIEW) { | 1028 | if (container->type == C_VIEW) { |
963 | view_init_floating(container->sway_view); | ||
964 | view_set_tiled(container->sway_view, false); | 1029 | view_set_tiled(container->sway_view, false); |
965 | } | 1030 | } |
966 | seat_set_focus(seat, seat_get_focus_inactive(seat, container)); | ||
967 | container_reap_empty_recursive(workspace); | ||
968 | } else { | 1031 | } else { |
969 | // Returning to tiled | 1032 | // Returning to tiled |
970 | if (container->scratchpad) { | 1033 | if (container->scratchpad) { |
971 | scratchpad_remove_container(container); | 1034 | scratchpad_remove_container(container); |
972 | } | 1035 | } |
973 | container_remove_child(container); | 1036 | container_remove_child(container); |
974 | container_add_child(workspace, container); | 1037 | struct sway_container *reference = |
1038 | seat_get_focus_inactive_tiling(seat, workspace); | ||
1039 | if (reference->type == C_VIEW) { | ||
1040 | reference = reference->parent; | ||
1041 | } | ||
1042 | container_add_child(reference, container); | ||
975 | container->width = container->parent->width; | 1043 | container->width = container->parent->width; |
976 | container->height = container->parent->height; | 1044 | container->height = container->parent->height; |
977 | if (container->type == C_VIEW) { | 1045 | if (container->type == C_VIEW) { |
978 | view_set_tiled(container->sway_view, true); | 1046 | view_set_tiled(container->sway_view, true); |
979 | } | 1047 | } |
980 | container->is_sticky = false; | 1048 | container->is_sticky = false; |
981 | container_reap_empty_recursive(workspace->sway_workspace->floating); | ||
982 | } | 1049 | } |
983 | 1050 | ||
984 | container_end_mouse_operation(container); | 1051 | container_end_mouse_operation(container); |
@@ -1198,6 +1265,17 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { | |||
1198 | ipc_event_window(container, "fullscreen_mode"); | 1265 | ipc_event_window(container, "fullscreen_mode"); |
1199 | } | 1266 | } |
1200 | 1267 | ||
1268 | bool container_is_floating_or_child(struct sway_container *container) { | ||
1269 | do { | ||
1270 | if (container->parent && container->parent->layout == L_FLOATING) { | ||
1271 | return true; | ||
1272 | } | ||
1273 | container = container->parent; | ||
1274 | } while (container && container->type != C_WORKSPACE); | ||
1275 | |||
1276 | return false; | ||
1277 | } | ||
1278 | |||
1201 | bool container_is_fullscreen_or_child(struct sway_container *container) { | 1279 | bool container_is_fullscreen_or_child(struct sway_container *container) { |
1202 | do { | 1280 | do { |
1203 | if (container->is_fullscreen) { | 1281 | if (container->is_fullscreen) { |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index ab5acc16..a0764a54 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -387,9 +387,11 @@ void container_move(struct sway_container *container, | |||
387 | // If moving a fullscreen view, only consider outputs | 387 | // If moving a fullscreen view, only consider outputs |
388 | if (container->is_fullscreen) { | 388 | if (container->is_fullscreen) { |
389 | current = container_parent(container, C_OUTPUT); | 389 | current = container_parent(container, C_OUTPUT); |
390 | } else if (container_is_fullscreen_or_child(container)) { | 390 | } else if (container_is_fullscreen_or_child(container) || |
391 | container_is_floating_or_child(container)) { | ||
391 | // If we've fullscreened a split container, only allow the child to move | 392 | // If we've fullscreened a split container, only allow the child to move |
392 | // around within the fullscreen parent. | 393 | // around within the fullscreen parent. |
394 | // Same with floating a split container. | ||
393 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | 395 | struct sway_container *ws = container_parent(container, C_WORKSPACE); |
394 | top = ws->sway_workspace->fullscreen; | 396 | top = ws->sway_workspace->fullscreen; |
395 | } | 397 | } |
@@ -465,6 +467,9 @@ void container_move(struct sway_container *container, | |||
465 | if ((index == parent->children->length - 1 && offs > 0) | 467 | if ((index == parent->children->length - 1 && offs > 0) |
466 | || (index == 0 && offs < 0)) { | 468 | || (index == 0 && offs < 0)) { |
467 | if (current->parent == container->parent) { | 469 | if (current->parent == container->parent) { |
470 | if (parent->parent->layout == L_FLOATING) { | ||
471 | return; | ||
472 | } | ||
468 | if (!parent->is_fullscreen && | 473 | if (!parent->is_fullscreen && |
469 | (parent->layout == L_TABBED || | 474 | (parent->layout == L_TABBED || |
470 | parent->layout == L_STACKED)) { | 475 | parent->layout == L_STACKED)) { |
@@ -488,10 +493,14 @@ void container_move(struct sway_container *container, | |||
488 | sibling = parent->children->items[index + offs]; | 493 | sibling = parent->children->items[index + offs]; |
489 | wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); | 494 | wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); |
490 | } | 495 | } |
491 | } else if (!parent->is_fullscreen && (parent->layout == L_TABBED || | 496 | } else if (!parent->is_fullscreen && |
497 | parent->parent->layout != L_FLOATING && | ||
498 | (parent->layout == L_TABBED || | ||
492 | parent->layout == L_STACKED)) { | 499 | parent->layout == L_STACKED)) { |
493 | move_out_of_tabs_stacks(container, current, move_dir, offs); | 500 | move_out_of_tabs_stacks(container, current, move_dir, offs); |
494 | return; | 501 | return; |
502 | } else if (parent->parent->layout == L_FLOATING) { | ||
503 | return; | ||
495 | } else { | 504 | } else { |
496 | wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); | 505 | wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); |
497 | current = current->parent; | 506 | current = current->parent; |
@@ -717,10 +726,6 @@ struct sway_container *container_get_in_direction( | |||
717 | enum movement_direction dir) { | 726 | enum movement_direction dir) { |
718 | struct sway_container *parent = container->parent; | 727 | struct sway_container *parent = container->parent; |
719 | 728 | ||
720 | if (container_is_floating(container)) { | ||
721 | return NULL; | ||
722 | } | ||
723 | |||
724 | if (dir == MOVE_CHILD) { | 729 | if (dir == MOVE_CHILD) { |
725 | return seat_get_focus_inactive(seat, container); | 730 | return seat_get_focus_inactive(seat, container); |
726 | } | 731 | } |
@@ -732,7 +737,7 @@ struct sway_container *container_get_in_direction( | |||
732 | parent = container->parent; | 737 | parent = container->parent; |
733 | } else { | 738 | } else { |
734 | if (dir == MOVE_PARENT) { | 739 | if (dir == MOVE_PARENT) { |
735 | if (parent->type == C_OUTPUT) { | 740 | if (parent->type == C_OUTPUT || container_is_floating(container)) { |
736 | return NULL; | 741 | return NULL; |
737 | } else { | 742 | } else { |
738 | return parent; | 743 | return parent; |
diff --git a/sway/tree/view.c b/sway/tree/view.c index e641544e..8f54cc11 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -168,55 +168,6 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, | |||
168 | return 0; | 168 | return 0; |
169 | } | 169 | } |
170 | 170 | ||
171 | void view_init_floating(struct sway_view *view) { | ||
172 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | ||
173 | int min_width, min_height; | ||
174 | int max_width, max_height; | ||
175 | |||
176 | if (config->floating_minimum_width == -1) { // no minimum | ||
177 | min_width = 0; | ||
178 | } else if (config->floating_minimum_width == 0) { // automatic | ||
179 | min_width = 75; | ||
180 | } else { | ||
181 | min_width = config->floating_minimum_width; | ||
182 | } | ||
183 | |||
184 | if (config->floating_minimum_height == -1) { // no minimum | ||
185 | min_height = 0; | ||
186 | } else if (config->floating_minimum_height == 0) { // automatic | ||
187 | min_height = 50; | ||
188 | } else { | ||
189 | min_height = config->floating_minimum_height; | ||
190 | } | ||
191 | |||
192 | if (config->floating_maximum_width == -1) { // no maximum | ||
193 | max_width = INT_MAX; | ||
194 | } else if (config->floating_maximum_width == 0) { // automatic | ||
195 | max_width = ws->width * 0.6666; | ||
196 | } else { | ||
197 | max_width = config->floating_maximum_width; | ||
198 | } | ||
199 | |||
200 | if (config->floating_maximum_height == -1) { // no maximum | ||
201 | max_height = INT_MAX; | ||
202 | } else if (config->floating_maximum_height == 0) { // automatic | ||
203 | max_height = ws->height * 0.6666; | ||
204 | } else { | ||
205 | max_height = config->floating_maximum_height; | ||
206 | } | ||
207 | |||
208 | view->width = fmax(min_width, fmin(view->natural_width, max_width)); | ||
209 | view->height = fmax(min_height, fmin(view->natural_height, max_height)); | ||
210 | view->x = ws->x + (ws->width - view->width) / 2; | ||
211 | view->y = ws->y + (ws->height - view->height) / 2; | ||
212 | |||
213 | // If the view's border is B_NONE then these properties are ignored. | ||
214 | view->border_top = view->border_bottom = true; | ||
215 | view->border_left = view->border_right = true; | ||
216 | |||
217 | container_set_geometry_from_floating_view(view->swayc); | ||
218 | } | ||
219 | |||
220 | void view_autoconfigure(struct sway_view *view) { | 171 | void view_autoconfigure(struct sway_view *view) { |
221 | if (!sway_assert(view->swayc, | 172 | if (!sway_assert(view->swayc, |
222 | "Called view_autoconfigure() on a view without a swayc")) { | 173 | "Called view_autoconfigure() on a view without a swayc")) { |
@@ -626,10 +577,8 @@ void view_unmap(struct sway_view *view) { | |||
626 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 577 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); |
627 | 578 | ||
628 | struct sway_container *parent; | 579 | struct sway_container *parent; |
629 | if (view->swayc->is_fullscreen) { | 580 | if (container_is_fullscreen_or_child(view->swayc)) { |
630 | ws->sway_workspace->fullscreen = NULL; | ||
631 | parent = container_destroy(view->swayc); | 581 | parent = container_destroy(view->swayc); |
632 | |||
633 | arrange_windows(ws->parent); | 582 | arrange_windows(ws->parent); |
634 | } else { | 583 | } else { |
635 | parent = container_destroy(view->swayc); | 584 | parent = container_destroy(view->swayc); |
@@ -1050,11 +999,14 @@ void view_update_marks_textures(struct sway_view *view) { | |||
1050 | } | 999 | } |
1051 | 1000 | ||
1052 | bool view_is_visible(struct sway_view *view) { | 1001 | bool view_is_visible(struct sway_view *view) { |
1053 | if (!view->swayc || view->swayc->destroying || !view->swayc->parent) { | 1002 | if (!view->swayc || view->swayc->destroying) { |
1054 | return false; | 1003 | return false; |
1055 | } | 1004 | } |
1056 | struct sway_container *workspace = | 1005 | struct sway_container *workspace = |
1057 | container_parent(view->swayc, C_WORKSPACE); | 1006 | container_parent(view->swayc, C_WORKSPACE); |
1007 | if (!workspace) { | ||
1008 | return false; | ||
1009 | } | ||
1058 | // Determine if view is nested inside a floating container which is sticky. | 1010 | // Determine if view is nested inside a floating container which is sticky. |
1059 | // A simple floating view will have this ancestry: | 1011 | // A simple floating view will have this ancestry: |
1060 | // C_VIEW -> floating -> workspace | 1012 | // C_VIEW -> floating -> workspace |