summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-07-28 09:30:12 -0400
committerLibravatar GitHub <noreply@github.com>2018-07-28 09:30:12 -0400
commit53069f1403587d230e8f2c6adb61daa7c5e022b7 (patch)
tree67b966d2736ba19540b0102381710f9fb5316e61
parentMerge pull request #2368 from RyanDwyer/handle-out-of-fds (diff)
parentFocus child when showing a scratchpad container (diff)
downloadsway-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.h3
-rw-r--r--include/sway/tree/container.h11
-rw-r--r--include/sway/tree/view.h5
-rw-r--r--sway/commands/floating.c21
-rw-r--r--sway/commands/focus.c25
-rw-r--r--sway/commands/move.c19
-rw-r--r--sway/commands/scratchpad.c12
-rw-r--r--sway/commands/split.c4
-rw-r--r--sway/desktop/render.c2
-rw-r--r--sway/input/cursor.c16
-rw-r--r--sway/input/seat.c28
-rw-r--r--sway/scratchpad.c18
-rw-r--r--sway/tree/container.c90
-rw-r--r--sway/tree/layout.c19
-rw-r--r--sway/tree/view.c58
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);
124struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, 124struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
125 struct sway_container *container); 125 struct sway_container *container);
126 126
127struct 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 */
298size_t container_titlebar_height(void); 298size_t container_titlebar_height(void);
299 299
300/**
301 * Resize and center the container in its workspace.
302 */
303void container_init_floating(struct sway_container *container);
304
300void container_set_floating(struct sway_container *container, bool enable); 305void container_set_floating(struct sway_container *container, bool enable);
301 306
302void container_set_geometry_from_floating_view(struct sway_container *con); 307void container_set_geometry_from_floating_view(struct sway_container *con);
@@ -341,6 +346,12 @@ void container_end_mouse_operation(struct sway_container *container);
341void container_set_fullscreen(struct sway_container *container, bool enable); 346void 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 */
352bool 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 */
240void 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
300static struct cmd_results *move_to_scratchpad(struct sway_container *con) { 300static 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
11static struct cmd_results *do_split(int layout) { 11static 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
127static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, 127static 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
171struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, 177struct 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
176static void handle_seat_container_destroy(struct wl_listener *listener, 182static 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
866struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, 867struct 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
872struct 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
871struct sway_container *seat_get_active_child(struct sway_seat *seat, 877struct 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 */
412struct sway_container *container_destroy(struct sway_container *con) { 412struct 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
955void 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
951void container_set_floating(struct sway_container *container, bool enable) { 1016void 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
1268bool 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
1201bool container_is_fullscreen_or_child(struct sway_container *container) { 1279bool 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
171void 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
220void view_autoconfigure(struct sway_view *view) { 171void 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
1052bool view_is_visible(struct sway_view *view) { 1001bool 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