diff options
-rw-r--r-- | include/sway/tree/container.h | 23 | ||||
-rw-r--r-- | include/sway/tree/view.h | 15 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 3 | ||||
-rw-r--r-- | sway/commands.c | 4 | ||||
-rw-r--r-- | sway/commands/border.c | 8 | ||||
-rw-r--r-- | sway/commands/floating.c | 40 | ||||
-rw-r--r-- | sway/commands/layout.c | 10 | ||||
-rw-r--r-- | sway/commands/move.c | 6 | ||||
-rw-r--r-- | sway/commands/split.c | 15 | ||||
-rw-r--r-- | sway/commands/sticky.c | 40 | ||||
-rw-r--r-- | sway/config.c | 11 | ||||
-rw-r--r-- | sway/criteria.c | 9 | ||||
-rw-r--r-- | sway/debug-tree.c | 2 | ||||
-rw-r--r-- | sway/desktop/output.c | 112 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 35 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 35 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 52 | ||||
-rw-r--r-- | sway/input/cursor.c | 15 | ||||
-rw-r--r-- | sway/input/seat.c | 22 | ||||
-rw-r--r-- | sway/ipc-json.c | 10 | ||||
-rw-r--r-- | sway/meson.build | 2 | ||||
-rw-r--r-- | sway/tree/arrange.c | 16 | ||||
-rw-r--r-- | sway/tree/container.c | 169 | ||||
-rw-r--r-- | sway/tree/layout.c | 54 | ||||
-rw-r--r-- | sway/tree/view.c | 126 | ||||
-rw-r--r-- | sway/tree/workspace.c | 48 |
26 files changed, 662 insertions, 220 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index bb6c04a6..7ed6aab1 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -76,12 +76,14 @@ struct sway_container { | |||
76 | enum sway_container_layout layout; | 76 | enum sway_container_layout layout; |
77 | enum sway_container_layout prev_layout; | 77 | enum sway_container_layout prev_layout; |
78 | 78 | ||
79 | bool is_sticky; | ||
80 | |||
79 | // For C_ROOT, this has no meaning | 81 | // For C_ROOT, this has no meaning |
80 | // For C_OUTPUT, this is the output position in layout coordinates | 82 | // For other types, this is the position in layout coordinates |
81 | // For other types, this is the position in output-local coordinates | ||
82 | // Includes borders | 83 | // Includes borders |
83 | double x, y; | 84 | double x, y; |
84 | double width, height; | 85 | double width, height; |
86 | double saved_x, saved_y; | ||
85 | double saved_width, saved_height; | 87 | double saved_width, saved_height; |
86 | 88 | ||
87 | list_t *children; | 89 | list_t *children; |
@@ -172,6 +174,13 @@ struct sway_container *container_at(struct sway_container *container, | |||
172 | double *sx, double *sy); | 174 | double *sx, double *sy); |
173 | 175 | ||
174 | /** | 176 | /** |
177 | * Same as container_at, but only checks floating views and expects coordinates | ||
178 | * to be layout coordinates, as that's what floating views use. | ||
179 | */ | ||
180 | struct sway_container *floating_container_at(double lx, double ly, | ||
181 | struct wlr_surface **surface, double *sx, double *sy); | ||
182 | |||
183 | /** | ||
175 | * Apply the function for each descendant of the container breadth first. | 184 | * Apply the function for each descendant of the container breadth first. |
176 | */ | 185 | */ |
177 | void container_for_each_descendant_bfs(struct sway_container *container, | 186 | void container_for_each_descendant_bfs(struct sway_container *container, |
@@ -227,4 +236,14 @@ void container_notify_subtree_changed(struct sway_container *container); | |||
227 | */ | 236 | */ |
228 | size_t container_titlebar_height(void); | 237 | size_t container_titlebar_height(void); |
229 | 238 | ||
239 | void container_set_floating(struct sway_container *container, bool enable); | ||
240 | |||
241 | void container_set_geometry_from_floating_view(struct sway_container *con); | ||
242 | |||
243 | /** | ||
244 | * Determine if the given container is itself floating. | ||
245 | * This will return false for any descendants of a floating container. | ||
246 | */ | ||
247 | bool container_is_floating(struct sway_container *container); | ||
248 | |||
230 | #endif | 249 | #endif |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index a8bf4955..3df38e2d 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -29,10 +29,11 @@ struct sway_view_impl { | |||
29 | const char *(*get_string_prop)(struct sway_view *view, | 29 | const char *(*get_string_prop)(struct sway_view *view, |
30 | enum sway_view_prop prop); | 30 | enum sway_view_prop prop); |
31 | uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop); | 31 | uint32_t (*get_int_prop)(struct sway_view *view, enum sway_view_prop prop); |
32 | void (*configure)(struct sway_view *view, double ox, double oy, int width, | 32 | void (*configure)(struct sway_view *view, double lx, double ly, int width, |
33 | int height); | 33 | int height); |
34 | void (*set_activated)(struct sway_view *view, bool activated); | 34 | void (*set_activated)(struct sway_view *view, bool activated); |
35 | void (*set_fullscreen)(struct sway_view *view, bool fullscreen); | 35 | void (*set_fullscreen)(struct sway_view *view, bool fullscreen); |
36 | bool (*wants_floating)(struct sway_view *view); | ||
36 | void (*for_each_surface)(struct sway_view *view, | 37 | void (*for_each_surface)(struct sway_view *view, |
37 | wlr_surface_iterator_func_t iterator, void *user_data); | 38 | wlr_surface_iterator_func_t iterator, void *user_data); |
38 | void (*close)(struct sway_view *view); | 39 | void (*close)(struct sway_view *view); |
@@ -46,10 +47,17 @@ struct sway_view { | |||
46 | struct sway_container *swayc; // NULL for unmapped views | 47 | struct sway_container *swayc; // NULL for unmapped views |
47 | struct wlr_surface *surface; // NULL for unmapped views | 48 | struct wlr_surface *surface; // NULL for unmapped views |
48 | 49 | ||
49 | // Geometry of the view itself (excludes borders) | 50 | // Geometry of the view itself (excludes borders) in layout coordinates |
50 | double x, y; | 51 | double x, y; |
51 | int width, height; | 52 | int width, height; |
52 | 53 | ||
54 | double saved_x, saved_y; | ||
55 | int saved_width, saved_height; | ||
56 | |||
57 | // The size the view would want to be if it weren't tiled. | ||
58 | // Used when changing a view from tiled to floating. | ||
59 | int natural_width, natural_height; | ||
60 | |||
53 | bool is_fullscreen; | 61 | bool is_fullscreen; |
54 | 62 | ||
55 | char *title_format; | 63 | char *title_format; |
@@ -131,6 +139,7 @@ struct sway_xwayland_view { | |||
131 | struct wl_listener unmap; | 139 | struct wl_listener unmap; |
132 | struct wl_listener destroy; | 140 | struct wl_listener destroy; |
133 | 141 | ||
142 | int pending_lx, pending_ly; | ||
134 | int pending_width, pending_height; | 143 | int pending_width, pending_height; |
135 | }; | 144 | }; |
136 | 145 | ||
@@ -236,7 +245,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface); | |||
236 | 245 | ||
237 | void view_unmap(struct sway_view *view); | 246 | void view_unmap(struct sway_view *view); |
238 | 247 | ||
239 | void view_update_position(struct sway_view *view, double ox, double oy); | 248 | void view_update_position(struct sway_view *view, double lx, double ly); |
240 | 249 | ||
241 | void view_update_size(struct sway_view *view, int width, int height); | 250 | void view_update_size(struct sway_view *view, int width, int height); |
242 | 251 | ||
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 35e1df3b..81321fc8 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -8,6 +8,7 @@ struct sway_view; | |||
8 | struct sway_workspace { | 8 | struct sway_workspace { |
9 | struct sway_container *swayc; | 9 | struct sway_container *swayc; |
10 | struct sway_view *fullscreen; | 10 | struct sway_view *fullscreen; |
11 | struct sway_container *floating; | ||
11 | }; | 12 | }; |
12 | 13 | ||
13 | extern char *prev_workspace_name; | 14 | extern char *prev_workspace_name; |
@@ -30,4 +31,6 @@ struct sway_container *workspace_prev(struct sway_container *current); | |||
30 | 31 | ||
31 | bool workspace_is_visible(struct sway_container *ws); | 32 | bool workspace_is_visible(struct sway_container *ws); |
32 | 33 | ||
34 | bool workspace_is_empty(struct sway_container *ws); | ||
35 | |||
33 | #endif | 36 | #endif |
diff --git a/sway/commands.c b/sway/commands.c index 6f5113f8..e9762bef 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -110,7 +110,6 @@ static struct cmd_handler handlers[] = { | |||
110 | { "font", cmd_font }, | 110 | { "font", cmd_font }, |
111 | { "for_window", cmd_for_window }, | 111 | { "for_window", cmd_for_window }, |
112 | { "force_focus_wrapping", cmd_force_focus_wrapping }, | 112 | { "force_focus_wrapping", cmd_force_focus_wrapping }, |
113 | { "fullscreen", cmd_fullscreen }, | ||
114 | { "hide_edge_borders", cmd_hide_edge_borders }, | 113 | { "hide_edge_borders", cmd_hide_edge_borders }, |
115 | { "include", cmd_include }, | 114 | { "include", cmd_include }, |
116 | { "input", cmd_input }, | 115 | { "input", cmd_input }, |
@@ -176,7 +175,9 @@ static struct cmd_handler config_handlers[] = { | |||
176 | static struct cmd_handler command_handlers[] = { | 175 | static struct cmd_handler command_handlers[] = { |
177 | { "border", cmd_border }, | 176 | { "border", cmd_border }, |
178 | { "exit", cmd_exit }, | 177 | { "exit", cmd_exit }, |
178 | { "floating", cmd_floating }, | ||
179 | { "focus", cmd_focus }, | 179 | { "focus", cmd_focus }, |
180 | { "fullscreen", cmd_fullscreen }, | ||
180 | { "kill", cmd_kill }, | 181 | { "kill", cmd_kill }, |
181 | { "layout", cmd_layout }, | 182 | { "layout", cmd_layout }, |
182 | { "mark", cmd_mark }, | 183 | { "mark", cmd_mark }, |
@@ -189,6 +190,7 @@ static struct cmd_handler command_handlers[] = { | |||
189 | { "splith", cmd_splith }, | 190 | { "splith", cmd_splith }, |
190 | { "splitt", cmd_splitt }, | 191 | { "splitt", cmd_splitt }, |
191 | { "splitv", cmd_splitv }, | 192 | { "splitv", cmd_splitv }, |
193 | { "sticky", cmd_sticky }, | ||
192 | { "swap", cmd_swap }, | 194 | { "swap", cmd_swap }, |
193 | { "title_format", cmd_title_format }, | 195 | { "title_format", cmd_title_format }, |
194 | { "unmark", cmd_unmark }, | 196 | { "unmark", cmd_unmark }, |
diff --git a/sway/commands/border.c b/sway/commands/border.c index 4ba361da..0b059562 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -37,7 +37,13 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
37 | "or 'border pixel <px>'"); | 37 | "or 'border pixel <px>'"); |
38 | } | 38 | } |
39 | 39 | ||
40 | view_autoconfigure(view); | 40 | if (container_is_floating(view->swayc)) { |
41 | container_damage_whole(view->swayc); | ||
42 | container_set_geometry_from_floating_view(view->swayc); | ||
43 | container_damage_whole(view->swayc); | ||
44 | } else { | ||
45 | view_autoconfigure(view); | ||
46 | } | ||
41 | 47 | ||
42 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 48 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
43 | if (seat->cursor) { | 49 | if (seat->cursor) { |
diff --git a/sway/commands/floating.c b/sway/commands/floating.c new file mode 100644 index 00000000..46b761da --- /dev/null +++ b/sway/commands/floating.c | |||
@@ -0,0 +1,40 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/commands.h" | ||
4 | #include "sway/input/seat.h" | ||
5 | #include "sway/ipc-server.h" | ||
6 | #include "sway/output.h" | ||
7 | #include "sway/tree/arrange.h" | ||
8 | #include "sway/tree/container.h" | ||
9 | #include "sway/tree/layout.h" | ||
10 | #include "sway/tree/view.h" | ||
11 | #include "list.h" | ||
12 | |||
13 | struct cmd_results *cmd_floating(int argc, char **argv) { | ||
14 | struct cmd_results *error = NULL; | ||
15 | if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { | ||
16 | return error; | ||
17 | } | ||
18 | struct sway_container *container = | ||
19 | config->handler_context.current_container; | ||
20 | if (container->type != C_VIEW) { | ||
21 | // TODO: This doesn't strictly speaking have to be true | ||
22 | return cmd_results_new(CMD_INVALID, "float", "Only views can float"); | ||
23 | } | ||
24 | |||
25 | bool wants_floating; | ||
26 | if (strcasecmp(argv[0], "enable") == 0) { | ||
27 | wants_floating = true; | ||
28 | } else if (strcasecmp(argv[0], "disable") == 0) { | ||
29 | wants_floating = false; | ||
30 | } else if (strcasecmp(argv[0], "toggle") == 0) { | ||
31 | wants_floating = !container_is_floating(container); | ||
32 | } else { | ||
33 | return cmd_results_new(CMD_FAILURE, "floating", | ||
34 | "Expected 'floating <enable|disable|toggle>'"); | ||
35 | } | ||
36 | |||
37 | container_set_floating(container, wants_floating); | ||
38 | |||
39 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
40 | } | ||
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index 6b44b001..a009e38f 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c | |||
@@ -12,19 +12,15 @@ struct cmd_results *cmd_layout(int argc, char **argv) { | |||
12 | } | 12 | } |
13 | struct sway_container *parent = config->handler_context.current_container; | 13 | struct sway_container *parent = config->handler_context.current_container; |
14 | 14 | ||
15 | // TODO: floating | 15 | if (container_is_floating(parent)) { |
16 | /* | 16 | return cmd_results_new(CMD_FAILURE, "layout", |
17 | if (parent->is_floating) { | 17 | "Unable to change layout of floating windows"); |
18 | return cmd_results_new(CMD_FAILURE, "layout", "Unable to change layout of floating windows"); | ||
19 | } | 18 | } |
20 | */ | ||
21 | 19 | ||
22 | while (parent->type == C_VIEW) { | 20 | while (parent->type == C_VIEW) { |
23 | parent = parent->parent; | 21 | parent = parent->parent; |
24 | } | 22 | } |
25 | 23 | ||
26 | // TODO: stacks and tabs | ||
27 | |||
28 | if (strcasecmp(argv[0], "default") == 0) { | 24 | if (strcasecmp(argv[0], "default") == 0) { |
29 | parent->layout = parent->prev_layout; | 25 | parent->layout = parent->prev_layout; |
30 | if (parent->layout == L_NONE) { | 26 | if (parent->layout == L_NONE) { |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 890b1a8c..dc9a6f6f 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -13,16 +13,14 @@ | |||
13 | #include "stringop.h" | 13 | #include "stringop.h" |
14 | #include "list.h" | 14 | #include "list.h" |
15 | 15 | ||
16 | static const char* expected_syntax = | 16 | static const char* expected_syntax = |
17 | "Expected 'move <left|right|up|down> <[px] px>' or " | 17 | "Expected 'move <left|right|up|down> <[px] px>' or " |
18 | "'move <container|window> to workspace <name>' or " | 18 | "'move <container|window> to workspace <name>' or " |
19 | "'move <container|window|workspace> to output <name|direction>' or " | 19 | "'move <container|window|workspace> to output <name|direction>' or " |
20 | "'move position mouse'"; | 20 | "'move position mouse'"; |
21 | 21 | ||
22 | static struct sway_container *output_in_direction(const char *direction, | 22 | static struct sway_container *output_in_direction(const char *direction, |
23 | struct wlr_output *reference, int ref_ox, int ref_oy) { | 23 | struct wlr_output *reference, int ref_lx, int ref_ly) { |
24 | int ref_lx = ref_ox + reference->lx, | ||
25 | ref_ly = ref_oy + reference->ly; | ||
26 | struct { | 24 | struct { |
27 | char *name; | 25 | char *name; |
28 | enum wlr_direction direction; | 26 | enum wlr_direction direction; |
diff --git a/sway/commands/split.c b/sway/commands/split.c index 0a61ac8d..57e42a5a 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c | |||
@@ -10,6 +10,10 @@ | |||
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 | } | ||
13 | struct sway_container *parent = container_split(con, layout); | 17 | struct sway_container *parent = container_split(con, layout); |
14 | container_create_notify(parent); | 18 | container_create_notify(parent); |
15 | arrange_children_of(parent); | 19 | arrange_children_of(parent); |
@@ -23,24 +27,23 @@ struct cmd_results *cmd_split(int argc, char **argv) { | |||
23 | return error; | 27 | return error; |
24 | } | 28 | } |
25 | if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { | 29 | if (strcasecmp(argv[0], "v") == 0 || strcasecmp(argv[0], "vertical") == 0) { |
26 | do_split(L_VERT); | 30 | return do_split(L_VERT); |
27 | } else if (strcasecmp(argv[0], "h") == 0 || | 31 | } else if (strcasecmp(argv[0], "h") == 0 || |
28 | strcasecmp(argv[0], "horizontal") == 0) { | 32 | strcasecmp(argv[0], "horizontal") == 0) { |
29 | do_split(L_HORIZ); | 33 | return do_split(L_HORIZ); |
30 | } else if (strcasecmp(argv[0], "t") == 0 || | 34 | } else if (strcasecmp(argv[0], "t") == 0 || |
31 | strcasecmp(argv[0], "toggle") == 0) { | 35 | strcasecmp(argv[0], "toggle") == 0) { |
32 | struct sway_container *focused = | 36 | struct sway_container *focused = |
33 | config->handler_context.current_container; | 37 | config->handler_context.current_container; |
34 | 38 | ||
35 | if (focused->parent->layout == L_VERT) { | 39 | if (focused->parent->layout == L_VERT) { |
36 | do_split(L_HORIZ); | 40 | return do_split(L_HORIZ); |
37 | } else { | 41 | } else { |
38 | do_split(L_VERT); | 42 | return do_split(L_VERT); |
39 | } | 43 | } |
40 | } else { | 44 | } else { |
41 | error = cmd_results_new(CMD_FAILURE, "split", | 45 | return cmd_results_new(CMD_FAILURE, "split", |
42 | "Invalid split command (expected either horizontal or vertical)."); | 46 | "Invalid split command (expected either horizontal or vertical)."); |
43 | return error; | ||
44 | } | 47 | } |
45 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 48 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
46 | } | 49 | } |
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c new file mode 100644 index 00000000..732ccb98 --- /dev/null +++ b/sway/commands/sticky.c | |||
@@ -0,0 +1,40 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/commands.h" | ||
4 | #include "sway/input/seat.h" | ||
5 | #include "sway/ipc-server.h" | ||
6 | #include "sway/output.h" | ||
7 | #include "sway/tree/arrange.h" | ||
8 | #include "sway/tree/container.h" | ||
9 | #include "sway/tree/layout.h" | ||
10 | #include "sway/tree/view.h" | ||
11 | #include "list.h" | ||
12 | |||
13 | struct cmd_results *cmd_sticky(int argc, char **argv) { | ||
14 | struct cmd_results *error = NULL; | ||
15 | if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { | ||
16 | return error; | ||
17 | } | ||
18 | struct sway_container *container = | ||
19 | config->handler_context.current_container; | ||
20 | if (!container_is_floating(container)) { | ||
21 | return cmd_results_new(CMD_FAILURE, "sticky", | ||
22 | "Can't set sticky on a tiled container"); | ||
23 | } | ||
24 | |||
25 | bool wants_sticky; | ||
26 | if (strcasecmp(argv[0], "enable") == 0) { | ||
27 | wants_sticky = true; | ||
28 | } else if (strcasecmp(argv[0], "disable") == 0) { | ||
29 | wants_sticky = false; | ||
30 | } else if (strcasecmp(argv[0], "toggle") == 0) { | ||
31 | wants_sticky = !container->is_sticky; | ||
32 | } else { | ||
33 | return cmd_results_new(CMD_FAILURE, "sticky", | ||
34 | "Expected 'sticky <enable|disable|toggle>'"); | ||
35 | } | ||
36 | |||
37 | container->is_sticky = wants_sticky; | ||
38 | |||
39 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
40 | } | ||
diff --git a/sway/config.c b/sway/config.c index cf05c236..27308066 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "sway/config.h" | 26 | #include "sway/config.h" |
27 | #include "sway/tree/arrange.h" | 27 | #include "sway/tree/arrange.h" |
28 | #include "sway/tree/layout.h" | 28 | #include "sway/tree/layout.h" |
29 | #include "sway/tree/workspace.h" | ||
29 | #include "cairo.h" | 30 | #include "cairo.h" |
30 | #include "pango.h" | 31 | #include "pango.h" |
31 | #include "readline.h" | 32 | #include "readline.h" |
@@ -751,6 +752,16 @@ void config_update_font_height(bool recalculate) { | |||
751 | container_for_each_descendant_dfs(&root_container, | 752 | container_for_each_descendant_dfs(&root_container, |
752 | find_font_height_iterator, &recalculate); | 753 | find_font_height_iterator, &recalculate); |
753 | 754 | ||
755 | // Also consider floating views | ||
756 | for (int i = 0; i < root_container.children->length; ++i) { | ||
757 | struct sway_container *output = root_container.children->items[i]; | ||
758 | for (int j = 0; j < output->children->length; ++j) { | ||
759 | struct sway_container *ws = output->children->items[j]; | ||
760 | container_for_each_descendant_dfs(ws->sway_workspace->floating, | ||
761 | find_font_height_iterator, &recalculate); | ||
762 | } | ||
763 | } | ||
764 | |||
754 | if (config->font_height != prev_max_height) { | 765 | if (config->font_height != prev_max_height) { |
755 | arrange_root(); | 766 | arrange_root(); |
756 | } | 767 | } |
diff --git a/sway/criteria.c b/sway/criteria.c index dec5fed7..a263485a 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -121,12 +121,15 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
121 | } | 121 | } |
122 | 122 | ||
123 | if (criteria->floating) { | 123 | if (criteria->floating) { |
124 | // TODO | 124 | if (!container_is_floating(view->swayc)) { |
125 | return false; | 125 | return false; |
126 | } | ||
126 | } | 127 | } |
127 | 128 | ||
128 | if (criteria->tiling) { | 129 | if (criteria->tiling) { |
129 | // TODO | 130 | if (container_is_floating(view->swayc)) { |
131 | return false; | ||
132 | } | ||
130 | } | 133 | } |
131 | 134 | ||
132 | if (criteria->urgent) { | 135 | if (criteria->urgent) { |
diff --git a/sway/debug-tree.c b/sway/debug-tree.c index ae0a1869..f3465afe 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c | |||
@@ -25,9 +25,9 @@ static const char *layout_to_str(enum sway_container_layout layout) { | |||
25 | case L_FLOATING: | 25 | case L_FLOATING: |
26 | return "L_FLOATING"; | 26 | return "L_FLOATING"; |
27 | case L_NONE: | 27 | case L_NONE: |
28 | default: | ||
29 | return "L_NONE"; | 28 | return "L_NONE"; |
30 | } | 29 | } |
30 | return "L_NONE"; | ||
31 | } | 31 | } |
32 | 32 | ||
33 | static int draw_container(cairo_t *cairo, struct sway_container *container, | 33 | static int draw_container(cairo_t *cairo, struct sway_container *container, |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 0deb86ca..4047fa3f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -65,6 +65,13 @@ struct root_geometry { | |||
65 | float rotation; | 65 | float rotation; |
66 | }; | 66 | }; |
67 | 67 | ||
68 | struct render_data { | ||
69 | struct root_geometry root_geo; | ||
70 | struct sway_output *output; | ||
71 | pixman_region32_t *damage; | ||
72 | float alpha; | ||
73 | }; | ||
74 | |||
68 | static bool get_surface_box(struct root_geometry *geo, | 75 | static bool get_surface_box(struct root_geometry *geo, |
69 | struct sway_output *output, struct wlr_surface *surface, int sx, int sy, | 76 | struct sway_output *output, struct wlr_surface *surface, int sx, int sy, |
70 | struct wlr_box *surface_box) { | 77 | struct wlr_box *surface_box) { |
@@ -116,8 +123,9 @@ static void surface_for_each_surface(struct wlr_surface *surface, | |||
116 | static void output_view_for_each_surface(struct sway_view *view, | 123 | static void output_view_for_each_surface(struct sway_view *view, |
117 | struct root_geometry *geo, wlr_surface_iterator_func_t iterator, | 124 | struct root_geometry *geo, wlr_surface_iterator_func_t iterator, |
118 | void *user_data) { | 125 | void *user_data) { |
119 | geo->x = view->x; | 126 | struct render_data *data = user_data; |
120 | geo->y = view->y; | 127 | geo->x = view->x - data->output->swayc->x; |
128 | geo->y = view->y - data->output->swayc->y; | ||
121 | geo->width = view->surface->current->width; | 129 | geo->width = view->surface->current->width; |
122 | geo->height = view->surface->current->height; | 130 | geo->height = view->surface->current->height; |
123 | geo->rotation = 0; // TODO | 131 | geo->rotation = 0; // TODO |
@@ -160,13 +168,6 @@ static void scale_box(struct wlr_box *box, float scale) { | |||
160 | box->height *= scale; | 168 | box->height *= scale; |
161 | } | 169 | } |
162 | 170 | ||
163 | struct render_data { | ||
164 | struct root_geometry root_geo; | ||
165 | struct sway_output *output; | ||
166 | pixman_region32_t *damage; | ||
167 | float alpha; | ||
168 | }; | ||
169 | |||
170 | static void scissor_output(struct wlr_output *wlr_output, | 171 | static void scissor_output(struct wlr_output *wlr_output, |
171 | pixman_box32_t *rect) { | 172 | pixman_box32_t *rect) { |
172 | struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); | 173 | struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); |
@@ -275,7 +276,10 @@ static void render_rect(struct wlr_output *wlr_output, | |||
275 | struct wlr_renderer *renderer = | 276 | struct wlr_renderer *renderer = |
276 | wlr_backend_get_renderer(wlr_output->backend); | 277 | wlr_backend_get_renderer(wlr_output->backend); |
277 | 278 | ||
278 | struct wlr_box box = *_box; | 279 | struct wlr_box box; |
280 | memcpy(&box, _box, sizeof(struct wlr_box)); | ||
281 | box.x -= wlr_output->lx * wlr_output->scale; | ||
282 | box.y -= wlr_output->ly * wlr_output->scale; | ||
279 | 283 | ||
280 | pixman_region32_t damage; | 284 | pixman_region32_t damage; |
281 | pixman_region32_init(&damage); | 285 | pixman_region32_init(&damage); |
@@ -449,9 +453,10 @@ static void render_titlebar(struct sway_output *output, | |||
449 | struct wlr_box texture_box; | 453 | struct wlr_box texture_box; |
450 | wlr_texture_get_size(marks_texture, | 454 | wlr_texture_get_size(marks_texture, |
451 | &texture_box.width, &texture_box.height); | 455 | &texture_box.width, &texture_box.height); |
452 | texture_box.x = | 456 | texture_box.x = (x - output->swayc->x + width - TITLEBAR_H_PADDING) |
453 | (x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width; | 457 | * output_scale - texture_box.width; |
454 | texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale; | 458 | texture_box.y = (y - output->swayc->y + TITLEBAR_V_PADDING) |
459 | * output_scale; | ||
455 | 460 | ||
456 | float matrix[9]; | 461 | float matrix[9]; |
457 | wlr_matrix_project_box(matrix, &texture_box, | 462 | wlr_matrix_project_box(matrix, &texture_box, |
@@ -472,8 +477,10 @@ static void render_titlebar(struct sway_output *output, | |||
472 | struct wlr_box texture_box; | 477 | struct wlr_box texture_box; |
473 | wlr_texture_get_size(title_texture, | 478 | wlr_texture_get_size(title_texture, |
474 | &texture_box.width, &texture_box.height); | 479 | &texture_box.width, &texture_box.height); |
475 | texture_box.x = (x + TITLEBAR_H_PADDING) * output_scale; | 480 | texture_box.x = (x - output->swayc->x + TITLEBAR_H_PADDING) |
476 | texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale; | 481 | * output_scale; |
482 | texture_box.y = (y - output->swayc->y + TITLEBAR_V_PADDING) | ||
483 | * output_scale; | ||
477 | 484 | ||
478 | float matrix[9]; | 485 | float matrix[9]; |
479 | wlr_matrix_project_box(matrix, &texture_box, | 486 | wlr_matrix_project_box(matrix, &texture_box, |
@@ -755,8 +762,58 @@ static void render_container(struct sway_output *output, | |||
755 | render_container_tabbed(output, damage, con, parent_focused); | 762 | render_container_tabbed(output, damage, con, parent_focused); |
756 | break; | 763 | break; |
757 | case L_FLOATING: | 764 | case L_FLOATING: |
758 | // TODO | 765 | sway_assert(false, "Didn't expect to see floating here"); |
759 | break; | 766 | } |
767 | } | ||
768 | |||
769 | static void render_floating_container(struct sway_output *soutput, | ||
770 | pixman_region32_t *damage, struct sway_container *con) { | ||
771 | if (con->type == C_VIEW) { | ||
772 | struct sway_view *view = con->sway_view; | ||
773 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
774 | struct sway_container *focus = seat_get_focus(seat); | ||
775 | struct border_colors *colors; | ||
776 | struct wlr_texture *title_texture; | ||
777 | struct wlr_texture *marks_texture; | ||
778 | |||
779 | if (focus == con) { | ||
780 | colors = &config->border_colors.focused; | ||
781 | title_texture = con->title_focused; | ||
782 | marks_texture = view->marks_focused; | ||
783 | } else { | ||
784 | colors = &config->border_colors.unfocused; | ||
785 | title_texture = con->title_unfocused; | ||
786 | marks_texture = view->marks_unfocused; | ||
787 | } | ||
788 | |||
789 | if (con->sway_view->border == B_NORMAL) { | ||
790 | render_titlebar(soutput, damage, con, con->x, con->y, con->width, | ||
791 | colors, title_texture, marks_texture); | ||
792 | } else { | ||
793 | render_top_border(soutput, damage, con, colors); | ||
794 | } | ||
795 | render_view(soutput, damage, con, colors); | ||
796 | } else { | ||
797 | render_container(soutput, damage, con, false); | ||
798 | } | ||
799 | } | ||
800 | |||
801 | static void render_floating(struct sway_output *soutput, | ||
802 | pixman_region32_t *damage) { | ||
803 | for (int i = 0; i < root_container.children->length; ++i) { | ||
804 | struct sway_container *output = root_container.children->items[i]; | ||
805 | for (int j = 0; j < output->children->length; ++j) { | ||
806 | struct sway_container *workspace = output->children->items[j]; | ||
807 | struct sway_workspace *ws = workspace->sway_workspace; | ||
808 | if (!workspace_is_visible(workspace)) { | ||
809 | continue; | ||
810 | } | ||
811 | for (int k = 0; k < ws->floating->children->length; ++k) { | ||
812 | struct sway_container *floater = | ||
813 | ws->floating->children->items[k]; | ||
814 | render_floating_container(soutput, damage, floater); | ||
815 | } | ||
816 | } | ||
760 | } | 817 | } |
761 | } | 818 | } |
762 | 819 | ||
@@ -794,8 +851,6 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
794 | goto renderer_end; | 851 | goto renderer_end; |
795 | } | 852 | } |
796 | 853 | ||
797 | //wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | ||
798 | |||
799 | struct sway_container *workspace = output_get_active_workspace(output); | 854 | struct sway_container *workspace = output_get_active_workspace(output); |
800 | 855 | ||
801 | if (workspace->sway_workspace->fullscreen) { | 856 | if (workspace->sway_workspace->fullscreen) { |
@@ -834,6 +889,7 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
834 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 889 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
835 | struct sway_container *focus = seat_get_focus(seat); | 890 | struct sway_container *focus = seat_get_focus(seat); |
836 | render_container(output, damage, workspace, focus == workspace); | 891 | render_container(output, damage, workspace, focus == workspace); |
892 | render_floating(output, damage); | ||
837 | 893 | ||
838 | render_unmanaged(output, damage, | 894 | render_unmanaged(output, damage, |
839 | &root_container.sway_root->xwayland_unmanaged); | 895 | &root_container.sway_root->xwayland_unmanaged); |
@@ -915,6 +971,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
915 | 971 | ||
916 | struct sway_container *workspace = output_get_active_workspace(output); | 972 | struct sway_container *workspace = output_get_active_workspace(output); |
917 | send_frame_done_container(&data, workspace); | 973 | send_frame_done_container(&data, workspace); |
974 | send_frame_done_container(&data, workspace->sway_workspace->floating); | ||
918 | 975 | ||
919 | send_frame_done_unmanaged(&data, | 976 | send_frame_done_unmanaged(&data, |
920 | &root_container.sway_root->xwayland_unmanaged); | 977 | &root_container.sway_root->xwayland_unmanaged); |
@@ -1052,21 +1109,14 @@ static void output_damage_whole_container_iterator(struct sway_container *con, | |||
1052 | 1109 | ||
1053 | void output_damage_whole_container(struct sway_output *output, | 1110 | void output_damage_whole_container(struct sway_output *output, |
1054 | struct sway_container *con) { | 1111 | struct sway_container *con) { |
1055 | float scale = output->wlr_output->scale; | ||
1056 | struct wlr_box box = { | 1112 | struct wlr_box box = { |
1057 | .x = con->x * scale, | 1113 | .x = con->x - output->wlr_output->lx, |
1058 | .y = con->y * scale, | 1114 | .y = con->y - output->wlr_output->ly, |
1059 | .width = con->width * scale, | 1115 | .width = con->width, |
1060 | .height = con->height * scale, | 1116 | .height = con->height, |
1061 | }; | 1117 | }; |
1118 | scale_box(&box, output->wlr_output->scale); | ||
1062 | wlr_output_damage_add_box(output->damage, &box); | 1119 | wlr_output_damage_add_box(output->damage, &box); |
1063 | |||
1064 | if (con->type == C_VIEW) { | ||
1065 | output_damage_whole_container_iterator(con, output); | ||
1066 | } else { | ||
1067 | container_descendants(con, C_VIEW, | ||
1068 | output_damage_whole_container_iterator, output); | ||
1069 | } | ||
1070 | } | 1120 | } |
1071 | 1121 | ||
1072 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { | 1122 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index b2b95fa0..d2b8822c 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -87,7 +87,7 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p | |||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | static void configure(struct sway_view *view, double ox, double oy, int width, | 90 | static void configure(struct sway_view *view, double lx, double ly, int width, |
91 | int height) { | 91 | int height) { |
92 | struct sway_xdg_shell_view *xdg_shell_view = | 92 | struct sway_xdg_shell_view *xdg_shell_view = |
93 | xdg_shell_view_from_view(view); | 93 | xdg_shell_view_from_view(view); |
@@ -98,6 +98,7 @@ static void configure(struct sway_view *view, double ox, double oy, int width, | |||
98 | xdg_shell_view->pending_width = width; | 98 | xdg_shell_view->pending_width = width; |
99 | xdg_shell_view->pending_height = height; | 99 | xdg_shell_view->pending_height = height; |
100 | wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height); | 100 | wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height); |
101 | view_update_position(view, lx, ly); | ||
101 | } | 102 | } |
102 | 103 | ||
103 | static void set_activated(struct sway_view *view, bool activated) { | 104 | static void set_activated(struct sway_view *view, bool activated) { |
@@ -118,6 +119,14 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { | |||
118 | wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); | 119 | wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); |
119 | } | 120 | } |
120 | 121 | ||
122 | static bool wants_floating(struct sway_view *view) { | ||
123 | struct wlr_xdg_toplevel_state *state = | ||
124 | &view->wlr_xdg_surface->toplevel->current; | ||
125 | return state->min_width != 0 && state->min_height != 0 | ||
126 | && state->min_width == state->max_width | ||
127 | && state->min_height == state->max_height; | ||
128 | } | ||
129 | |||
121 | static void for_each_surface(struct sway_view *view, | 130 | static void for_each_surface(struct sway_view *view, |
122 | wlr_surface_iterator_func_t iterator, void *user_data) { | 131 | wlr_surface_iterator_func_t iterator, void *user_data) { |
123 | if (xdg_shell_view_from_view(view) == NULL) { | 132 | if (xdg_shell_view_from_view(view) == NULL) { |
@@ -155,6 +164,7 @@ static const struct sway_view_impl view_impl = { | |||
155 | .configure = configure, | 164 | .configure = configure, |
156 | .set_activated = set_activated, | 165 | .set_activated = set_activated, |
157 | .set_fullscreen = set_fullscreen, | 166 | .set_fullscreen = set_fullscreen, |
167 | .wants_floating = wants_floating, | ||
158 | .for_each_surface = for_each_surface, | 168 | .for_each_surface = for_each_surface, |
159 | .close = _close, | 169 | .close = _close, |
160 | .destroy = destroy, | 170 | .destroy = destroy, |
@@ -164,11 +174,18 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
164 | struct sway_xdg_shell_view *xdg_shell_view = | 174 | struct sway_xdg_shell_view *xdg_shell_view = |
165 | wl_container_of(listener, xdg_shell_view, commit); | 175 | wl_container_of(listener, xdg_shell_view, commit); |
166 | struct sway_view *view = &xdg_shell_view->view; | 176 | struct sway_view *view = &xdg_shell_view->view; |
167 | // NOTE: We intentionally discard the view's desired width here | 177 | if (view->swayc && container_is_floating(view->swayc)) { |
168 | // TODO: Store this for restoration when moving to floating plane | 178 | int width = view->wlr_xdg_surface->geometry.width; |
169 | // TODO: Let floating views do whatever | 179 | int height = view->wlr_xdg_surface->geometry.height; |
170 | view_update_size(view, xdg_shell_view->pending_width, | 180 | if (!width && !height) { |
171 | xdg_shell_view->pending_height); | 181 | width = view->wlr_xdg_surface->surface->current->width; |
182 | height = view->wlr_xdg_surface->surface->current->height; | ||
183 | } | ||
184 | view_update_size(view, width, height); | ||
185 | } else { | ||
186 | view_update_size(view, xdg_shell_view->pending_width, | ||
187 | xdg_shell_view->pending_height); | ||
188 | } | ||
172 | view_update_title(view, false); | 189 | view_update_title(view, false); |
173 | view_damage_from(view); | 190 | view_damage_from(view); |
174 | } | 191 | } |
@@ -196,6 +213,12 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
196 | struct sway_view *view = &xdg_shell_view->view; | 213 | struct sway_view *view = &xdg_shell_view->view; |
197 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; | 214 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; |
198 | 215 | ||
216 | view->natural_width = view->wlr_xdg_surface->geometry.width; | ||
217 | view->natural_height = view->wlr_xdg_surface->geometry.height; | ||
218 | if (!view->natural_width && !view->natural_height) { | ||
219 | view->natural_width = view->wlr_xdg_surface->surface->current->width; | ||
220 | view->natural_height = view->wlr_xdg_surface->surface->current->height; | ||
221 | } | ||
199 | view_map(view, view->wlr_xdg_surface->surface); | 222 | view_map(view, view->wlr_xdg_surface->surface); |
200 | 223 | ||
201 | xdg_shell_view->commit.notify = handle_commit; | 224 | xdg_shell_view->commit.notify = handle_commit; |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index d098c797..6ffe334a 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -86,7 +86,7 @@ static const char *get_string_prop(struct sway_view *view, enum sway_view_prop p | |||
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | static void configure(struct sway_view *view, double ox, double oy, int width, | 89 | static void configure(struct sway_view *view, double lx, double ly, int width, |
90 | int height) { | 90 | int height) { |
91 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | 91 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = |
92 | xdg_shell_v6_view_from_view(view); | 92 | xdg_shell_v6_view_from_view(view); |
@@ -97,6 +97,7 @@ static void configure(struct sway_view *view, double ox, double oy, int width, | |||
97 | xdg_shell_v6_view->pending_width = width; | 97 | xdg_shell_v6_view->pending_width = width; |
98 | xdg_shell_v6_view->pending_height = height; | 98 | xdg_shell_v6_view->pending_height = height; |
99 | wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height); | 99 | wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height); |
100 | view_update_position(view, lx, ly); | ||
100 | } | 101 | } |
101 | 102 | ||
102 | static void set_activated(struct sway_view *view, bool activated) { | 103 | static void set_activated(struct sway_view *view, bool activated) { |
@@ -117,6 +118,14 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { | |||
117 | wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen); | 118 | wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen); |
118 | } | 119 | } |
119 | 120 | ||
121 | static bool wants_floating(struct sway_view *view) { | ||
122 | struct wlr_xdg_toplevel_v6_state *state = | ||
123 | &view->wlr_xdg_surface_v6->toplevel->current; | ||
124 | return state->min_width != 0 && state->min_height != 0 | ||
125 | && state->min_width == state->max_width | ||
126 | && state->min_height == state->max_height; | ||
127 | } | ||
128 | |||
120 | static void for_each_surface(struct sway_view *view, | 129 | static void for_each_surface(struct sway_view *view, |
121 | wlr_surface_iterator_func_t iterator, void *user_data) { | 130 | wlr_surface_iterator_func_t iterator, void *user_data) { |
122 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 131 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
@@ -154,6 +163,7 @@ static const struct sway_view_impl view_impl = { | |||
154 | .configure = configure, | 163 | .configure = configure, |
155 | .set_activated = set_activated, | 164 | .set_activated = set_activated, |
156 | .set_fullscreen = set_fullscreen, | 165 | .set_fullscreen = set_fullscreen, |
166 | .wants_floating = wants_floating, | ||
157 | .for_each_surface = for_each_surface, | 167 | .for_each_surface = for_each_surface, |
158 | .close = _close, | 168 | .close = _close, |
159 | .destroy = destroy, | 169 | .destroy = destroy, |
@@ -163,11 +173,18 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
163 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | 173 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = |
164 | wl_container_of(listener, xdg_shell_v6_view, commit); | 174 | wl_container_of(listener, xdg_shell_v6_view, commit); |
165 | struct sway_view *view = &xdg_shell_v6_view->view; | 175 | struct sway_view *view = &xdg_shell_v6_view->view; |
166 | // NOTE: We intentionally discard the view's desired width here | 176 | if (view->swayc && container_is_floating(view->swayc)) { |
167 | // TODO: Store this for restoration when moving to floating plane | 177 | int width = view->wlr_xdg_surface_v6->geometry.width; |
168 | // TODO: Let floating views do whatever | 178 | int height = view->wlr_xdg_surface_v6->geometry.height; |
169 | view_update_size(view, xdg_shell_v6_view->pending_width, | 179 | if (!width && !height) { |
170 | xdg_shell_v6_view->pending_height); | 180 | width = view->wlr_xdg_surface_v6->surface->current->width; |
181 | height = view->wlr_xdg_surface_v6->surface->current->height; | ||
182 | } | ||
183 | view_update_size(view, width, height); | ||
184 | } else { | ||
185 | view_update_size(view, xdg_shell_v6_view->pending_width, | ||
186 | xdg_shell_v6_view->pending_height); | ||
187 | } | ||
171 | view_update_title(view, false); | 188 | view_update_title(view, false); |
172 | view_damage_from(view); | 189 | view_damage_from(view); |
173 | } | 190 | } |
@@ -195,6 +212,12 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
195 | struct sway_view *view = &xdg_shell_v6_view->view; | 212 | struct sway_view *view = &xdg_shell_v6_view->view; |
196 | struct wlr_xdg_surface_v6 *xdg_surface = view->wlr_xdg_surface_v6; | 213 | struct wlr_xdg_surface_v6 *xdg_surface = view->wlr_xdg_surface_v6; |
197 | 214 | ||
215 | view->natural_width = view->wlr_xdg_surface_v6->geometry.width; | ||
216 | view->natural_height = view->wlr_xdg_surface_v6->geometry.height; | ||
217 | if (!view->natural_width && !view->natural_height) { | ||
218 | view->natural_width = view->wlr_xdg_surface_v6->surface->current->width; | ||
219 | view->natural_height = view->wlr_xdg_surface_v6->surface->current->height; | ||
220 | } | ||
198 | view_map(view, view->wlr_xdg_surface_v6->surface); | 221 | view_map(view, view->wlr_xdg_surface_v6->surface); |
199 | 222 | ||
200 | xdg_shell_v6_view->commit.notify = handle_commit; | 223 | xdg_shell_v6_view->commit.notify = handle_commit; |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 6a99a66a..75bfb7b2 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -152,7 +152,7 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) { | |||
152 | } | 152 | } |
153 | } | 153 | } |
154 | 154 | ||
155 | static void configure(struct sway_view *view, double ox, double oy, int width, | 155 | static void configure(struct sway_view *view, double lx, double ly, int width, |
156 | int height) { | 156 | int height) { |
157 | struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); | 157 | struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); |
158 | if (xwayland_view == NULL) { | 158 | if (xwayland_view == NULL) { |
@@ -160,25 +160,11 @@ static void configure(struct sway_view *view, double ox, double oy, int width, | |||
160 | } | 160 | } |
161 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 161 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
162 | 162 | ||
163 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 163 | xwayland_view->pending_lx = lx; |
164 | if (!sway_assert(output, "view must be within tree to set position")) { | 164 | xwayland_view->pending_ly = ly; |
165 | return; | ||
166 | } | ||
167 | struct sway_container *root = container_parent(output, C_ROOT); | ||
168 | if (!sway_assert(root, "output must be within tree to set position")) { | ||
169 | return; | ||
170 | } | ||
171 | struct wlr_output_layout *layout = root->sway_root->output_layout; | ||
172 | struct wlr_output_layout_output *loutput = | ||
173 | wlr_output_layout_get(layout, output->sway_output->wlr_output); | ||
174 | if (!sway_assert(loutput, "output must be within layout to set position")) { | ||
175 | return; | ||
176 | } | ||
177 | |||
178 | xwayland_view->pending_width = width; | 165 | xwayland_view->pending_width = width; |
179 | xwayland_view->pending_height = height; | 166 | xwayland_view->pending_height = height; |
180 | wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y, | 167 | wlr_xwayland_surface_configure(xsurface, lx, ly, width, height); |
181 | width, height); | ||
182 | } | 168 | } |
183 | 169 | ||
184 | static void set_activated(struct sway_view *view, bool activated) { | 170 | static void set_activated(struct sway_view *view, bool activated) { |
@@ -197,6 +183,19 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { | |||
197 | wlr_xwayland_surface_set_fullscreen(surface, fullscreen); | 183 | wlr_xwayland_surface_set_fullscreen(surface, fullscreen); |
198 | } | 184 | } |
199 | 185 | ||
186 | static bool wants_floating(struct sway_view *view) { | ||
187 | // TODO: | ||
188 | // We want to return true if the window type contains any of these: | ||
189 | // NET_WM_WINDOW_TYPE_DIALOG | ||
190 | // NET_WM_WINDOW_TYPE_UTILITY | ||
191 | // NET_WM_WINDOW_TYPE_TOOLBAR | ||
192 | // NET_WM_WINDOW_TYPE_SPLASH | ||
193 | // | ||
194 | // We also want to return true if the NET_WM_STATE is MODAL. | ||
195 | // wlroots doesn't appear to provide all this information at the moment. | ||
196 | return false; | ||
197 | } | ||
198 | |||
200 | static void _close(struct sway_view *view) { | 199 | static void _close(struct sway_view *view) { |
201 | if (xwayland_view_from_view(view) == NULL) { | 200 | if (xwayland_view_from_view(view) == NULL) { |
202 | return; | 201 | return; |
@@ -226,6 +225,7 @@ static const struct sway_view_impl view_impl = { | |||
226 | .configure = configure, | 225 | .configure = configure, |
227 | .set_activated = set_activated, | 226 | .set_activated = set_activated, |
228 | .set_fullscreen = set_fullscreen, | 227 | .set_fullscreen = set_fullscreen, |
228 | .wants_floating = wants_floating, | ||
229 | .close = _close, | 229 | .close = _close, |
230 | .destroy = destroy, | 230 | .destroy = destroy, |
231 | }; | 231 | }; |
@@ -234,10 +234,15 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
234 | struct sway_xwayland_view *xwayland_view = | 234 | struct sway_xwayland_view *xwayland_view = |
235 | wl_container_of(listener, xwayland_view, commit); | 235 | wl_container_of(listener, xwayland_view, commit); |
236 | struct sway_view *view = &xwayland_view->view; | 236 | struct sway_view *view = &xwayland_view->view; |
237 | // NOTE: We intentionally discard the view's desired width here | 237 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
238 | // TODO: Let floating views do whatever | 238 | if (view->swayc && container_is_floating(view->swayc)) { |
239 | view_update_size(view, xwayland_view->pending_width, | 239 | view_update_size(view, xsurface->width, xsurface->height); |
240 | xwayland_view->pending_height); | 240 | } else { |
241 | view_update_size(view, xwayland_view->pending_width, | ||
242 | xwayland_view->pending_height); | ||
243 | } | ||
244 | view_update_position(view, | ||
245 | xwayland_view->pending_lx, xwayland_view->pending_ly); | ||
241 | view_damage_from(view); | 246 | view_damage_from(view); |
242 | } | 247 | } |
243 | 248 | ||
@@ -254,6 +259,9 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
254 | struct wlr_xwayland_surface *xsurface = data; | 259 | struct wlr_xwayland_surface *xsurface = data; |
255 | struct sway_view *view = &xwayland_view->view; | 260 | struct sway_view *view = &xwayland_view->view; |
256 | 261 | ||
262 | view->natural_width = xsurface->width; | ||
263 | view->natural_height = xsurface->height; | ||
264 | |||
257 | // Wire up the commit listener here, because xwayland map/unmap can change | 265 | // Wire up the commit listener here, because xwayland map/unmap can change |
258 | // the underlying wlr_surface | 266 | // the underlying wlr_surface |
259 | wl_signal_add(&xsurface->surface->events.commit, &xwayland_view->commit); | 267 | wl_signal_add(&xsurface->surface->events.commit, &xwayland_view->commit); |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 6751931d..16e5427b 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -46,7 +46,7 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output, | |||
46 | * location, it is stored in **surface (it may not be a view). | 46 | * location, it is stored in **surface (it may not be a view). |
47 | */ | 47 | */ |
48 | static struct sway_container *container_at_coords( | 48 | static struct sway_container *container_at_coords( |
49 | struct sway_seat *seat, double x, double y, | 49 | struct sway_seat *seat, double lx, double ly, |
50 | struct wlr_surface **surface, double *sx, double *sy) { | 50 | struct wlr_surface **surface, double *sx, double *sy) { |
51 | // check for unmanaged views first | 51 | // check for unmanaged views first |
52 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; | 52 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; |
@@ -55,8 +55,8 @@ static struct sway_container *container_at_coords( | |||
55 | struct wlr_xwayland_surface *xsurface = | 55 | struct wlr_xwayland_surface *xsurface = |
56 | unmanaged_surface->wlr_xwayland_surface; | 56 | unmanaged_surface->wlr_xwayland_surface; |
57 | 57 | ||
58 | double _sx = x - unmanaged_surface->lx; | 58 | double _sx = lx - unmanaged_surface->lx; |
59 | double _sy = y - unmanaged_surface->ly; | 59 | double _sy = ly - unmanaged_surface->ly; |
60 | if (wlr_surface_point_accepts_input(xsurface->surface, _sx, _sy)) { | 60 | if (wlr_surface_point_accepts_input(xsurface->surface, _sx, _sy)) { |
61 | *surface = xsurface->surface; | 61 | *surface = xsurface->surface; |
62 | *sx = _sx; | 62 | *sx = _sx; |
@@ -69,12 +69,12 @@ static struct sway_container *container_at_coords( | |||
69 | struct wlr_output_layout *output_layout = | 69 | struct wlr_output_layout *output_layout = |
70 | root_container.sway_root->output_layout; | 70 | root_container.sway_root->output_layout; |
71 | struct wlr_output *wlr_output = wlr_output_layout_output_at( | 71 | struct wlr_output *wlr_output = wlr_output_layout_output_at( |
72 | output_layout, x, y); | 72 | output_layout, lx, ly); |
73 | if (wlr_output == NULL) { | 73 | if (wlr_output == NULL) { |
74 | return NULL; | 74 | return NULL; |
75 | } | 75 | } |
76 | struct sway_output *output = wlr_output->data; | 76 | struct sway_output *output = wlr_output->data; |
77 | double ox = x, oy = y; | 77 | double ox = lx, oy = ly; |
78 | wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); | 78 | wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); |
79 | 79 | ||
80 | // find the focused workspace on the output for this seat | 80 | // find the focused workspace on the output for this seat |
@@ -108,7 +108,10 @@ static struct sway_container *container_at_coords( | |||
108 | } | 108 | } |
109 | 109 | ||
110 | struct sway_container *c; | 110 | struct sway_container *c; |
111 | if ((c = container_at(ws, ox, oy, surface, sx, sy))) { | 111 | if ((c = floating_container_at(lx, ly, surface, sx, sy))) { |
112 | return c; | ||
113 | } | ||
114 | if ((c = container_at(ws, lx, ly, surface, sx, sy))) { | ||
112 | return c; | 115 | return c; |
113 | } | 116 | } |
114 | 117 | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 0295212c..d35cbeef 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -113,7 +113,14 @@ static void seat_send_focus(struct sway_container *con, | |||
113 | 113 | ||
114 | static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | 114 | static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, |
115 | struct sway_container *container, enum sway_container_type type) { | 115 | struct sway_container *container, enum sway_container_type type) { |
116 | if (container->type == C_VIEW || container->children->length == 0) { | 116 | if (container->type == C_VIEW) { |
117 | return container; | ||
118 | } | ||
119 | |||
120 | struct sway_container *floating = container->type == C_WORKSPACE ? | ||
121 | container->sway_workspace->floating : NULL; | ||
122 | if (container->children->length == 0 && | ||
123 | (!floating || floating->children->length == 0)) { | ||
117 | return container; | 124 | return container; |
118 | } | 125 | } |
119 | 126 | ||
@@ -126,6 +133,9 @@ static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | |||
126 | if (container_has_child(container, current->container)) { | 133 | if (container_has_child(container, current->container)) { |
127 | return current->container; | 134 | return current->container; |
128 | } | 135 | } |
136 | if (floating && container_has_child(floating, current->container)) { | ||
137 | return current->container; | ||
138 | } | ||
129 | } | 139 | } |
130 | 140 | ||
131 | return NULL; | 141 | return NULL; |
@@ -568,7 +578,7 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
568 | // clean up unfocused empty workspace on new output | 578 | // clean up unfocused empty workspace on new output |
569 | if (new_output_last_ws) { | 579 | if (new_output_last_ws) { |
570 | if (!workspace_is_visible(new_output_last_ws) | 580 | if (!workspace_is_visible(new_output_last_ws) |
571 | && new_output_last_ws->children->length == 0) { | 581 | && workspace_is_empty(new_output_last_ws)) { |
572 | if (last_workspace == new_output_last_ws) { | 582 | if (last_workspace == new_output_last_ws) { |
573 | last_focus = NULL; | 583 | last_focus = NULL; |
574 | last_workspace = NULL; | 584 | last_workspace = NULL; |
@@ -581,7 +591,7 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
581 | if (last_workspace) { | 591 | if (last_workspace) { |
582 | ipc_event_workspace(last_workspace, container, "focus"); | 592 | ipc_event_workspace(last_workspace, container, "focus"); |
583 | if (!workspace_is_visible(last_workspace) | 593 | if (!workspace_is_visible(last_workspace) |
584 | && last_workspace->children->length == 0) { | 594 | && workspace_is_empty(last_workspace)) { |
585 | if (last_workspace == last_focus) { | 595 | if (last_workspace == last_focus) { |
586 | last_focus = NULL; | 596 | last_focus = NULL; |
587 | } | 597 | } |
@@ -591,10 +601,8 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
591 | 601 | ||
592 | if (config->mouse_warping && warp) { | 602 | if (config->mouse_warping && warp) { |
593 | if (new_output && last_output && new_output != last_output) { | 603 | if (new_output && last_output && new_output != last_output) { |
594 | double x = new_output->x + container->x + | 604 | double x = container->x + container->width / 2.0; |
595 | container->width / 2.0; | 605 | double y = container->y + container->height / 2.0; |
596 | double y = new_output->y + container->y + | ||
597 | container->height / 2.0; | ||
598 | struct wlr_output *wlr_output = | 606 | struct wlr_output *wlr_output = |
599 | new_output->sway_output->wlr_output; | 607 | new_output->sway_output->wlr_output; |
600 | if (!wlr_output_layout_contains_point( | 608 | if (!wlr_output_layout_contains_point( |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 03582950..6d185449 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "log.h" | 4 | #include "log.h" |
5 | #include "sway/ipc-json.h" | 5 | #include "sway/ipc-json.h" |
6 | #include "sway/tree/container.h" | 6 | #include "sway/tree/container.h" |
7 | #include "sway/tree/workspace.h" | ||
7 | #include "sway/output.h" | 8 | #include "sway/output.h" |
8 | #include "sway/input/input-manager.h" | 9 | #include "sway/input/input-manager.h" |
9 | #include "sway/input/seat.h" | 10 | #include "sway/input/seat.h" |
@@ -152,6 +153,15 @@ static void ipc_json_describe_workspace(struct sway_container *workspace, | |||
152 | 153 | ||
153 | const char *layout = ipc_json_layout_description(workspace->layout); | 154 | const char *layout = ipc_json_layout_description(workspace->layout); |
154 | json_object_object_add(object, "layout", json_object_new_string(layout)); | 155 | json_object_object_add(object, "layout", json_object_new_string(layout)); |
156 | |||
157 | // Floating | ||
158 | json_object *floating_array = json_object_new_array(); | ||
159 | struct sway_container *floating = workspace->sway_workspace->floating; | ||
160 | for (int i = 0; i < floating->children->length; ++i) { | ||
161 | struct sway_container *floater = floating->children->items[i]; | ||
162 | json_object_array_add(floating_array, ipc_json_describe_container_recursive(floater)); | ||
163 | } | ||
164 | json_object_object_add(object, "floating_nodes", floating_array); | ||
155 | } | 165 | } |
156 | 166 | ||
157 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { | 167 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { |
diff --git a/sway/meson.build b/sway/meson.build index 68675f67..4c038583 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -36,6 +36,7 @@ sway_sources = files( | |||
36 | 'commands/exit.c', | 36 | 'commands/exit.c', |
37 | 'commands/exec.c', | 37 | 'commands/exec.c', |
38 | 'commands/exec_always.c', | 38 | 'commands/exec_always.c', |
39 | 'commands/floating.c', | ||
39 | 'commands/focus.c', | 40 | 'commands/focus.c', |
40 | 'commands/focus_follows_mouse.c', | 41 | 'commands/focus_follows_mouse.c', |
41 | 'commands/focus_wrapping.c', | 42 | 'commands/focus_wrapping.c', |
@@ -64,6 +65,7 @@ sway_sources = files( | |||
64 | 'commands/set.c', | 65 | 'commands/set.c', |
65 | 'commands/show_marks.c', | 66 | 'commands/show_marks.c', |
66 | 'commands/split.c', | 67 | 'commands/split.c', |
68 | 'commands/sticky.c', | ||
67 | 'commands/swaybg_command.c', | 69 | 'commands/swaybg_command.c', |
68 | 'commands/swap.c', | 70 | 'commands/swap.c', |
69 | 'commands/title_format.c', | 71 | 'commands/title_format.c', |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index bdef56ea..721b557e 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -73,8 +73,8 @@ void arrange_workspace(struct sway_container *workspace) { | |||
73 | area->width, area->height, area->x, area->y); | 73 | area->width, area->height, area->x, area->y); |
74 | workspace->width = area->width; | 74 | workspace->width = area->width; |
75 | workspace->height = area->height; | 75 | workspace->height = area->height; |
76 | workspace->x = area->x; | 76 | workspace->x = output->x + area->x; |
77 | workspace->y = area->y; | 77 | workspace->y = output->y + area->y; |
78 | wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", | 78 | wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", |
79 | workspace->name, workspace->x, workspace->y); | 79 | workspace->name, workspace->x, workspace->y); |
80 | arrange_children_of(workspace); | 80 | arrange_children_of(workspace); |
@@ -247,6 +247,18 @@ void arrange_children_of(struct sway_container *parent) { | |||
247 | arrange_children_of(child); | 247 | arrange_children_of(child); |
248 | } | 248 | } |
249 | } | 249 | } |
250 | |||
251 | // If container is a workspace, process floating containers too | ||
252 | if (parent->type == C_WORKSPACE) { | ||
253 | struct sway_workspace *ws = workspace->sway_workspace; | ||
254 | for (int i = 0; i < ws->floating->children->length; ++i) { | ||
255 | struct sway_container *child = ws->floating->children->items[i]; | ||
256 | if (child->type != C_VIEW) { | ||
257 | arrange_children_of(child); | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
250 | container_damage_whole(parent); | 262 | container_damage_whole(parent); |
251 | update_debug_tree(); | 263 | update_debug_tree(); |
252 | } | 264 | } |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 33d88d7f..9e70da09 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -64,16 +64,6 @@ void container_create_notify(struct sway_container *container) { | |||
64 | } | 64 | } |
65 | } | 65 | } |
66 | 66 | ||
67 | static void container_close_notify(struct sway_container *container) { | ||
68 | if (container == NULL) { | ||
69 | return; | ||
70 | } | ||
71 | // TODO send ipc event type based on the container type | ||
72 | if (container->type == C_VIEW || container->type == C_WORKSPACE) { | ||
73 | ipc_event_window(container, "close"); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static void container_update_textures_recursive(struct sway_container *con) { | 67 | static void container_update_textures_recursive(struct sway_container *con) { |
78 | container_update_title_textures(con); | 68 | container_update_title_textures(con); |
79 | 69 | ||
@@ -143,7 +133,6 @@ static void _container_destroy(struct sway_container *cont) { | |||
143 | } | 133 | } |
144 | 134 | ||
145 | wl_signal_emit(&cont->events.destroy, cont); | 135 | wl_signal_emit(&cont->events.destroy, cont); |
146 | container_close_notify(cont); | ||
147 | 136 | ||
148 | struct sway_container *parent = cont->parent; | 137 | struct sway_container *parent = cont->parent; |
149 | if (cont->children != NULL && cont->children->length) { | 138 | if (cont->children != NULL && cont->children->length) { |
@@ -151,6 +140,7 @@ static void _container_destroy(struct sway_container *cont) { | |||
151 | // container_remove_child, which removes child from this container | 140 | // container_remove_child, which removes child from this container |
152 | while (cont->children != NULL && cont->children->length > 0) { | 141 | while (cont->children != NULL && cont->children->length > 0) { |
153 | struct sway_container *child = cont->children->items[0]; | 142 | struct sway_container *child = cont->children->items[0]; |
143 | ipc_event_window(child, "close"); | ||
154 | container_remove_child(child); | 144 | container_remove_child(child); |
155 | _container_destroy(child); | 145 | _container_destroy(child); |
156 | } | 146 | } |
@@ -188,15 +178,13 @@ static struct sway_container *container_workspace_destroy( | |||
188 | return NULL; | 178 | return NULL; |
189 | } | 179 | } |
190 | 180 | ||
181 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); | ||
182 | ipc_event_window(workspace, "close"); | ||
183 | |||
191 | struct sway_container *parent = workspace->parent; | 184 | struct sway_container *parent = workspace->parent; |
192 | if (workspace->children->length == 0) { | 185 | if (!workspace_is_empty(workspace) && output) { |
193 | // destroy the WS if there are no children (TODO check for floating) | ||
194 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); | ||
195 | ipc_event_workspace(workspace, NULL, "empty"); | ||
196 | } else if (output) { | ||
197 | // Move children to a different workspace on this output | 186 | // Move children to a different workspace on this output |
198 | struct sway_container *new_workspace = NULL; | 187 | struct sway_container *new_workspace = NULL; |
199 | // TODO move floating | ||
200 | for (int i = 0; i < output->children->length; i++) { | 188 | for (int i = 0; i < output->children->length; i++) { |
201 | if (output->children->items[i] != workspace) { | 189 | if (output->children->items[i] != workspace) { |
202 | new_workspace = output->children->items[i]; | 190 | new_workspace = output->children->items[i]; |
@@ -209,6 +197,11 @@ static struct sway_container *container_workspace_destroy( | |||
209 | for (int i = 0; i < workspace->children->length; i++) { | 197 | for (int i = 0; i < workspace->children->length; i++) { |
210 | container_move_to(workspace->children->items[i], new_workspace); | 198 | container_move_to(workspace->children->items[i], new_workspace); |
211 | } | 199 | } |
200 | struct sway_container *floating = workspace->sway_workspace->floating; | ||
201 | for (int i = 0; i < floating->children->length; i++) { | ||
202 | container_move_to(floating->children->items[i], | ||
203 | new_workspace->sway_workspace->floating); | ||
204 | } | ||
212 | } | 205 | } |
213 | 206 | ||
214 | free(workspace->sway_workspace); | 207 | free(workspace->sway_workspace); |
@@ -275,13 +268,17 @@ static void container_root_finish(struct sway_container *con) { | |||
275 | } | 268 | } |
276 | 269 | ||
277 | bool container_reap_empty(struct sway_container *con) { | 270 | bool container_reap_empty(struct sway_container *con) { |
271 | if (con->layout == L_FLOATING) { | ||
272 | // Don't reap the magical floating container that each workspace has | ||
273 | return false; | ||
274 | } | ||
278 | switch (con->type) { | 275 | switch (con->type) { |
279 | case C_ROOT: | 276 | case C_ROOT: |
280 | case C_OUTPUT: | 277 | case C_OUTPUT: |
281 | // dont reap these | 278 | // dont reap these |
282 | break; | 279 | break; |
283 | case C_WORKSPACE: | 280 | case C_WORKSPACE: |
284 | if (!workspace_is_visible(con) && con->children->length == 0) { | 281 | if (!workspace_is_visible(con) && workspace_is_empty(con)) { |
285 | wlr_log(L_DEBUG, "Destroying workspace via reaper"); | 282 | wlr_log(L_DEBUG, "Destroying workspace via reaper"); |
286 | container_workspace_destroy(con); | 283 | container_workspace_destroy(con); |
287 | return true; | 284 | return true; |
@@ -349,10 +346,12 @@ struct sway_container *container_destroy(struct sway_container *con) { | |||
349 | if (con->children->length) { | 346 | if (con->children->length) { |
350 | for (int i = 0; i < con->children->length; ++i) { | 347 | for (int i = 0; i < con->children->length; ++i) { |
351 | struct sway_container *child = con->children->items[0]; | 348 | struct sway_container *child = con->children->items[0]; |
349 | ipc_event_window(child, "close"); | ||
352 | container_remove_child(child); | 350 | container_remove_child(child); |
353 | container_add_child(parent, child); | 351 | container_add_child(parent, child); |
354 | } | 352 | } |
355 | } | 353 | } |
354 | ipc_event_window(con, "close"); | ||
356 | _container_destroy(con); | 355 | _container_destroy(con); |
357 | break; | 356 | break; |
358 | case C_VIEW: | 357 | case C_VIEW: |
@@ -436,7 +435,6 @@ struct sway_container *container_find(struct sway_container *container, | |||
436 | if (!container->children) { | 435 | if (!container->children) { |
437 | return NULL; | 436 | return NULL; |
438 | } | 437 | } |
439 | // TODO: floating windows | ||
440 | for (int i = 0; i < container->children->length; ++i) { | 438 | for (int i = 0; i < container->children->length; ++i) { |
441 | struct sway_container *child = container->children->items[i]; | 439 | struct sway_container *child = container->children->items[i]; |
442 | if (test(child, data)) { | 440 | if (test(child, data)) { |
@@ -448,6 +446,9 @@ struct sway_container *container_find(struct sway_container *container, | |||
448 | } | 446 | } |
449 | } | 447 | } |
450 | } | 448 | } |
449 | if (container->type == C_WORKSPACE) { | ||
450 | return container_find(container->sway_workspace->floating, test, data); | ||
451 | } | ||
451 | return NULL; | 452 | return NULL; |
452 | } | 453 | } |
453 | 454 | ||
@@ -466,14 +467,14 @@ struct sway_container *container_parent(struct sway_container *container, | |||
466 | } | 467 | } |
467 | 468 | ||
468 | static struct sway_container *container_at_view(struct sway_container *swayc, | 469 | static struct sway_container *container_at_view(struct sway_container *swayc, |
469 | double ox, double oy, | 470 | double lx, double ly, |
470 | struct wlr_surface **surface, double *sx, double *sy) { | 471 | struct wlr_surface **surface, double *sx, double *sy) { |
471 | if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { | 472 | if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { |
472 | return NULL; | 473 | return NULL; |
473 | } | 474 | } |
474 | struct sway_view *sview = swayc->sway_view; | 475 | struct sway_view *sview = swayc->sway_view; |
475 | double view_sx = ox - sview->x; | 476 | double view_sx = lx - sview->x; |
476 | double view_sy = oy - sview->y; | 477 | double view_sy = ly - sview->y; |
477 | 478 | ||
478 | double _sx, _sy; | 479 | double _sx, _sy; |
479 | struct wlr_surface *_surface = NULL; | 480 | struct wlr_surface *_surface = NULL; |
@@ -515,18 +516,18 @@ static struct sway_container *container_at_view(struct sway_container *swayc, | |||
515 | * container_at for a container with layout L_TABBED. | 516 | * container_at for a container with layout L_TABBED. |
516 | */ | 517 | */ |
517 | static struct sway_container *container_at_tabbed(struct sway_container *parent, | 518 | static struct sway_container *container_at_tabbed(struct sway_container *parent, |
518 | double ox, double oy, | 519 | double lx, double ly, |
519 | struct wlr_surface **surface, double *sx, double *sy) { | 520 | struct wlr_surface **surface, double *sx, double *sy) { |
520 | if (oy < parent->y || oy > parent->y + parent->height) { | 521 | if (ly < parent->y || ly > parent->y + parent->height) { |
521 | return NULL; | 522 | return NULL; |
522 | } | 523 | } |
523 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 524 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
524 | 525 | ||
525 | // Tab titles | 526 | // Tab titles |
526 | int title_height = container_titlebar_height(); | 527 | int title_height = container_titlebar_height(); |
527 | if (oy < parent->y + title_height) { | 528 | if (ly < parent->y + title_height) { |
528 | int tab_width = parent->width / parent->children->length; | 529 | int tab_width = parent->width / parent->children->length; |
529 | int child_index = (ox - parent->x) / tab_width; | 530 | int child_index = (lx - parent->x) / tab_width; |
530 | if (child_index >= parent->children->length) { | 531 | if (child_index >= parent->children->length) { |
531 | child_index = parent->children->length - 1; | 532 | child_index = parent->children->length - 1; |
532 | } | 533 | } |
@@ -537,23 +538,23 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent, | |||
537 | // Surfaces | 538 | // Surfaces |
538 | struct sway_container *current = seat_get_active_child(seat, parent); | 539 | struct sway_container *current = seat_get_active_child(seat, parent); |
539 | 540 | ||
540 | return container_at(current, ox, oy, surface, sx, sy); | 541 | return container_at(current, lx, ly, surface, sx, sy); |
541 | } | 542 | } |
542 | 543 | ||
543 | /** | 544 | /** |
544 | * container_at for a container with layout L_STACKED. | 545 | * container_at for a container with layout L_STACKED. |
545 | */ | 546 | */ |
546 | static struct sway_container *container_at_stacked( | 547 | static struct sway_container *container_at_stacked( |
547 | struct sway_container *parent, double ox, double oy, | 548 | struct sway_container *parent, double lx, double ly, |
548 | struct wlr_surface **surface, double *sx, double *sy) { | 549 | struct wlr_surface **surface, double *sx, double *sy) { |
549 | if (oy < parent->y || oy > parent->y + parent->height) { | 550 | if (ly < parent->y || ly > parent->y + parent->height) { |
550 | return NULL; | 551 | return NULL; |
551 | } | 552 | } |
552 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 553 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
553 | 554 | ||
554 | // Title bars | 555 | // Title bars |
555 | int title_height = container_titlebar_height(); | 556 | int title_height = container_titlebar_height(); |
556 | int child_index = (oy - parent->y) / title_height; | 557 | int child_index = (ly - parent->y) / title_height; |
557 | if (child_index < parent->children->length) { | 558 | if (child_index < parent->children->length) { |
558 | struct sway_container *child = parent->children->items[child_index]; | 559 | struct sway_container *child = parent->children->items[child_index]; |
559 | return seat_get_focus_inactive(seat, child); | 560 | return seat_get_focus_inactive(seat, child); |
@@ -562,14 +563,14 @@ static struct sway_container *container_at_stacked( | |||
562 | // Surfaces | 563 | // Surfaces |
563 | struct sway_container *current = seat_get_active_child(seat, parent); | 564 | struct sway_container *current = seat_get_active_child(seat, parent); |
564 | 565 | ||
565 | return container_at(current, ox, oy, surface, sx, sy); | 566 | return container_at(current, lx, ly, surface, sx, sy); |
566 | } | 567 | } |
567 | 568 | ||
568 | /** | 569 | /** |
569 | * container_at for a container with layout L_HORIZ or L_VERT. | 570 | * container_at for a container with layout L_HORIZ or L_VERT. |
570 | */ | 571 | */ |
571 | static struct sway_container *container_at_linear(struct sway_container *parent, | 572 | static struct sway_container *container_at_linear(struct sway_container *parent, |
572 | double ox, double oy, | 573 | double lx, double ly, |
573 | struct wlr_surface **surface, double *sx, double *sy) { | 574 | struct wlr_surface **surface, double *sx, double *sy) { |
574 | for (int i = 0; i < parent->children->length; ++i) { | 575 | for (int i = 0; i < parent->children->length; ++i) { |
575 | struct sway_container *child = parent->children->items[i]; | 576 | struct sway_container *child = parent->children->items[i]; |
@@ -579,22 +580,22 @@ static struct sway_container *container_at_linear(struct sway_container *parent, | |||
579 | .width = child->width, | 580 | .width = child->width, |
580 | .height = child->height, | 581 | .height = child->height, |
581 | }; | 582 | }; |
582 | if (wlr_box_contains_point(&box, ox, oy)) { | 583 | if (wlr_box_contains_point(&box, lx, ly)) { |
583 | return container_at(child, ox, oy, surface, sx, sy); | 584 | return container_at(child, lx, ly, surface, sx, sy); |
584 | } | 585 | } |
585 | } | 586 | } |
586 | return NULL; | 587 | return NULL; |
587 | } | 588 | } |
588 | 589 | ||
589 | struct sway_container *container_at(struct sway_container *parent, | 590 | struct sway_container *container_at(struct sway_container *parent, |
590 | double ox, double oy, | 591 | double lx, double ly, |
591 | struct wlr_surface **surface, double *sx, double *sy) { | 592 | struct wlr_surface **surface, double *sx, double *sy) { |
592 | if (!sway_assert(parent->type >= C_WORKSPACE, | 593 | if (!sway_assert(parent->type >= C_WORKSPACE, |
593 | "Expected workspace or deeper")) { | 594 | "Expected workspace or deeper")) { |
594 | return NULL; | 595 | return NULL; |
595 | } | 596 | } |
596 | if (parent->type == C_VIEW) { | 597 | if (parent->type == C_VIEW) { |
597 | return container_at_view(parent, ox, oy, surface, sx, sy); | 598 | return container_at_view(parent, lx, ly, surface, sx, sy); |
598 | } | 599 | } |
599 | if (!parent->children->length) { | 600 | if (!parent->children->length) { |
600 | return NULL; | 601 | return NULL; |
@@ -603,13 +604,14 @@ struct sway_container *container_at(struct sway_container *parent, | |||
603 | switch (parent->layout) { | 604 | switch (parent->layout) { |
604 | case L_HORIZ: | 605 | case L_HORIZ: |
605 | case L_VERT: | 606 | case L_VERT: |
606 | return container_at_linear(parent, ox, oy, surface, sx, sy); | 607 | return container_at_linear(parent, lx, ly, surface, sx, sy); |
607 | case L_TABBED: | 608 | case L_TABBED: |
608 | return container_at_tabbed(parent, ox, oy, surface, sx, sy); | 609 | return container_at_tabbed(parent, lx, ly, surface, sx, sy); |
609 | case L_STACKED: | 610 | case L_STACKED: |
610 | return container_at_stacked(parent, ox, oy, surface, sx, sy); | 611 | return container_at_stacked(parent, lx, ly, surface, sx, sy); |
611 | case L_FLOATING: | 612 | case L_FLOATING: |
612 | return NULL; // TODO | 613 | sway_assert(false, "Didn't expect to see floating here"); |
614 | return NULL; | ||
613 | case L_NONE: | 615 | case L_NONE: |
614 | return NULL; | 616 | return NULL; |
615 | } | 617 | } |
@@ -617,6 +619,34 @@ struct sway_container *container_at(struct sway_container *parent, | |||
617 | return NULL; | 619 | return NULL; |
618 | } | 620 | } |
619 | 621 | ||
622 | struct sway_container *floating_container_at(double lx, double ly, | ||
623 | struct wlr_surface **surface, double *sx, double *sy) { | ||
624 | for (int i = 0; i < root_container.children->length; ++i) { | ||
625 | struct sway_container *output = root_container.children->items[i]; | ||
626 | for (int j = 0; j < output->children->length; ++j) { | ||
627 | struct sway_container *workspace = output->children->items[j]; | ||
628 | struct sway_workspace *ws = workspace->sway_workspace; | ||
629 | if (!workspace_is_visible(workspace)) { | ||
630 | continue; | ||
631 | } | ||
632 | for (int k = 0; k < ws->floating->children->length; ++k) { | ||
633 | struct sway_container *floater = | ||
634 | ws->floating->children->items[k]; | ||
635 | struct wlr_box box = { | ||
636 | .x = floater->x, | ||
637 | .y = floater->y, | ||
638 | .width = floater->width, | ||
639 | .height = floater->height, | ||
640 | }; | ||
641 | if (wlr_box_contains_point(&box, lx, ly)) { | ||
642 | return container_at(floater, lx, ly, surface, sx, sy); | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | return NULL; | ||
648 | } | ||
649 | |||
620 | void container_for_each_descendant_dfs(struct sway_container *container, | 650 | void container_for_each_descendant_dfs(struct sway_container *container, |
621 | void (*f)(struct sway_container *container, void *data), | 651 | void (*f)(struct sway_container *container, void *data), |
622 | void *data) { | 652 | void *data) { |
@@ -674,7 +704,7 @@ static bool find_child_func(struct sway_container *con, void *data) { | |||
674 | 704 | ||
675 | bool container_has_child(struct sway_container *con, | 705 | bool container_has_child(struct sway_container *con, |
676 | struct sway_container *child) { | 706 | struct sway_container *child) { |
677 | if (con == NULL || con->type == C_VIEW || con->children->length == 0) { | 707 | if (con == NULL || con->type == C_VIEW) { |
678 | return false; | 708 | return false; |
679 | } | 709 | } |
680 | return container_find(con, find_child_func, child); | 710 | return container_find(con, find_child_func, child); |
@@ -866,3 +896,60 @@ void container_notify_subtree_changed(struct sway_container *container) { | |||
866 | size_t container_titlebar_height() { | 896 | size_t container_titlebar_height() { |
867 | return config->font_height + TITLEBAR_V_PADDING * 2; | 897 | return config->font_height + TITLEBAR_V_PADDING * 2; |
868 | } | 898 | } |
899 | |||
900 | void container_set_floating(struct sway_container *container, bool enable) { | ||
901 | if (container_is_floating(container) == enable) { | ||
902 | return; | ||
903 | } | ||
904 | |||
905 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | ||
906 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
907 | container_damage_whole(container); | ||
908 | |||
909 | if (enable) { | ||
910 | container_remove_child(container); | ||
911 | container_add_child(workspace->sway_workspace->floating, container); | ||
912 | if (container->type == C_VIEW) { | ||
913 | view_autoconfigure(container->sway_view); | ||
914 | } | ||
915 | seat_set_focus(seat, seat_get_focus_inactive(seat, container)); | ||
916 | container_reap_empty_recursive(workspace); | ||
917 | } else { | ||
918 | // Returning to tiled | ||
919 | container_remove_child(container); | ||
920 | container_add_child(workspace, container); | ||
921 | container->width = container->parent->width; | ||
922 | container->height = container->parent->height; | ||
923 | container->is_sticky = false; | ||
924 | container_reap_empty_recursive(workspace->sway_workspace->floating); | ||
925 | } | ||
926 | arrange_workspace(workspace); | ||
927 | container_damage_whole(container); | ||
928 | } | ||
929 | |||
930 | void container_set_geometry_from_floating_view(struct sway_container *con) { | ||
931 | if (!sway_assert(con->type == C_VIEW, "Expected a view")) { | ||
932 | return; | ||
933 | } | ||
934 | if (!sway_assert(container_is_floating(con), | ||
935 | "Expected a floating view")) { | ||
936 | return; | ||
937 | } | ||
938 | struct sway_view *view = con->sway_view; | ||
939 | size_t border_width = view->border_thickness * (view->border != B_NONE); | ||
940 | size_t top = | ||
941 | view->border == B_NORMAL ? container_titlebar_height() : border_width; | ||
942 | |||
943 | con->x = view->x - border_width; | ||
944 | con->y = view->y - top; | ||
945 | con->width = view->width + border_width * 2; | ||
946 | con->height = top + view->height + border_width; | ||
947 | } | ||
948 | |||
949 | bool container_is_floating(struct sway_container *container) { | ||
950 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | ||
951 | if (!workspace) { | ||
952 | return false; | ||
953 | } | ||
954 | return container->parent == workspace->sway_workspace->floating; | ||
955 | } | ||
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 2f4ae667..d88948dc 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -45,20 +45,14 @@ void layout_init(void) { | |||
45 | } | 45 | } |
46 | 46 | ||
47 | static int index_child(const struct sway_container *child) { | 47 | static int index_child(const struct sway_container *child) { |
48 | // TODO handle floating | ||
49 | struct sway_container *parent = child->parent; | 48 | struct sway_container *parent = child->parent; |
50 | int i, len; | 49 | for (int i = 0; i < parent->children->length; ++i) { |
51 | len = parent->children->length; | ||
52 | for (i = 0; i < len; ++i) { | ||
53 | if (parent->children->items[i] == child) { | 50 | if (parent->children->items[i] == child) { |
54 | break; | 51 | return i; |
55 | } | 52 | } |
56 | } | 53 | } |
57 | 54 | // This happens if the child is a floating container | |
58 | if (!sway_assert(i < len, "Stray container")) { | 55 | return -1; |
59 | return -1; | ||
60 | } | ||
61 | return i; | ||
62 | } | 56 | } |
63 | 57 | ||
64 | static void container_handle_fullscreen_reparent(struct sway_container *viewcon, | 58 | static void container_handle_fullscreen_reparent(struct sway_container *viewcon, |
@@ -160,6 +154,10 @@ void container_move_to(struct sway_container *container, | |||
160 | || container_has_ancestor(container, destination)) { | 154 | || container_has_ancestor(container, destination)) { |
161 | return; | 155 | return; |
162 | } | 156 | } |
157 | if (container_is_floating(container)) { | ||
158 | // TODO | ||
159 | return; | ||
160 | } | ||
163 | struct sway_container *old_parent = container_remove_child(container); | 161 | struct sway_container *old_parent = container_remove_child(container); |
164 | container->width = container->height = 0; | 162 | container->width = container->height = 0; |
165 | container->saved_width = container->saved_height = 0; | 163 | container->saved_width = container->saved_height = 0; |
@@ -172,8 +170,9 @@ void container_move_to(struct sway_container *container, | |||
172 | } | 170 | } |
173 | wl_signal_emit(&container->events.reparent, old_parent); | 171 | wl_signal_emit(&container->events.reparent, old_parent); |
174 | if (container->type == C_WORKSPACE) { | 172 | if (container->type == C_WORKSPACE) { |
175 | struct sway_seat *seat = input_manager_get_default_seat( | 173 | // If moving a workspace to a new output, maybe create a new workspace |
176 | input_manager); | 174 | // on the previous output |
175 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | ||
177 | if (old_parent->children->length == 0) { | 176 | if (old_parent->children->length == 0) { |
178 | char *ws_name = workspace_next_name(old_parent->name); | 177 | char *ws_name = workspace_next_name(old_parent->name); |
179 | struct sway_container *ws = | 178 | struct sway_container *ws = |
@@ -681,26 +680,6 @@ static struct sway_container *get_swayc_in_output_direction( | |||
681 | return ws; | 680 | return ws; |
682 | } | 681 | } |
683 | 682 | ||
684 | static void get_layout_center_position(struct sway_container *container, | ||
685 | int *x, int *y) { | ||
686 | // FIXME view coords are inconsistently referred to in layout/output systems | ||
687 | if (container->type == C_OUTPUT) { | ||
688 | *x = container->x + container->width/2; | ||
689 | *y = container->y + container->height/2; | ||
690 | } else { | ||
691 | struct sway_container *output = container_parent(container, C_OUTPUT); | ||
692 | if (container->type == C_WORKSPACE) { | ||
693 | // Workspace coordinates are actually wrong/arbitrary, but should | ||
694 | // be same as output. | ||
695 | *x = output->x; | ||
696 | *y = output->y; | ||
697 | } else { | ||
698 | *x = output->x + container->x; | ||
699 | *y = output->y + container->y; | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | |||
704 | static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { | 683 | static struct sway_container *sway_output_from_wlr(struct wlr_output *output) { |
705 | if (output == NULL) { | 684 | if (output == NULL) { |
706 | return NULL; | 685 | return NULL; |
@@ -719,6 +698,10 @@ struct sway_container *container_get_in_direction( | |||
719 | enum movement_direction dir) { | 698 | enum movement_direction dir) { |
720 | struct sway_container *parent = container->parent; | 699 | struct sway_container *parent = container->parent; |
721 | 700 | ||
701 | if (container_is_floating(container)) { | ||
702 | return NULL; | ||
703 | } | ||
704 | |||
722 | if (container->type == C_VIEW && container->sway_view->is_fullscreen) { | 705 | if (container->type == C_VIEW && container->sway_view->is_fullscreen) { |
723 | if (dir == MOVE_PARENT || dir == MOVE_CHILD) { | 706 | if (dir == MOVE_PARENT || dir == MOVE_CHILD) { |
724 | return NULL; | 707 | return NULL; |
@@ -743,14 +726,17 @@ struct sway_container *container_get_in_direction( | |||
743 | bool can_move = false; | 726 | bool can_move = false; |
744 | int desired; | 727 | int desired; |
745 | int idx = index_child(container); | 728 | int idx = index_child(container); |
729 | if (idx == -1) { | ||
730 | return NULL; | ||
731 | } | ||
746 | if (parent->type == C_ROOT) { | 732 | if (parent->type == C_ROOT) { |
747 | enum wlr_direction wlr_dir = 0; | 733 | enum wlr_direction wlr_dir = 0; |
748 | if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), | 734 | if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), |
749 | "got invalid direction: %d", dir)) { | 735 | "got invalid direction: %d", dir)) { |
750 | return NULL; | 736 | return NULL; |
751 | } | 737 | } |
752 | int lx, ly; | 738 | int lx = container->x + container->width / 2; |
753 | get_layout_center_position(container, &lx, &ly); | 739 | int ly = container->y + container->height / 2; |
754 | struct wlr_output_layout *layout = | 740 | struct wlr_output_layout *layout = |
755 | root_container.sway_root->output_layout; | 741 | root_container.sway_root->output_layout; |
756 | struct wlr_output *wlr_adjacent = | 742 | struct wlr_output *wlr_adjacent = |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 26ff1e8d..3117ded6 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -119,13 +119,28 @@ const char *view_get_shell(struct sway_view *view) { | |||
119 | return "unknown"; | 119 | return "unknown"; |
120 | } | 120 | } |
121 | 121 | ||
122 | void view_configure(struct sway_view *view, double ox, double oy, int width, | 122 | void view_configure(struct sway_view *view, double lx, double ly, int width, |
123 | int height) { | 123 | int height) { |
124 | if (view->impl->configure) { | 124 | if (view->impl->configure) { |
125 | view->impl->configure(view, ox, oy, width, height); | 125 | view->impl->configure(view, lx, ly, width, height); |
126 | } | 126 | } |
127 | } | 127 | } |
128 | 128 | ||
129 | static void view_autoconfigure_floating(struct sway_view *view) { | ||
130 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | ||
131 | int max_width = ws->width * 0.6666; | ||
132 | int max_height = ws->height * 0.6666; | ||
133 | int width = | ||
134 | view->natural_width > max_width ? max_width : view->natural_width; | ||
135 | int height = | ||
136 | view->natural_height > max_height ? max_height : view->natural_height; | ||
137 | int lx = ws->x + (ws->width - width) / 2; | ||
138 | int ly = ws->y + (ws->height - height) / 2; | ||
139 | |||
140 | view->border_left = view->border_right = view->border_bottom = true; | ||
141 | view_configure(view, lx, ly, width, height); | ||
142 | } | ||
143 | |||
129 | void view_autoconfigure(struct sway_view *view) { | 144 | void view_autoconfigure(struct sway_view *view) { |
130 | if (!sway_assert(view->swayc, | 145 | if (!sway_assert(view->swayc, |
131 | "Called view_autoconfigure() on a view without a swayc")) { | 146 | "Called view_autoconfigure() on a view without a swayc")) { |
@@ -135,8 +150,12 @@ void view_autoconfigure(struct sway_view *view) { | |||
135 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 150 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); |
136 | 151 | ||
137 | if (view->is_fullscreen) { | 152 | if (view->is_fullscreen) { |
138 | view_configure(view, 0, 0, output->width, output->height); | 153 | view_configure(view, output->x, output->y, output->width, output->height); |
139 | view->x = view->y = 0; | 154 | return; |
155 | } | ||
156 | |||
157 | if (container_is_floating(view->swayc)) { | ||
158 | view_autoconfigure_floating(view); | ||
140 | return; | 159 | return; |
141 | } | 160 | } |
142 | 161 | ||
@@ -158,21 +177,19 @@ void view_autoconfigure(struct sway_view *view) { | |||
158 | 177 | ||
159 | view->border_top = view->border_bottom = true; | 178 | view->border_top = view->border_bottom = true; |
160 | view->border_left = view->border_right = true; | 179 | view->border_left = view->border_right = true; |
161 | if (view->swayc->layout != L_FLOATING) { | 180 | if (config->hide_edge_borders == E_BOTH |
162 | if (config->hide_edge_borders == E_BOTH | 181 | || config->hide_edge_borders == E_VERTICAL |
163 | || config->hide_edge_borders == E_VERTICAL | 182 | || (config->hide_edge_borders == E_SMART && !other_views)) { |
164 | || (config->hide_edge_borders == E_SMART && !other_views)) { | 183 | view->border_left = view->swayc->x != ws->x; |
165 | view->border_left = view->swayc->x != ws->x; | 184 | int right_x = view->swayc->x + view->swayc->width; |
166 | int right_x = view->swayc->x + view->swayc->width; | 185 | view->border_right = right_x != ws->x + ws->width; |
167 | view->border_right = right_x != ws->x + ws->width; | 186 | } |
168 | } | 187 | if (config->hide_edge_borders == E_BOTH |
169 | if (config->hide_edge_borders == E_BOTH | 188 | || config->hide_edge_borders == E_HORIZONTAL |
170 | || config->hide_edge_borders == E_HORIZONTAL | 189 | || (config->hide_edge_borders == E_SMART && !other_views)) { |
171 | || (config->hide_edge_borders == E_SMART && !other_views)) { | 190 | view->border_top = view->swayc->y != ws->y; |
172 | view->border_top = view->swayc->y != ws->y; | 191 | int bottom_y = view->swayc->y + view->swayc->height; |
173 | int bottom_y = view->swayc->y + view->swayc->height; | 192 | view->border_bottom = bottom_y != ws->y + ws->height; |
174 | view->border_bottom = bottom_y != ws->y + ws->height; | ||
175 | } | ||
176 | } | 193 | } |
177 | 194 | ||
178 | double x, y, width, height; | 195 | double x, y, width, height; |
@@ -184,11 +201,11 @@ void view_autoconfigure(struct sway_view *view) { | |||
184 | // disable any top border because we'll always have the title bar. | 201 | // disable any top border because we'll always have the title bar. |
185 | if (view->swayc->parent->layout == L_TABBED) { | 202 | if (view->swayc->parent->layout == L_TABBED) { |
186 | y_offset = container_titlebar_height(); | 203 | y_offset = container_titlebar_height(); |
187 | view->border_top = 0; | 204 | view->border_top = false; |
188 | } else if (view->swayc->parent->layout == L_STACKED) { | 205 | } else if (view->swayc->parent->layout == L_STACKED) { |
189 | y_offset = container_titlebar_height() | 206 | y_offset = container_titlebar_height() |
190 | * view->swayc->parent->children->length; | 207 | * view->swayc->parent->children->length; |
191 | view->border_top = 0; | 208 | view->border_top = false; |
192 | } | 209 | } |
193 | 210 | ||
194 | switch (view->border) { | 211 | switch (view->border) { |
@@ -257,6 +274,12 @@ void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { | |||
257 | view_set_fullscreen(workspace->sway_workspace->fullscreen, false); | 274 | view_set_fullscreen(workspace->sway_workspace->fullscreen, false); |
258 | } | 275 | } |
259 | workspace->sway_workspace->fullscreen = view; | 276 | workspace->sway_workspace->fullscreen = view; |
277 | view->saved_x = view->x; | ||
278 | view->saved_y = view->y; | ||
279 | view->saved_width = view->width; | ||
280 | view->saved_height = view->height; | ||
281 | view->swayc->saved_x = view->swayc->x; | ||
282 | view->swayc->saved_y = view->swayc->y; | ||
260 | view->swayc->saved_width = view->swayc->width; | 283 | view->swayc->saved_width = view->swayc->width; |
261 | view->swayc->saved_height = view->swayc->height; | 284 | view->swayc->saved_height = view->swayc->height; |
262 | 285 | ||
@@ -277,8 +300,14 @@ void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { | |||
277 | } | 300 | } |
278 | } else { | 301 | } else { |
279 | workspace->sway_workspace->fullscreen = NULL; | 302 | workspace->sway_workspace->fullscreen = NULL; |
280 | view->swayc->width = view->swayc->saved_width; | 303 | if (container_is_floating(view->swayc)) { |
281 | view->swayc->height = view->swayc->saved_height; | 304 | view_configure(view, view->saved_x, view->saved_y, |
305 | view->saved_width, view->saved_height); | ||
306 | } else { | ||
307 | view->swayc->width = view->swayc->saved_width; | ||
308 | view->swayc->height = view->swayc->saved_height; | ||
309 | view_autoconfigure(view); | ||
310 | } | ||
282 | } | 311 | } |
283 | } | 312 | } |
284 | 313 | ||
@@ -452,6 +481,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
452 | // TODO: CT_ASSIGN_OUTPUT | 481 | // TODO: CT_ASSIGN_OUTPUT |
453 | } | 482 | } |
454 | } | 483 | } |
484 | // If we're about to launch the view into the floating container, then | ||
485 | // launch it as a tiled view in the root of the workspace instead. | ||
486 | if (container_is_floating(focus)) { | ||
487 | focus = focus->parent->parent; | ||
488 | } | ||
455 | free(criterias); | 489 | free(criterias); |
456 | cont = container_view_create(focus, view); | 490 | cont = container_view_create(focus, view); |
457 | 491 | ||
@@ -468,7 +502,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
468 | wl_signal_add(&view->swayc->events.reparent, &view->container_reparent); | 502 | wl_signal_add(&view->swayc->events.reparent, &view->container_reparent); |
469 | view->container_reparent.notify = view_handle_container_reparent; | 503 | view->container_reparent.notify = view_handle_container_reparent; |
470 | 504 | ||
471 | arrange_children_of(cont->parent); | 505 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { |
506 | container_set_floating(view->swayc, true); | ||
507 | } else { | ||
508 | arrange_children_of(cont->parent); | ||
509 | } | ||
510 | |||
472 | input_manager_set_focus(input_manager, cont); | 511 | input_manager_set_focus(input_manager, cont); |
473 | if (workspace) { | 512 | if (workspace) { |
474 | workspace_switch(workspace); | 513 | workspace_switch(workspace); |
@@ -516,16 +555,16 @@ void view_unmap(struct sway_view *view) { | |||
516 | } | 555 | } |
517 | } | 556 | } |
518 | 557 | ||
519 | void view_update_position(struct sway_view *view, double ox, double oy) { | 558 | void view_update_position(struct sway_view *view, double lx, double ly) { |
520 | if (view->swayc->x == ox && view->swayc->y == oy) { | 559 | if (view->x == lx && view->y == ly) { |
521 | return; | 560 | return; |
522 | } | 561 | } |
523 | |||
524 | // TODO: Only allow this if the view is floating (this function will only be | ||
525 | // called in response to wayland clients wanting to reposition themselves). | ||
526 | container_damage_whole(view->swayc); | 562 | container_damage_whole(view->swayc); |
527 | view->swayc->x = ox; | 563 | view->x = lx; |
528 | view->swayc->y = oy; | 564 | view->y = ly; |
565 | if (container_is_floating(view->swayc)) { | ||
566 | container_set_geometry_from_floating_view(view->swayc); | ||
567 | } | ||
529 | container_damage_whole(view->swayc); | 568 | container_damage_whole(view->swayc); |
530 | } | 569 | } |
531 | 570 | ||
@@ -533,15 +572,15 @@ void view_update_size(struct sway_view *view, int width, int height) { | |||
533 | if (view->width == width && view->height == height) { | 572 | if (view->width == width && view->height == height) { |
534 | return; | 573 | return; |
535 | } | 574 | } |
536 | |||
537 | container_damage_whole(view->swayc); | 575 | container_damage_whole(view->swayc); |
538 | // Should we update the swayc width/height here too? | ||
539 | view->width = width; | 576 | view->width = width; |
540 | view->height = height; | 577 | view->height = height; |
578 | if (container_is_floating(view->swayc)) { | ||
579 | container_set_geometry_from_floating_view(view->swayc); | ||
580 | } | ||
541 | container_damage_whole(view->swayc); | 581 | container_damage_whole(view->swayc); |
542 | } | 582 | } |
543 | 583 | ||
544 | |||
545 | static void view_subsurface_create(struct sway_view *view, | 584 | static void view_subsurface_create(struct sway_view *view, |
546 | struct wlr_subsurface *subsurface) { | 585 | struct wlr_subsurface *subsurface) { |
547 | struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); | 586 | struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); |
@@ -888,6 +927,19 @@ bool view_is_visible(struct sway_view *view) { | |||
888 | if (!view->swayc) { | 927 | if (!view->swayc) { |
889 | return false; | 928 | return false; |
890 | } | 929 | } |
930 | struct sway_container *workspace = | ||
931 | container_parent(view->swayc, C_WORKSPACE); | ||
932 | // Determine if view is nested inside a floating container which is sticky. | ||
933 | // A simple floating view will have this ancestry: | ||
934 | // C_VIEW -> floating -> workspace | ||
935 | // A more complex ancestry could be: | ||
936 | // C_VIEW -> C_CONTAINER (tabbed) -> floating -> workspace | ||
937 | struct sway_container *floater = view->swayc; | ||
938 | while (floater->parent->type != C_WORKSPACE | ||
939 | && floater->parent->parent->type != C_WORKSPACE) { | ||
940 | floater = floater->parent; | ||
941 | } | ||
942 | bool is_sticky = container_is_floating(floater) && floater->is_sticky; | ||
891 | // Check view isn't in a tabbed or stacked container on an inactive tab | 943 | // Check view isn't in a tabbed or stacked container on an inactive tab |
892 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 944 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
893 | struct sway_container *container = view->swayc; | 945 | struct sway_container *container = view->swayc; |
@@ -901,10 +953,12 @@ bool view_is_visible(struct sway_view *view) { | |||
901 | container = container->parent; | 953 | container = container->parent; |
902 | } | 954 | } |
903 | // Check view isn't hidden by another fullscreen view | 955 | // Check view isn't hidden by another fullscreen view |
904 | struct sway_container *workspace = container; | ||
905 | if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { | 956 | if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { |
906 | return false; | 957 | return false; |
907 | } | 958 | } |
908 | // Check the workspace is visible | 959 | // Check the workspace is visible |
909 | return workspace_is_visible(workspace); | 960 | if (!is_sticky) { |
961 | return workspace_is_visible(workspace); | ||
962 | } | ||
963 | return true; | ||
910 | } | 964 | } |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index f34baa9e..f78ae9a5 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "sway/tree/arrange.h" | 12 | #include "sway/tree/arrange.h" |
13 | #include "sway/tree/container.h" | 13 | #include "sway/tree/container.h" |
14 | #include "sway/tree/workspace.h" | 14 | #include "sway/tree/workspace.h" |
15 | #include "list.h" | ||
15 | #include "log.h" | 16 | #include "log.h" |
16 | #include "util.h" | 17 | #include "util.h" |
17 | 18 | ||
@@ -64,6 +65,9 @@ struct sway_container *workspace_create(struct sway_container *output, | |||
64 | return NULL; | 65 | return NULL; |
65 | } | 66 | } |
66 | swayws->swayc = workspace; | 67 | swayws->swayc = workspace; |
68 | swayws->floating = container_create(C_CONTAINER); | ||
69 | swayws->floating->parent = swayws->swayc; | ||
70 | swayws->floating->layout = L_FLOATING; | ||
67 | workspace->sway_workspace = swayws; | 71 | workspace->sway_workspace = swayws; |
68 | 72 | ||
69 | container_add_child(output, workspace); | 73 | container_add_child(output, workspace); |
@@ -383,7 +387,21 @@ bool workspace_switch(struct sway_container *workspace) { | |||
383 | strcpy(prev_workspace_name, active_ws->name); | 387 | strcpy(prev_workspace_name, active_ws->name); |
384 | } | 388 | } |
385 | 389 | ||
386 | // TODO: Deal with sticky containers | 390 | // Move sticky containers to new workspace |
391 | struct sway_container *next_output = workspace->parent; | ||
392 | struct sway_container *next_output_prev_ws = | ||
393 | seat_get_active_child(seat, next_output); | ||
394 | struct sway_container *floating = | ||
395 | next_output_prev_ws->sway_workspace->floating; | ||
396 | bool has_sticky = false; | ||
397 | for (int i = 0; i < floating->children->length; ++i) { | ||
398 | struct sway_container *floater = floating->children->items[i]; | ||
399 | if (floater->is_sticky) { | ||
400 | has_sticky = true; | ||
401 | container_remove_child(floater); | ||
402 | container_add_child(workspace->sway_workspace->floating, floater); | ||
403 | } | ||
404 | } | ||
387 | 405 | ||
388 | wlr_log(L_DEBUG, "Switching to workspace %p:%s", | 406 | wlr_log(L_DEBUG, "Switching to workspace %p:%s", |
389 | workspace, workspace->name); | 407 | workspace, workspace->name); |
@@ -391,6 +409,16 @@ bool workspace_switch(struct sway_container *workspace) { | |||
391 | if (next == NULL) { | 409 | if (next == NULL) { |
392 | next = workspace; | 410 | next = workspace; |
393 | } | 411 | } |
412 | if (has_sticky) { | ||
413 | // If there's a sticky container, we might be setting focus to the same | ||
414 | // container that's already focused, so seat_set_focus is effectively a | ||
415 | // no op. We therefore need to send the IPC event and clean up the old | ||
416 | // workspace here. | ||
417 | ipc_event_workspace(active_ws, workspace, "focus"); | ||
418 | if (!workspace_is_visible(active_ws) && workspace_is_empty(active_ws)) { | ||
419 | container_destroy(active_ws); | ||
420 | } | ||
421 | } | ||
394 | seat_set_focus(seat, next); | 422 | seat_set_focus(seat, next); |
395 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | 423 | struct sway_container *output = container_parent(workspace, C_OUTPUT); |
396 | arrange_output(output); | 424 | arrange_output(output); |
@@ -406,3 +434,21 @@ bool workspace_is_visible(struct sway_container *ws) { | |||
406 | } | 434 | } |
407 | return focus == ws; | 435 | return focus == ws; |
408 | } | 436 | } |
437 | |||
438 | bool workspace_is_empty(struct sway_container *ws) { | ||
439 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
440 | return false; | ||
441 | } | ||
442 | if (ws->children->length) { | ||
443 | return false; | ||
444 | } | ||
445 | // Sticky views are not considered to be part of this workspace | ||
446 | struct sway_container *floating = ws->sway_workspace->floating; | ||
447 | for (int i = 0; i < floating->children->length; ++i) { | ||
448 | struct sway_container *floater = floating->children->items[i]; | ||
449 | if (!floater->is_sticky) { | ||
450 | return false; | ||
451 | } | ||
452 | } | ||
453 | return true; | ||
454 | } | ||