diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-05-24 22:30:44 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-06-01 23:14:58 +1000 |
commit | 1f2e399ade77070a2d0b82856ad9a3eef96b8676 (patch) | |
tree | c469197e140051aea912cb173723c7e55ce1e410 | |
parent | Send frame done to floating views (diff) | |
download | sway-1f2e399ade77070a2d0b82856ad9a3eef96b8676.tar.gz sway-1f2e399ade77070a2d0b82856ad9a3eef96b8676.tar.zst sway-1f2e399ade77070a2d0b82856ad9a3eef96b8676.zip |
Implement floating
-rw-r--r-- | include/sway/tree/container.h | 22 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 3 | ||||
-rw-r--r-- | include/sway/tree/view.h | 10 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 4 | ||||
-rw-r--r-- | sway/commands.c | 1 | ||||
-rw-r--r-- | sway/commands/floating.c | 25 | ||||
-rw-r--r-- | sway/commands/sticky.c | 40 | ||||
-rw-r--r-- | sway/criteria.c | 9 | ||||
-rw-r--r-- | sway/desktop/output.c | 114 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 32 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 32 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 97 | ||||
-rw-r--r-- | sway/input/cursor.c | 3 | ||||
-rw-r--r-- | sway/input/seat.c | 16 | ||||
-rw-r--r-- | sway/ipc-json.c | 10 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/tree/arrange.c | 12 | ||||
-rw-r--r-- | sway/tree/container.c | 133 | ||||
-rw-r--r-- | sway/tree/layout.c | 73 | ||||
-rw-r--r-- | sway/tree/view.c | 87 | ||||
-rw-r--r-- | sway/tree/workspace.c | 17 |
21 files changed, 572 insertions, 169 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index a4ffd25b..b802e1d1 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -75,8 +75,13 @@ struct sway_container { | |||
75 | enum sway_container_layout layout; | 75 | enum sway_container_layout layout; |
76 | enum sway_container_layout prev_layout; | 76 | enum sway_container_layout prev_layout; |
77 | 77 | ||
78 | // Allow the container to be automatically removed if it's empty. True by | ||
79 | // default, false for the magic floating container that each workspace has. | ||
80 | bool reapable; | ||
81 | |||
78 | // Saves us from searching the list of children/floating in the parent | 82 | // Saves us from searching the list of children/floating in the parent |
79 | bool is_floating; | 83 | bool is_floating; |
84 | bool is_sticky; | ||
80 | 85 | ||
81 | // For C_ROOT, this has no meaning | 86 | // For C_ROOT, this has no meaning |
82 | // For C_OUTPUT, this is the output position in layout coordinates | 87 | // For C_OUTPUT, this is the output position in layout coordinates |
@@ -174,6 +179,13 @@ struct sway_container *container_at(struct sway_container *container, | |||
174 | double *sx, double *sy); | 179 | double *sx, double *sy); |
175 | 180 | ||
176 | /** | 181 | /** |
182 | * Same as container_at, but only checks floating views and expects coordinates | ||
183 | * to be layout coordinates, as that's what floating views use. | ||
184 | */ | ||
185 | struct sway_container *floating_container_at(double lx, double ly, | ||
186 | struct wlr_surface **surface, double *sx, double *sy); | ||
187 | |||
188 | /** | ||
177 | * Apply the function for each descendant of the container breadth first. | 189 | * Apply the function for each descendant of the container breadth first. |
178 | */ | 190 | */ |
179 | void container_for_each_descendant_bfs(struct sway_container *container, | 191 | void container_for_each_descendant_bfs(struct sway_container *container, |
@@ -229,4 +241,14 @@ void container_notify_subtree_changed(struct sway_container *container); | |||
229 | */ | 241 | */ |
230 | size_t container_titlebar_height(void); | 242 | size_t container_titlebar_height(void); |
231 | 243 | ||
244 | void container_set_floating(struct sway_container *container, bool enable); | ||
245 | |||
246 | void container_set_geometry_from_view(struct sway_container *container); | ||
247 | |||
248 | /** | ||
249 | * Determine if the given container is itself floating or has a floating | ||
250 | * ancestor. | ||
251 | */ | ||
252 | bool container_self_or_parent_floating(struct sway_container *container); | ||
253 | |||
232 | #endif | 254 | #endif |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 33d0a5d0..2e0f2abf 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h | |||
@@ -46,9 +46,6 @@ struct sway_container *container_add_sibling(struct sway_container *parent, | |||
46 | 46 | ||
47 | struct sway_container *container_remove_child(struct sway_container *child); | 47 | struct sway_container *container_remove_child(struct sway_container *child); |
48 | 48 | ||
49 | void container_add_floating(struct sway_container *workspace, | ||
50 | struct sway_container *child); | ||
51 | |||
52 | struct sway_container *container_replace_child(struct sway_container *child, | 49 | struct sway_container *container_replace_child(struct sway_container *child, |
53 | struct sway_container *new_child); | 50 | struct sway_container *new_child); |
54 | 51 | ||
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index a8bf4955..6990e5b6 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -32,7 +32,9 @@ struct sway_view_impl { | |||
32 | void (*configure)(struct sway_view *view, double ox, double oy, int width, | 32 | void (*configure)(struct sway_view *view, double ox, double oy, 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_maximized)(struct sway_view *view, bool maximized); | ||
35 | void (*set_fullscreen)(struct sway_view *view, bool fullscreen); | 36 | void (*set_fullscreen)(struct sway_view *view, bool fullscreen); |
37 | bool (*wants_floating)(struct sway_view *view); | ||
36 | void (*for_each_surface)(struct sway_view *view, | 38 | void (*for_each_surface)(struct sway_view *view, |
37 | wlr_surface_iterator_func_t iterator, void *user_data); | 39 | wlr_surface_iterator_func_t iterator, void *user_data); |
38 | void (*close)(struct sway_view *view); | 40 | void (*close)(struct sway_view *view); |
@@ -50,6 +52,10 @@ struct sway_view { | |||
50 | double x, y; | 52 | double x, y; |
51 | int width, height; | 53 | int width, height; |
52 | 54 | ||
55 | // The size the view would want to be if it weren't tiled. | ||
56 | // Used when changing a view from tiled to floating. | ||
57 | int natural_width, natural_height; | ||
58 | |||
53 | bool is_fullscreen; | 59 | bool is_fullscreen; |
54 | 60 | ||
55 | char *title_format; | 61 | char *title_format; |
@@ -214,6 +220,8 @@ void view_autoconfigure(struct sway_view *view); | |||
214 | 220 | ||
215 | void view_set_activated(struct sway_view *view, bool activated); | 221 | void view_set_activated(struct sway_view *view, bool activated); |
216 | 222 | ||
223 | void view_set_maximized(struct sway_view *view, bool maximized); | ||
224 | |||
217 | void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen); | 225 | void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen); |
218 | 226 | ||
219 | void view_set_fullscreen(struct sway_view *view, bool fullscreen); | 227 | void view_set_fullscreen(struct sway_view *view, bool fullscreen); |
@@ -236,7 +244,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface); | |||
236 | 244 | ||
237 | void view_unmap(struct sway_view *view); | 245 | void view_unmap(struct sway_view *view); |
238 | 246 | ||
239 | void view_update_position(struct sway_view *view, double ox, double oy); | 247 | void view_update_position(struct sway_view *view, double lx, double ly); |
240 | 248 | ||
241 | void view_update_size(struct sway_view *view, int width, int height); | 249 | void view_update_size(struct sway_view *view, int width, int height); |
242 | 250 | ||
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index ece0ab5c..81321fc8 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -8,7 +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 | list_t *floating; | 11 | struct sway_container *floating; |
12 | }; | 12 | }; |
13 | 13 | ||
14 | extern char *prev_workspace_name; | 14 | extern char *prev_workspace_name; |
@@ -31,4 +31,6 @@ struct sway_container *workspace_prev(struct sway_container *current); | |||
31 | 31 | ||
32 | bool workspace_is_visible(struct sway_container *ws); | 32 | bool workspace_is_visible(struct sway_container *ws); |
33 | 33 | ||
34 | bool workspace_is_empty(struct sway_container *ws); | ||
35 | |||
34 | #endif | 36 | #endif |
diff --git a/sway/commands.c b/sway/commands.c index 4a8d11ba..e9762bef 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -190,6 +190,7 @@ static struct cmd_handler command_handlers[] = { | |||
190 | { "splith", cmd_splith }, | 190 | { "splith", cmd_splith }, |
191 | { "splitt", cmd_splitt }, | 191 | { "splitt", cmd_splitt }, |
192 | { "splitv", cmd_splitv }, | 192 | { "splitv", cmd_splitv }, |
193 | { "sticky", cmd_sticky }, | ||
193 | { "swap", cmd_swap }, | 194 | { "swap", cmd_swap }, |
194 | { "title_format", cmd_title_format }, | 195 | { "title_format", cmd_title_format }, |
195 | { "unmark", cmd_unmark }, | 196 | { "unmark", cmd_unmark }, |
diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 9e0be9d0..38a4e1da 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c | |||
@@ -31,31 +31,10 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
31 | wants_floating = !container->is_floating; | 31 | wants_floating = !container->is_floating; |
32 | } else { | 32 | } else { |
33 | return cmd_results_new(CMD_FAILURE, "floating", | 33 | return cmd_results_new(CMD_FAILURE, "floating", |
34 | "Expected 'floating <enable|disable|toggle>"); | 34 | "Expected 'floating <enable|disable|toggle>'"); |
35 | } | 35 | } |
36 | 36 | ||
37 | // Change from tiled to floating | 37 | container_set_floating(container, wants_floating); |
38 | if (!container->is_floating && wants_floating) { | ||
39 | struct sway_container *workspace = container_parent( | ||
40 | container, C_WORKSPACE); | ||
41 | container_remove_child(container); | ||
42 | container_add_floating(workspace, container); | ||
43 | |||
44 | struct sway_output *output = workspace->parent->sway_output; | ||
45 | output_damage_whole_container(output, container); | ||
46 | // Reset to sane size and position | ||
47 | container->width = 640; | ||
48 | container->height = 480; | ||
49 | container->x = workspace->width / 2 - container->width / 2; | ||
50 | container->y = workspace->height / 2 - container->height / 2; | ||
51 | view_autoconfigure(container->sway_view); | ||
52 | output_damage_whole_container(output, container); | ||
53 | |||
54 | seat_set_focus(config->handler_context.seat, container); | ||
55 | arrange_workspace(workspace); | ||
56 | } else if (container->is_floating && !wants_floating) { | ||
57 | // TODO | ||
58 | } | ||
59 | 38 | ||
60 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 39 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
61 | } | 40 | } |
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c new file mode 100644 index 00000000..4bb4bd39 --- /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) { | ||
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/criteria.c b/sway/criteria.c index dec5fed7..e97b12f8 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 (!view->swayc->is_floating) { |
125 | return false; | 125 | return false; |
126 | } | ||
126 | } | 127 | } |
127 | 128 | ||
128 | if (criteria->tiling) { | 129 | if (criteria->tiling) { |
129 | // TODO | 130 | if (view->swayc->is_floating) { |
131 | return false; | ||
132 | } | ||
130 | } | 133 | } |
131 | 134 | ||
132 | if (criteria->urgent) { | 135 | if (criteria->urgent) { |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 95479819..1d21e80f 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -754,9 +754,87 @@ static void render_container(struct sway_output *output, | |||
754 | case L_TABBED: | 754 | case L_TABBED: |
755 | render_container_tabbed(output, damage, con, parent_focused); | 755 | render_container_tabbed(output, damage, con, parent_focused); |
756 | break; | 756 | break; |
757 | case L_FLOATING: | 757 | } |
758 | // TODO | 758 | } |
759 | break; | 759 | |
760 | static bool floater_intersects_output(struct sway_container *floater, | ||
761 | struct sway_container *output) { | ||
762 | struct wlr_box box = { | ||
763 | .x = floater->x, | ||
764 | .y = floater->y, | ||
765 | .width = floater->width, | ||
766 | .height = floater->height, | ||
767 | }; | ||
768 | return wlr_output_layout_intersects(root_container.sway_root->output_layout, | ||
769 | output->sway_output->wlr_output, &box); | ||
770 | } | ||
771 | |||
772 | static void container_translate(struct sway_container *con, int x, int y) { | ||
773 | con->x += x; | ||
774 | con->y += y; | ||
775 | if (con->type == C_VIEW) { | ||
776 | con->sway_view->x += x; | ||
777 | con->sway_view->y += y; | ||
778 | } else { | ||
779 | for (int i = 0; i < con->children->length; ++i) { | ||
780 | struct sway_container *child = con->children->items[i]; | ||
781 | container_translate(child, x, y); | ||
782 | } | ||
783 | } | ||
784 | } | ||
785 | |||
786 | static void render_floating_container(struct sway_output *soutput, | ||
787 | pixman_region32_t *damage, struct sway_container *con) { | ||
788 | // We need to translate the floating container's coordinates from layout | ||
789 | // coordinates into output-local coordinates. This needs to happen for all | ||
790 | // children of the floating container too. | ||
791 | struct sway_container *output = container_parent(con, C_OUTPUT); | ||
792 | container_translate(con, -output->x, -output->y); | ||
793 | |||
794 | if (con->type == C_VIEW) { | ||
795 | struct sway_view *view = con->sway_view; | ||
796 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
797 | struct sway_container *focus = seat_get_focus(seat); | ||
798 | struct border_colors *colors; | ||
799 | struct wlr_texture *title_texture; | ||
800 | struct wlr_texture *marks_texture; | ||
801 | |||
802 | if (focus == con) { | ||
803 | colors = &config->border_colors.focused; | ||
804 | title_texture = con->title_focused; | ||
805 | marks_texture = view->marks_focused; | ||
806 | } else { | ||
807 | colors = &config->border_colors.unfocused; | ||
808 | title_texture = con->title_unfocused; | ||
809 | marks_texture = view->marks_unfocused; | ||
810 | } | ||
811 | render_titlebar(soutput, damage, con, con->x, con->y, con->width, | ||
812 | colors, title_texture, marks_texture); | ||
813 | render_view(soutput, damage, con, colors); | ||
814 | } else { | ||
815 | render_container(soutput, damage, con, false); | ||
816 | } | ||
817 | // Undo the translation | ||
818 | container_translate(con, output->x, output->y); | ||
819 | } | ||
820 | |||
821 | static void render_floating(struct sway_output *soutput, | ||
822 | pixman_region32_t *damage) { | ||
823 | for (int i = 0; i < root_container.children->length; ++i) { | ||
824 | struct sway_container *output = root_container.children->items[i]; | ||
825 | for (int j = 0; j < output->children->length; ++j) { | ||
826 | struct sway_container *workspace = output->children->items[j]; | ||
827 | struct sway_workspace *ws = workspace->sway_workspace; | ||
828 | bool ws_is_visible = workspace_is_visible(workspace); | ||
829 | for (int k = 0; k < ws->floating->children->length; ++k) { | ||
830 | struct sway_container *floater = | ||
831 | ws->floating->children->items[k]; | ||
832 | if ((ws_is_visible || floater->is_sticky) | ||
833 | && floater_intersects_output(floater, soutput->swayc)) { | ||
834 | render_floating_container(soutput, damage, floater); | ||
835 | } | ||
836 | } | ||
837 | } | ||
760 | } | 838 | } |
761 | } | 839 | } |
762 | 840 | ||
@@ -794,8 +872,6 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
794 | goto renderer_end; | 872 | goto renderer_end; |
795 | } | 873 | } |
796 | 874 | ||
797 | //wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | ||
798 | |||
799 | struct sway_container *workspace = output_get_active_workspace(output); | 875 | struct sway_container *workspace = output_get_active_workspace(output); |
800 | 876 | ||
801 | if (workspace->sway_workspace->fullscreen) { | 877 | if (workspace->sway_workspace->fullscreen) { |
@@ -818,7 +894,6 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
818 | } | 894 | } |
819 | } else { | 895 | } else { |
820 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; | 896 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; |
821 | wlr_renderer_clear(renderer, clear_color); | ||
822 | 897 | ||
823 | int nrects; | 898 | int nrects; |
824 | pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); | 899 | pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); |
@@ -840,6 +915,8 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
840 | &root_container.sway_root->xwayland_unmanaged); | 915 | &root_container.sway_root->xwayland_unmanaged); |
841 | render_layer(output, damage, | 916 | render_layer(output, damage, |
842 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | 917 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); |
918 | |||
919 | render_floating(output, damage); | ||
843 | } | 920 | } |
844 | render_layer(output, damage, | 921 | render_layer(output, damage, |
845 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); | 922 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); |
@@ -916,6 +993,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
916 | 993 | ||
917 | struct sway_container *workspace = output_get_active_workspace(output); | 994 | struct sway_container *workspace = output_get_active_workspace(output); |
918 | send_frame_done_container(&data, workspace); | 995 | send_frame_done_container(&data, workspace); |
996 | send_frame_done_container(&data, workspace->sway_workspace->floating); | ||
919 | 997 | ||
920 | send_frame_done_unmanaged(&data, | 998 | send_frame_done_unmanaged(&data, |
921 | &root_container.sway_root->xwayland_unmanaged); | 999 | &root_container.sway_root->xwayland_unmanaged); |
@@ -1037,7 +1115,15 @@ static void output_damage_view(struct sway_output *output, | |||
1037 | 1115 | ||
1038 | void output_damage_from_view(struct sway_output *output, | 1116 | void output_damage_from_view(struct sway_output *output, |
1039 | struct sway_view *view) { | 1117 | struct sway_view *view) { |
1040 | output_damage_view(output, view, false); | 1118 | if (container_self_or_parent_floating(view->swayc)) { |
1119 | view->x -= output->swayc->x; | ||
1120 | view->y -= output->swayc->y; | ||
1121 | output_damage_view(output, view, false); | ||
1122 | view->x += output->swayc->x; | ||
1123 | view->y += output->swayc->y; | ||
1124 | } else { | ||
1125 | output_damage_view(output, view, false); | ||
1126 | } | ||
1041 | } | 1127 | } |
1042 | 1128 | ||
1043 | static void output_damage_whole_container_iterator(struct sway_container *con, | 1129 | static void output_damage_whole_container_iterator(struct sway_container *con, |
@@ -1053,13 +1139,17 @@ static void output_damage_whole_container_iterator(struct sway_container *con, | |||
1053 | 1139 | ||
1054 | void output_damage_whole_container(struct sway_output *output, | 1140 | void output_damage_whole_container(struct sway_output *output, |
1055 | struct sway_container *con) { | 1141 | struct sway_container *con) { |
1056 | float scale = output->wlr_output->scale; | ||
1057 | struct wlr_box box = { | 1142 | struct wlr_box box = { |
1058 | .x = con->x * scale, | 1143 | .x = con->x, |
1059 | .y = con->y * scale, | 1144 | .y = con->y, |
1060 | .width = con->width * scale, | 1145 | .width = con->width, |
1061 | .height = con->height * scale, | 1146 | .height = con->height, |
1062 | }; | 1147 | }; |
1148 | if (con->is_floating) { | ||
1149 | box.x -= output->wlr_output->lx; | ||
1150 | box.y -= output->wlr_output->ly; | ||
1151 | } | ||
1152 | scale_box(&box, output->wlr_output->scale); | ||
1063 | wlr_output_damage_add_box(output->damage, &box); | 1153 | wlr_output_damage_add_box(output->damage, &box); |
1064 | 1154 | ||
1065 | if (con->type == C_VIEW) { | 1155 | if (con->type == C_VIEW) { |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index b2b95fa0..e1a73b20 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -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, ox, oy); | ||
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) { |
@@ -110,6 +111,14 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
110 | } | 111 | } |
111 | } | 112 | } |
112 | 113 | ||
114 | static void set_maximized(struct sway_view *view, bool maximized) { | ||
115 | if (xdg_shell_view_from_view(view) == NULL) { | ||
116 | return; | ||
117 | } | ||
118 | struct wlr_xdg_surface *surface = view->wlr_xdg_surface; | ||
119 | wlr_xdg_toplevel_set_maximized(surface, maximized); | ||
120 | } | ||
121 | |||
113 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { | 122 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { |
114 | if (xdg_shell_view_from_view(view) == NULL) { | 123 | if (xdg_shell_view_from_view(view) == NULL) { |
115 | return; | 124 | return; |
@@ -118,6 +127,11 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { | |||
118 | wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); | 127 | wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); |
119 | } | 128 | } |
120 | 129 | ||
130 | static bool wants_floating(struct sway_view *view) { | ||
131 | // TODO | ||
132 | return false; | ||
133 | } | ||
134 | |||
121 | static void for_each_surface(struct sway_view *view, | 135 | static void for_each_surface(struct sway_view *view, |
122 | wlr_surface_iterator_func_t iterator, void *user_data) { | 136 | wlr_surface_iterator_func_t iterator, void *user_data) { |
123 | if (xdg_shell_view_from_view(view) == NULL) { | 137 | if (xdg_shell_view_from_view(view) == NULL) { |
@@ -154,7 +168,9 @@ static const struct sway_view_impl view_impl = { | |||
154 | .get_string_prop = get_string_prop, | 168 | .get_string_prop = get_string_prop, |
155 | .configure = configure, | 169 | .configure = configure, |
156 | .set_activated = set_activated, | 170 | .set_activated = set_activated, |
171 | .set_maximized = set_maximized, | ||
157 | .set_fullscreen = set_fullscreen, | 172 | .set_fullscreen = set_fullscreen, |
173 | .wants_floating = wants_floating, | ||
158 | .for_each_surface = for_each_surface, | 174 | .for_each_surface = for_each_surface, |
159 | .close = _close, | 175 | .close = _close, |
160 | .destroy = destroy, | 176 | .destroy = destroy, |
@@ -164,11 +180,17 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
164 | struct sway_xdg_shell_view *xdg_shell_view = | 180 | struct sway_xdg_shell_view *xdg_shell_view = |
165 | wl_container_of(listener, xdg_shell_view, commit); | 181 | wl_container_of(listener, xdg_shell_view, commit); |
166 | struct sway_view *view = &xdg_shell_view->view; | 182 | struct sway_view *view = &xdg_shell_view->view; |
167 | // NOTE: We intentionally discard the view's desired width here | 183 | struct wlr_box *geometry = &view->wlr_xdg_surface->geometry; |
168 | // TODO: Store this for restoration when moving to floating plane | 184 | if (!view->natural_width && !view->natural_height) { |
169 | // TODO: Let floating views do whatever | 185 | view->natural_width = geometry->width; |
170 | view_update_size(view, xdg_shell_view->pending_width, | 186 | view->natural_height = geometry->height; |
171 | xdg_shell_view->pending_height); | 187 | } |
188 | if (view->swayc && view->swayc->is_floating) { | ||
189 | view_update_size(view, geometry->width, geometry->height); | ||
190 | } else { | ||
191 | view_update_size(view, xdg_shell_view->pending_width, | ||
192 | xdg_shell_view->pending_height); | ||
193 | } | ||
172 | view_update_title(view, false); | 194 | view_update_title(view, false); |
173 | view_damage_from(view); | 195 | view_damage_from(view); |
174 | } | 196 | } |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index d098c797..47e4162a 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -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, ox, oy); | ||
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) { |
@@ -109,6 +110,14 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
109 | } | 110 | } |
110 | } | 111 | } |
111 | 112 | ||
113 | static void set_maximized(struct sway_view *view, bool maximized) { | ||
114 | if (xdg_shell_v6_view_from_view(view) == NULL) { | ||
115 | return; | ||
116 | } | ||
117 | struct wlr_xdg_surface_v6 *surface = view->wlr_xdg_surface_v6; | ||
118 | wlr_xdg_toplevel_v6_set_maximized(surface, maximized); | ||
119 | } | ||
120 | |||
112 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { | 121 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { |
113 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 122 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
114 | return; | 123 | return; |
@@ -117,6 +126,11 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { | |||
117 | wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen); | 126 | wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen); |
118 | } | 127 | } |
119 | 128 | ||
129 | static bool wants_floating(struct sway_view *view) { | ||
130 | // TODO | ||
131 | return false; | ||
132 | } | ||
133 | |||
120 | static void for_each_surface(struct sway_view *view, | 134 | static void for_each_surface(struct sway_view *view, |
121 | wlr_surface_iterator_func_t iterator, void *user_data) { | 135 | wlr_surface_iterator_func_t iterator, void *user_data) { |
122 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 136 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
@@ -153,7 +167,9 @@ static const struct sway_view_impl view_impl = { | |||
153 | .get_string_prop = get_string_prop, | 167 | .get_string_prop = get_string_prop, |
154 | .configure = configure, | 168 | .configure = configure, |
155 | .set_activated = set_activated, | 169 | .set_activated = set_activated, |
170 | .set_maximized = set_maximized, | ||
156 | .set_fullscreen = set_fullscreen, | 171 | .set_fullscreen = set_fullscreen, |
172 | .wants_floating = wants_floating, | ||
157 | .for_each_surface = for_each_surface, | 173 | .for_each_surface = for_each_surface, |
158 | .close = _close, | 174 | .close = _close, |
159 | .destroy = destroy, | 175 | .destroy = destroy, |
@@ -163,11 +179,17 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
163 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | 179 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = |
164 | wl_container_of(listener, xdg_shell_v6_view, commit); | 180 | wl_container_of(listener, xdg_shell_v6_view, commit); |
165 | struct sway_view *view = &xdg_shell_v6_view->view; | 181 | struct sway_view *view = &xdg_shell_v6_view->view; |
166 | // NOTE: We intentionally discard the view's desired width here | 182 | struct wlr_box *geometry = &view->wlr_xdg_surface_v6->geometry; |
167 | // TODO: Store this for restoration when moving to floating plane | 183 | if (!view->natural_width && !view->natural_height) { |
168 | // TODO: Let floating views do whatever | 184 | view->natural_width = geometry->width; |
169 | view_update_size(view, xdg_shell_v6_view->pending_width, | 185 | view->natural_height = geometry->height; |
170 | xdg_shell_v6_view->pending_height); | 186 | } |
187 | if (view->swayc && view->swayc->is_floating) { | ||
188 | view_update_size(view, geometry->width, geometry->height); | ||
189 | } else { | ||
190 | view_update_size(view, xdg_shell_v6_view->pending_width, | ||
191 | xdg_shell_v6_view->pending_height); | ||
192 | } | ||
171 | view_update_title(view, false); | 193 | view_update_title(view, false); |
172 | view_damage_from(view); | 194 | view_damage_from(view); |
173 | } | 195 | } |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 6a99a66a..56cac1bd 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -152,7 +152,9 @@ 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 | // The x and y arguments are output-local for tiled views, and layout |
156 | // coordinates for floating views. | ||
157 | static void configure(struct sway_view *view, double x, double y, int width, | ||
156 | int height) { | 158 | int height) { |
157 | struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); | 159 | struct sway_xwayland_view *xwayland_view = xwayland_view_from_view(view); |
158 | if (xwayland_view == NULL) { | 160 | if (xwayland_view == NULL) { |
@@ -160,25 +162,33 @@ static void configure(struct sway_view *view, double ox, double oy, int width, | |||
160 | } | 162 | } |
161 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 163 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
162 | 164 | ||
163 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 165 | double lx, ly; |
164 | if (!sway_assert(output, "view must be within tree to set position")) { | 166 | if (view->swayc->is_floating) { |
165 | return; | 167 | lx = x; |
166 | } | 168 | ly = y; |
167 | struct sway_container *root = container_parent(output, C_ROOT); | 169 | } else { |
168 | if (!sway_assert(root, "output must be within tree to set position")) { | 170 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); |
169 | return; | 171 | if (!sway_assert(output, "view must be within tree to set position")) { |
170 | } | 172 | return; |
171 | struct wlr_output_layout *layout = root->sway_root->output_layout; | 173 | } |
172 | struct wlr_output_layout_output *loutput = | 174 | struct sway_container *root = container_parent(output, C_ROOT); |
173 | wlr_output_layout_get(layout, output->sway_output->wlr_output); | 175 | if (!sway_assert(root, "output must be within tree to set position")) { |
174 | if (!sway_assert(loutput, "output must be within layout to set position")) { | 176 | return; |
175 | return; | 177 | } |
178 | struct wlr_output_layout *layout = root->sway_root->output_layout; | ||
179 | struct wlr_output_layout_output *loutput = | ||
180 | wlr_output_layout_get(layout, output->sway_output->wlr_output); | ||
181 | if (!sway_assert(loutput, | ||
182 | "output must be within layout to set position")) { | ||
183 | return; | ||
184 | } | ||
185 | lx = x + loutput->x; | ||
186 | ly = y + loutput->y; | ||
176 | } | 187 | } |
177 | 188 | ||
178 | xwayland_view->pending_width = width; | 189 | xwayland_view->pending_width = width; |
179 | xwayland_view->pending_height = height; | 190 | xwayland_view->pending_height = height; |
180 | wlr_xwayland_surface_configure(xsurface, ox + loutput->x, oy + loutput->y, | 191 | wlr_xwayland_surface_configure(xsurface, lx, ly, width, height); |
181 | width, height); | ||
182 | } | 192 | } |
183 | 193 | ||
184 | static void set_activated(struct sway_view *view, bool activated) { | 194 | static void set_activated(struct sway_view *view, bool activated) { |
@@ -189,6 +199,14 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
189 | wlr_xwayland_surface_activate(surface, activated); | 199 | wlr_xwayland_surface_activate(surface, activated); |
190 | } | 200 | } |
191 | 201 | ||
202 | static void set_maximized(struct sway_view *view, bool maximized) { | ||
203 | if (xwayland_view_from_view(view) == NULL) { | ||
204 | return; | ||
205 | } | ||
206 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; | ||
207 | wlr_xwayland_surface_set_maximized(surface, maximized); | ||
208 | } | ||
209 | |||
192 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { | 210 | static void set_fullscreen(struct sway_view *view, bool fullscreen) { |
193 | if (xwayland_view_from_view(view) == NULL) { | 211 | if (xwayland_view_from_view(view) == NULL) { |
194 | return; | 212 | return; |
@@ -197,6 +215,35 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) { | |||
197 | wlr_xwayland_surface_set_fullscreen(surface, fullscreen); | 215 | wlr_xwayland_surface_set_fullscreen(surface, fullscreen); |
198 | } | 216 | } |
199 | 217 | ||
218 | static bool wants_floating(struct sway_view *view) { | ||
219 | // TODO: | ||
220 | // We want to return true if the window type contains any of these: | ||
221 | // NET_WM_WINDOW_TYPE_DIALOG | ||
222 | // NET_WM_WINDOW_TYPE_UTILITY | ||
223 | // NET_WM_WINDOW_TYPE_TOOLBAR | ||
224 | // NET_WM_WINDOW_TYPE_SPLASH | ||
225 | // | ||
226 | // We also want to return true if the NET_WM_STATE is MODAL. | ||
227 | // wlroots doesn't appear to provide all this information at the moment. | ||
228 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | ||
229 | uint32_t *atom = xsurface->window_type; | ||
230 | for (size_t i = 0; i < xsurface->window_type_len; ++i) { | ||
231 | wlr_log(L_DEBUG, "xwayland window type %i", *atom); | ||
232 | // TODO: Come up with a better way of doing this | ||
233 | switch (*atom) { | ||
234 | case 36: // NET_WM_WINDOW_TYPE_UTILITY | ||
235 | case 44: // NET_WM_WINDOW_TYPE_SPLASH | ||
236 | case 276: // ? PGP passphrase dialog | ||
237 | case 337: // ? Firefox open file dialog | ||
238 | case 338: // ? Firefox open file dialog | ||
239 | return true; | ||
240 | } | ||
241 | ++atom; | ||
242 | } | ||
243 | |||
244 | return false; | ||
245 | } | ||
246 | |||
200 | static void _close(struct sway_view *view) { | 247 | static void _close(struct sway_view *view) { |
201 | if (xwayland_view_from_view(view) == NULL) { | 248 | if (xwayland_view_from_view(view) == NULL) { |
202 | return; | 249 | return; |
@@ -225,7 +272,9 @@ static const struct sway_view_impl view_impl = { | |||
225 | .get_int_prop = get_int_prop, | 272 | .get_int_prop = get_int_prop, |
226 | .configure = configure, | 273 | .configure = configure, |
227 | .set_activated = set_activated, | 274 | .set_activated = set_activated, |
275 | .set_maximized = set_maximized, | ||
228 | .set_fullscreen = set_fullscreen, | 276 | .set_fullscreen = set_fullscreen, |
277 | .wants_floating = wants_floating, | ||
229 | .close = _close, | 278 | .close = _close, |
230 | .destroy = destroy, | 279 | .destroy = destroy, |
231 | }; | 280 | }; |
@@ -234,10 +283,18 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
234 | struct sway_xwayland_view *xwayland_view = | 283 | struct sway_xwayland_view *xwayland_view = |
235 | wl_container_of(listener, xwayland_view, commit); | 284 | wl_container_of(listener, xwayland_view, commit); |
236 | struct sway_view *view = &xwayland_view->view; | 285 | struct sway_view *view = &xwayland_view->view; |
237 | // NOTE: We intentionally discard the view's desired width here | 286 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
238 | // TODO: Let floating views do whatever | 287 | if (!view->natural_width && !view->natural_height) { |
239 | view_update_size(view, xwayland_view->pending_width, | 288 | view->natural_width = xsurface->width; |
240 | xwayland_view->pending_height); | 289 | view->natural_height = xsurface->height; |
290 | } | ||
291 | if (view->swayc && view->swayc->is_floating) { | ||
292 | view_update_size(view, xsurface->width, xsurface->height); | ||
293 | view_update_position(view, xsurface->x, xsurface->y); | ||
294 | } else { | ||
295 | view_update_size(view, xwayland_view->pending_width, | ||
296 | xwayland_view->pending_height); | ||
297 | } | ||
241 | view_damage_from(view); | 298 | view_damage_from(view); |
242 | } | 299 | } |
243 | 300 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 6751931d..96bf574c 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -108,6 +108,9 @@ static struct sway_container *container_at_coords( | |||
108 | } | 108 | } |
109 | 109 | ||
110 | struct sway_container *c; | 110 | struct sway_container *c; |
111 | if ((c = floating_container_at(x, y, surface, sx, sy))) { | ||
112 | return c; | ||
113 | } | ||
111 | if ((c = container_at(ws, ox, oy, surface, sx, sy))) { | 114 | if ((c = container_at(ws, ox, oy, surface, sx, sy))) { |
112 | return c; | 115 | return c; |
113 | } | 116 | } |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 0295212c..6a266fba 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 | } |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index da4bef60..4d7024a8 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" |
@@ -150,6 +151,15 @@ static void ipc_json_describe_workspace(struct sway_container *workspace, | |||
150 | 151 | ||
151 | const char *layout = ipc_json_layout_description(workspace->layout); | 152 | const char *layout = ipc_json_layout_description(workspace->layout); |
152 | json_object_object_add(object, "layout", json_object_new_string(layout)); | 153 | json_object_object_add(object, "layout", json_object_new_string(layout)); |
154 | |||
155 | // Floating | ||
156 | json_object *floating_array = json_object_new_array(); | ||
157 | struct sway_container *floating = workspace->sway_workspace->floating; | ||
158 | for (int i = 0; i < floating->children->length; ++i) { | ||
159 | struct sway_container *floater = floating->children->items[i]; | ||
160 | json_object_array_add(floating_array, ipc_json_describe_container_recursive(floater)); | ||
161 | } | ||
162 | json_object_object_add(object, "floating_nodes", floating_array); | ||
153 | } | 163 | } |
154 | 164 | ||
155 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { | 165 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { |
diff --git a/sway/meson.build b/sway/meson.build index 5618a257..4c038583 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -65,6 +65,7 @@ sway_sources = files( | |||
65 | 'commands/set.c', | 65 | 'commands/set.c', |
66 | 'commands/show_marks.c', | 66 | 'commands/show_marks.c', |
67 | 'commands/split.c', | 67 | 'commands/split.c', |
68 | 'commands/sticky.c', | ||
68 | 'commands/swaybg_command.c', | 69 | 'commands/swaybg_command.c', |
69 | 'commands/swap.c', | 70 | 'commands/swap.c', |
70 | 'commands/title_format.c', | 71 | 'commands/title_format.c', |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index bdef56ea..da4f7889 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -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..f9a0474c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -123,6 +123,7 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
123 | c->layout = L_NONE; | 123 | c->layout = L_NONE; |
124 | c->type = type; | 124 | c->type = type; |
125 | c->alpha = 1.0f; | 125 | c->alpha = 1.0f; |
126 | c->reapable = true; | ||
126 | 127 | ||
127 | if (type != C_VIEW) { | 128 | if (type != C_VIEW) { |
128 | c->children = create_list(); | 129 | c->children = create_list(); |
@@ -189,14 +190,13 @@ static struct sway_container *container_workspace_destroy( | |||
189 | } | 190 | } |
190 | 191 | ||
191 | struct sway_container *parent = workspace->parent; | 192 | struct sway_container *parent = workspace->parent; |
192 | if (workspace->children->length == 0) { | 193 | if (workspace_is_empty(workspace)) { |
193 | // destroy the WS if there are no children (TODO check for floating) | 194 | // destroy the WS if there are no children |
194 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); | 195 | wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); |
195 | ipc_event_workspace(workspace, NULL, "empty"); | 196 | ipc_event_workspace(workspace, NULL, "empty"); |
196 | } else if (output) { | 197 | } else if (output) { |
197 | // Move children to a different workspace on this output | 198 | // Move children to a different workspace on this output |
198 | struct sway_container *new_workspace = NULL; | 199 | struct sway_container *new_workspace = NULL; |
199 | // TODO move floating | ||
200 | for (int i = 0; i < output->children->length; i++) { | 200 | for (int i = 0; i < output->children->length; i++) { |
201 | if (output->children->items[i] != workspace) { | 201 | if (output->children->items[i] != workspace) { |
202 | new_workspace = output->children->items[i]; | 202 | new_workspace = output->children->items[i]; |
@@ -209,6 +209,11 @@ static struct sway_container *container_workspace_destroy( | |||
209 | for (int i = 0; i < workspace->children->length; i++) { | 209 | for (int i = 0; i < workspace->children->length; i++) { |
210 | container_move_to(workspace->children->items[i], new_workspace); | 210 | container_move_to(workspace->children->items[i], new_workspace); |
211 | } | 211 | } |
212 | struct sway_container *floating = workspace->sway_workspace->floating; | ||
213 | for (int i = 0; i < floating->children->length; i++) { | ||
214 | container_move_to(floating->children->items[i], | ||
215 | new_workspace->sway_workspace->floating); | ||
216 | } | ||
212 | } | 217 | } |
213 | 218 | ||
214 | free(workspace->sway_workspace); | 219 | free(workspace->sway_workspace); |
@@ -275,13 +280,16 @@ static void container_root_finish(struct sway_container *con) { | |||
275 | } | 280 | } |
276 | 281 | ||
277 | bool container_reap_empty(struct sway_container *con) { | 282 | bool container_reap_empty(struct sway_container *con) { |
283 | if (!con->reapable) { | ||
284 | return false; | ||
285 | } | ||
278 | switch (con->type) { | 286 | switch (con->type) { |
279 | case C_ROOT: | 287 | case C_ROOT: |
280 | case C_OUTPUT: | 288 | case C_OUTPUT: |
281 | // dont reap these | 289 | // dont reap these |
282 | break; | 290 | break; |
283 | case C_WORKSPACE: | 291 | case C_WORKSPACE: |
284 | if (!workspace_is_visible(con) && con->children->length == 0) { | 292 | if (!workspace_is_visible(con) && workspace_is_empty(con)) { |
285 | wlr_log(L_DEBUG, "Destroying workspace via reaper"); | 293 | wlr_log(L_DEBUG, "Destroying workspace via reaper"); |
286 | container_workspace_destroy(con); | 294 | container_workspace_destroy(con); |
287 | return true; | 295 | return true; |
@@ -436,7 +444,6 @@ struct sway_container *container_find(struct sway_container *container, | |||
436 | if (!container->children) { | 444 | if (!container->children) { |
437 | return NULL; | 445 | return NULL; |
438 | } | 446 | } |
439 | // TODO: floating windows | ||
440 | for (int i = 0; i < container->children->length; ++i) { | 447 | for (int i = 0; i < container->children->length; ++i) { |
441 | struct sway_container *child = container->children->items[i]; | 448 | struct sway_container *child = container->children->items[i]; |
442 | if (test(child, data)) { | 449 | if (test(child, data)) { |
@@ -448,6 +455,9 @@ struct sway_container *container_find(struct sway_container *container, | |||
448 | } | 455 | } |
449 | } | 456 | } |
450 | } | 457 | } |
458 | if (container->type == C_WORKSPACE) { | ||
459 | return container_find(container->sway_workspace->floating, test, data); | ||
460 | } | ||
451 | return NULL; | 461 | return NULL; |
452 | } | 462 | } |
453 | 463 | ||
@@ -608,8 +618,6 @@ struct sway_container *container_at(struct sway_container *parent, | |||
608 | return container_at_tabbed(parent, ox, oy, surface, sx, sy); | 618 | return container_at_tabbed(parent, ox, oy, surface, sx, sy); |
609 | case L_STACKED: | 619 | case L_STACKED: |
610 | return container_at_stacked(parent, ox, oy, surface, sx, sy); | 620 | return container_at_stacked(parent, ox, oy, surface, sx, sy); |
611 | case L_FLOATING: | ||
612 | return NULL; // TODO | ||
613 | case L_NONE: | 621 | case L_NONE: |
614 | return NULL; | 622 | return NULL; |
615 | } | 623 | } |
@@ -617,6 +625,34 @@ struct sway_container *container_at(struct sway_container *parent, | |||
617 | return NULL; | 625 | return NULL; |
618 | } | 626 | } |
619 | 627 | ||
628 | struct sway_container *floating_container_at(double lx, double ly, | ||
629 | struct wlr_surface **surface, double *sx, double *sy) { | ||
630 | for (int i = 0; i < root_container.children->length; ++i) { | ||
631 | struct sway_container *output = root_container.children->items[i]; | ||
632 | for (int j = 0; j < output->children->length; ++j) { | ||
633 | struct sway_container *workspace = output->children->items[j]; | ||
634 | struct sway_workspace *ws = workspace->sway_workspace; | ||
635 | bool ws_is_visible = workspace_is_visible(workspace); | ||
636 | for (int k = 0; k < ws->floating->children->length; ++k) { | ||
637 | struct sway_container *floater = | ||
638 | ws->floating->children->items[k]; | ||
639 | if (ws_is_visible || floater->is_sticky) { | ||
640 | struct wlr_box box = { | ||
641 | .x = floater->x, | ||
642 | .y = floater->y, | ||
643 | .width = floater->width, | ||
644 | .height = floater->height, | ||
645 | }; | ||
646 | if (wlr_box_contains_point(&box, lx, ly)) { | ||
647 | return container_at(floater, lx, ly, surface, sx, sy); | ||
648 | } | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | } | ||
653 | return NULL; | ||
654 | } | ||
655 | |||
620 | void container_for_each_descendant_dfs(struct sway_container *container, | 656 | void container_for_each_descendant_dfs(struct sway_container *container, |
621 | void (*f)(struct sway_container *container, void *data), | 657 | void (*f)(struct sway_container *container, void *data), |
622 | void *data) { | 658 | void *data) { |
@@ -674,7 +710,7 @@ static bool find_child_func(struct sway_container *con, void *data) { | |||
674 | 710 | ||
675 | bool container_has_child(struct sway_container *con, | 711 | bool container_has_child(struct sway_container *con, |
676 | struct sway_container *child) { | 712 | struct sway_container *child) { |
677 | if (con == NULL || con->type == C_VIEW || con->children->length == 0) { | 713 | if (con == NULL || con->type == C_VIEW) { |
678 | return false; | 714 | return false; |
679 | } | 715 | } |
680 | return container_find(con, find_child_func, child); | 716 | return container_find(con, find_child_func, child); |
@@ -806,9 +842,6 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe | |||
806 | case L_STACKED: | 842 | case L_STACKED: |
807 | lenient_strcat(buffer, "S["); | 843 | lenient_strcat(buffer, "S["); |
808 | break; | 844 | break; |
809 | case L_FLOATING: | ||
810 | lenient_strcat(buffer, "F["); | ||
811 | break; | ||
812 | case L_NONE: | 845 | case L_NONE: |
813 | lenient_strcat(buffer, "D["); | 846 | lenient_strcat(buffer, "D["); |
814 | break; | 847 | break; |
@@ -866,3 +899,81 @@ void container_notify_subtree_changed(struct sway_container *container) { | |||
866 | size_t container_titlebar_height() { | 899 | size_t container_titlebar_height() { |
867 | return config->font_height + TITLEBAR_V_PADDING * 2; | 900 | return config->font_height + TITLEBAR_V_PADDING * 2; |
868 | } | 901 | } |
902 | |||
903 | static void configure_floating_view(struct sway_view *view) { | ||
904 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | ||
905 | int max_width = ws->width * 0.6666; | ||
906 | int max_height = ws->height * 0.6666; | ||
907 | int width = | ||
908 | view->natural_width > max_width ? max_width : view->natural_width; | ||
909 | int height = | ||
910 | view->natural_height > max_height ? max_height : view->natural_height; | ||
911 | struct sway_container *output = ws->parent; | ||
912 | int lx = output->x + (ws->width - width) / 2; | ||
913 | int ly = output->y + (ws->height - height) / 2; | ||
914 | |||
915 | view->border_left = view->border_right = view->border_bottom = true; | ||
916 | view_set_maximized(view, false); | ||
917 | view_configure(view, lx, ly, width, height); | ||
918 | } | ||
919 | |||
920 | void container_set_floating(struct sway_container *container, bool enable) { | ||
921 | if (container->is_floating == enable) { | ||
922 | return; | ||
923 | } | ||
924 | |||
925 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | ||
926 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
927 | container_damage_whole(container); | ||
928 | |||
929 | if (enable) { | ||
930 | container_remove_child(container); | ||
931 | container_add_child(workspace->sway_workspace->floating, container); | ||
932 | container->is_floating = true; | ||
933 | if (container->type == C_VIEW) { | ||
934 | configure_floating_view(container->sway_view); | ||
935 | } | ||
936 | seat_set_focus(seat, seat_get_focus_inactive(seat, container)); | ||
937 | container_reap_empty_recursive(workspace); | ||
938 | } else { | ||
939 | // Returning to tiled | ||
940 | container_remove_child(container); | ||
941 | container_add_child(workspace, container); | ||
942 | container->width = container->parent->width; | ||
943 | container->height = container->parent->height; | ||
944 | if (container->type == C_VIEW) { | ||
945 | view_set_maximized(container->sway_view, true); | ||
946 | } | ||
947 | container->is_floating = false; | ||
948 | container->is_sticky = false; | ||
949 | container_reap_empty_recursive(workspace->sway_workspace->floating); | ||
950 | } | ||
951 | arrange_workspace(workspace); | ||
952 | container_damage_whole(container); | ||
953 | } | ||
954 | |||
955 | void container_set_geometry_from_view(struct sway_container *container) { | ||
956 | if (!sway_assert(container->type == C_VIEW, "Expected a view")) { | ||
957 | return; | ||
958 | } | ||
959 | if (!sway_assert(container->is_floating, "Expected a floating view")) { | ||
960 | return; | ||
961 | } | ||
962 | struct sway_view *view = container->sway_view; | ||
963 | size_t border_width = view->border_thickness * (view->border != B_NONE); | ||
964 | size_t top = | ||
965 | view->border == B_NORMAL ? container_titlebar_height() : border_width; | ||
966 | |||
967 | container->x = view->x - border_width; | ||
968 | container->y = view->y - top; | ||
969 | container->width = view->width + border_width * 2; | ||
970 | container->height = top + view->height + border_width; | ||
971 | } | ||
972 | |||
973 | bool container_self_or_parent_floating(struct sway_container *container) { | ||
974 | while (container->parent->type != C_WORKSPACE | ||
975 | && container->parent->parent->type != C_WORKSPACE) { | ||
976 | container = container->parent; | ||
977 | } | ||
978 | return container->is_floating; | ||
979 | } | ||
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 7bbeb4b1..59ad0b53 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, |
@@ -142,26 +136,11 @@ struct sway_container *container_remove_child(struct sway_container *child) { | |||
142 | } | 136 | } |
143 | 137 | ||
144 | struct sway_container *parent = child->parent; | 138 | struct sway_container *parent = child->parent; |
145 | if (!child->is_floating) { | 139 | for (int i = 0; i < parent->children->length; ++i) { |
146 | for (int i = 0; i < parent->children->length; ++i) { | 140 | if (parent->children->items[i] == child) { |
147 | if (parent->children->items[i] == child) { | 141 | list_del(parent->children, i); |
148 | list_del(parent->children, i); | 142 | break; |
149 | break; | ||
150 | } | ||
151 | } | ||
152 | } else { | ||
153 | if (!sway_assert(parent->type == C_WORKSPACE && child->type == C_VIEW, | ||
154 | "Found floating non-view and/or in non-workspace")) { | ||
155 | return parent; | ||
156 | } | ||
157 | struct sway_workspace *ws = parent->sway_workspace; | ||
158 | for (int i = 0; i < ws->floating->length; ++i) { | ||
159 | if (ws->floating->items[i] == child) { | ||
160 | list_del(ws->floating, i); | ||
161 | break; | ||
162 | } | ||
163 | } | 143 | } |
164 | child->is_floating = false; | ||
165 | } | 144 | } |
166 | child->parent = NULL; | 145 | child->parent = NULL; |
167 | container_notify_subtree_changed(parent); | 146 | container_notify_subtree_changed(parent); |
@@ -169,32 +148,16 @@ struct sway_container *container_remove_child(struct sway_container *child) { | |||
169 | return parent; | 148 | return parent; |
170 | } | 149 | } |
171 | 150 | ||
172 | void container_add_floating(struct sway_container *workspace, | ||
173 | struct sway_container *child) { | ||
174 | if (!sway_assert(workspace->type == C_WORKSPACE && child->type == C_VIEW, | ||
175 | "Attempted to float non-view and/or in non-workspace")) { | ||
176 | return; | ||
177 | } | ||
178 | if (!sway_assert(!child->parent, | ||
179 | "child already has a parent (invalid call)")) { | ||
180 | return; | ||
181 | } | ||
182 | if (!sway_assert(!child->is_floating, | ||
183 | "child is already floating (invalid state)")) { | ||
184 | return; | ||
185 | } | ||
186 | struct sway_workspace *ws = workspace->sway_workspace; | ||
187 | list_add(ws->floating, child); | ||
188 | child->parent = workspace; | ||
189 | child->is_floating = true; | ||
190 | } | ||
191 | |||
192 | void container_move_to(struct sway_container *container, | 151 | void container_move_to(struct sway_container *container, |
193 | struct sway_container *destination) { | 152 | struct sway_container *destination) { |
194 | if (container == destination | 153 | if (container == destination |
195 | || container_has_ancestor(container, destination)) { | 154 | || container_has_ancestor(container, destination)) { |
196 | return; | 155 | return; |
197 | } | 156 | } |
157 | if (container->is_floating) { | ||
158 | // TODO | ||
159 | return; | ||
160 | } | ||
198 | struct sway_container *old_parent = container_remove_child(container); | 161 | struct sway_container *old_parent = container_remove_child(container); |
199 | container->width = container->height = 0; | 162 | container->width = container->height = 0; |
200 | container->saved_width = container->saved_height = 0; | 163 | container->saved_width = container->saved_height = 0; |
@@ -207,8 +170,9 @@ void container_move_to(struct sway_container *container, | |||
207 | } | 170 | } |
208 | wl_signal_emit(&container->events.reparent, old_parent); | 171 | wl_signal_emit(&container->events.reparent, old_parent); |
209 | if (container->type == C_WORKSPACE) { | 172 | if (container->type == C_WORKSPACE) { |
210 | struct sway_seat *seat = input_manager_get_default_seat( | 173 | // If moving a workspace to a new output, maybe create a new workspace |
211 | input_manager); | 174 | // on the previous output |
175 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | ||
212 | if (old_parent->children->length == 0) { | 176 | if (old_parent->children->length == 0) { |
213 | char *ws_name = workspace_next_name(old_parent->name); | 177 | char *ws_name = workspace_next_name(old_parent->name); |
214 | struct sway_container *ws = | 178 | struct sway_container *ws = |
@@ -754,6 +718,10 @@ struct sway_container *container_get_in_direction( | |||
754 | enum movement_direction dir) { | 718 | enum movement_direction dir) { |
755 | struct sway_container *parent = container->parent; | 719 | struct sway_container *parent = container->parent; |
756 | 720 | ||
721 | if (container->is_floating) { | ||
722 | return NULL; | ||
723 | } | ||
724 | |||
757 | if (container->type == C_VIEW && container->sway_view->is_fullscreen) { | 725 | if (container->type == C_VIEW && container->sway_view->is_fullscreen) { |
758 | if (dir == MOVE_PARENT || dir == MOVE_CHILD) { | 726 | if (dir == MOVE_PARENT || dir == MOVE_CHILD) { |
759 | return NULL; | 727 | return NULL; |
@@ -778,6 +746,9 @@ struct sway_container *container_get_in_direction( | |||
778 | bool can_move = false; | 746 | bool can_move = false; |
779 | int desired; | 747 | int desired; |
780 | int idx = index_child(container); | 748 | int idx = index_child(container); |
749 | if (idx == -1) { | ||
750 | return NULL; | ||
751 | } | ||
781 | if (parent->type == C_ROOT) { | 752 | if (parent->type == C_ROOT) { |
782 | enum wlr_direction wlr_dir = 0; | 753 | enum wlr_direction wlr_dir = 0; |
783 | if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), | 754 | if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 26ff1e8d..651a2be6 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -158,21 +158,19 @@ void view_autoconfigure(struct sway_view *view) { | |||
158 | 158 | ||
159 | view->border_top = view->border_bottom = true; | 159 | view->border_top = view->border_bottom = true; |
160 | view->border_left = view->border_right = true; | 160 | view->border_left = view->border_right = true; |
161 | if (view->swayc->layout != L_FLOATING) { | 161 | if (config->hide_edge_borders == E_BOTH |
162 | if (config->hide_edge_borders == E_BOTH | 162 | || config->hide_edge_borders == E_VERTICAL |
163 | || config->hide_edge_borders == E_VERTICAL | 163 | || (config->hide_edge_borders == E_SMART && !other_views)) { |
164 | || (config->hide_edge_borders == E_SMART && !other_views)) { | 164 | view->border_left = view->swayc->x != ws->x; |
165 | view->border_left = view->swayc->x != ws->x; | 165 | int right_x = view->swayc->x + view->swayc->width; |
166 | int right_x = view->swayc->x + view->swayc->width; | 166 | view->border_right = right_x != ws->x + ws->width; |
167 | view->border_right = right_x != ws->x + ws->width; | 167 | } |
168 | } | 168 | if (config->hide_edge_borders == E_BOTH |
169 | if (config->hide_edge_borders == E_BOTH | 169 | || config->hide_edge_borders == E_HORIZONTAL |
170 | || config->hide_edge_borders == E_HORIZONTAL | 170 | || (config->hide_edge_borders == E_SMART && !other_views)) { |
171 | || (config->hide_edge_borders == E_SMART && !other_views)) { | 171 | view->border_top = view->swayc->y != ws->y; |
172 | view->border_top = view->swayc->y != ws->y; | 172 | int bottom_y = view->swayc->y + view->swayc->height; |
173 | int bottom_y = view->swayc->y + view->swayc->height; | 173 | view->border_bottom = bottom_y != ws->y + ws->height; |
174 | view->border_bottom = bottom_y != ws->y + ws->height; | ||
175 | } | ||
176 | } | 174 | } |
177 | 175 | ||
178 | double x, y, width, height; | 176 | double x, y, width, height; |
@@ -184,11 +182,11 @@ void view_autoconfigure(struct sway_view *view) { | |||
184 | // disable any top border because we'll always have the title bar. | 182 | // disable any top border because we'll always have the title bar. |
185 | if (view->swayc->parent->layout == L_TABBED) { | 183 | if (view->swayc->parent->layout == L_TABBED) { |
186 | y_offset = container_titlebar_height(); | 184 | y_offset = container_titlebar_height(); |
187 | view->border_top = 0; | 185 | view->border_top = false; |
188 | } else if (view->swayc->parent->layout == L_STACKED) { | 186 | } else if (view->swayc->parent->layout == L_STACKED) { |
189 | y_offset = container_titlebar_height() | 187 | y_offset = container_titlebar_height() |
190 | * view->swayc->parent->children->length; | 188 | * view->swayc->parent->children->length; |
191 | view->border_top = 0; | 189 | view->border_top = false; |
192 | } | 190 | } |
193 | 191 | ||
194 | switch (view->border) { | 192 | switch (view->border) { |
@@ -237,6 +235,12 @@ void view_set_activated(struct sway_view *view, bool activated) { | |||
237 | } | 235 | } |
238 | } | 236 | } |
239 | 237 | ||
238 | void view_set_maximized(struct sway_view *view, bool maximized) { | ||
239 | if (view->impl->set_maximized) { | ||
240 | view->impl->set_maximized(view, maximized); | ||
241 | } | ||
242 | } | ||
243 | |||
240 | // Set fullscreen, but without IPC events or arranging windows. | 244 | // Set fullscreen, but without IPC events or arranging windows. |
241 | void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { | 245 | void view_set_fullscreen_raw(struct sway_view *view, bool fullscreen) { |
242 | if (view->is_fullscreen == fullscreen) { | 246 | if (view->is_fullscreen == fullscreen) { |
@@ -452,6 +456,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
452 | // TODO: CT_ASSIGN_OUTPUT | 456 | // TODO: CT_ASSIGN_OUTPUT |
453 | } | 457 | } |
454 | } | 458 | } |
459 | // If we're about to launch the view into the floating container, then | ||
460 | // launch it as a tiled view in the root of the workspace instead. | ||
461 | if (focus->is_floating) { | ||
462 | focus = focus->parent->parent; | ||
463 | } | ||
455 | free(criterias); | 464 | free(criterias); |
456 | cont = container_view_create(focus, view); | 465 | cont = container_view_create(focus, view); |
457 | 466 | ||
@@ -468,7 +477,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
468 | wl_signal_add(&view->swayc->events.reparent, &view->container_reparent); | 477 | wl_signal_add(&view->swayc->events.reparent, &view->container_reparent); |
469 | view->container_reparent.notify = view_handle_container_reparent; | 478 | view->container_reparent.notify = view_handle_container_reparent; |
470 | 479 | ||
471 | arrange_children_of(cont->parent); | 480 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { |
481 | container_set_floating(view->swayc, true); | ||
482 | } else { | ||
483 | arrange_children_of(cont->parent); | ||
484 | } | ||
485 | |||
472 | input_manager_set_focus(input_manager, cont); | 486 | input_manager_set_focus(input_manager, cont); |
473 | if (workspace) { | 487 | if (workspace) { |
474 | workspace_switch(workspace); | 488 | workspace_switch(workspace); |
@@ -516,16 +530,14 @@ void view_unmap(struct sway_view *view) { | |||
516 | } | 530 | } |
517 | } | 531 | } |
518 | 532 | ||
519 | void view_update_position(struct sway_view *view, double ox, double oy) { | 533 | void view_update_position(struct sway_view *view, double lx, double ly) { |
520 | if (view->swayc->x == ox && view->swayc->y == oy) { | 534 | if (!view->swayc->is_floating) { |
521 | return; | 535 | return; |
522 | } | 536 | } |
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); | 537 | container_damage_whole(view->swayc); |
527 | view->swayc->x = ox; | 538 | view->x = lx; |
528 | view->swayc->y = oy; | 539 | view->y = ly; |
540 | container_set_geometry_from_view(view->swayc); | ||
529 | container_damage_whole(view->swayc); | 541 | container_damage_whole(view->swayc); |
530 | } | 542 | } |
531 | 543 | ||
@@ -533,15 +545,15 @@ void view_update_size(struct sway_view *view, int width, int height) { | |||
533 | if (view->width == width && view->height == height) { | 545 | if (view->width == width && view->height == height) { |
534 | return; | 546 | return; |
535 | } | 547 | } |
536 | |||
537 | container_damage_whole(view->swayc); | 548 | container_damage_whole(view->swayc); |
538 | // Should we update the swayc width/height here too? | ||
539 | view->width = width; | 549 | view->width = width; |
540 | view->height = height; | 550 | view->height = height; |
551 | if (view->swayc->is_floating) { | ||
552 | container_set_geometry_from_view(view->swayc); | ||
553 | } | ||
541 | container_damage_whole(view->swayc); | 554 | container_damage_whole(view->swayc); |
542 | } | 555 | } |
543 | 556 | ||
544 | |||
545 | static void view_subsurface_create(struct sway_view *view, | 557 | static void view_subsurface_create(struct sway_view *view, |
546 | struct wlr_subsurface *subsurface) { | 558 | struct wlr_subsurface *subsurface) { |
547 | struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); | 559 | struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); |
@@ -888,6 +900,19 @@ bool view_is_visible(struct sway_view *view) { | |||
888 | if (!view->swayc) { | 900 | if (!view->swayc) { |
889 | return false; | 901 | return false; |
890 | } | 902 | } |
903 | struct sway_container *workspace = | ||
904 | container_parent(view->swayc, C_WORKSPACE); | ||
905 | // Determine if view is nested inside a floating container which is sticky. | ||
906 | // A simple floating view will have this ancestry: | ||
907 | // C_VIEW (is_floating=true) -> floating -> workspace | ||
908 | // A more complex ancestry could be: | ||
909 | // C_VIEW -> C_CONTAINER (tabbed and is_floating) -> floating -> workspace | ||
910 | struct sway_container *floater = view->swayc; | ||
911 | while (floater->parent->type != C_WORKSPACE | ||
912 | && floater->parent->parent->type != C_WORKSPACE) { | ||
913 | floater = floater->parent; | ||
914 | } | ||
915 | bool is_sticky = floater->is_floating && floater->is_sticky; | ||
891 | // Check view isn't in a tabbed or stacked container on an inactive tab | 916 | // 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); | 917 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
893 | struct sway_container *container = view->swayc; | 918 | struct sway_container *container = view->swayc; |
@@ -901,10 +926,12 @@ bool view_is_visible(struct sway_view *view) { | |||
901 | container = container->parent; | 926 | container = container->parent; |
902 | } | 927 | } |
903 | // Check view isn't hidden by another fullscreen view | 928 | // Check view isn't hidden by another fullscreen view |
904 | struct sway_container *workspace = container; | ||
905 | if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { | 929 | if (workspace->sway_workspace->fullscreen && !view->is_fullscreen) { |
906 | return false; | 930 | return false; |
907 | } | 931 | } |
908 | // Check the workspace is visible | 932 | // Check the workspace is visible |
909 | return workspace_is_visible(workspace); | 933 | if (!is_sticky) { |
934 | return workspace_is_visible(workspace); | ||
935 | } | ||
936 | return true; | ||
910 | } | 937 | } |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index c4f8ac5e..5bef409a 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -65,7 +65,9 @@ struct sway_container *workspace_create(struct sway_container *output, | |||
65 | return NULL; | 65 | return NULL; |
66 | } | 66 | } |
67 | swayws->swayc = workspace; | 67 | swayws->swayc = workspace; |
68 | swayws->floating = create_list(); | 68 | swayws->floating = container_create(C_CONTAINER); |
69 | swayws->floating->parent = swayws->swayc; | ||
70 | swayws->floating->reapable = false; | ||
69 | workspace->sway_workspace = swayws; | 71 | workspace->sway_workspace = swayws; |
70 | 72 | ||
71 | container_add_child(output, workspace); | 73 | container_add_child(output, workspace); |
@@ -408,3 +410,16 @@ bool workspace_is_visible(struct sway_container *ws) { | |||
408 | } | 410 | } |
409 | return focus == ws; | 411 | return focus == ws; |
410 | } | 412 | } |
413 | |||
414 | bool workspace_is_empty(struct sway_container *ws) { | ||
415 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
416 | return false; | ||
417 | } | ||
418 | if (ws->children->length) { | ||
419 | return false; | ||
420 | } | ||
421 | if (ws->sway_workspace->floating->children->length) { | ||
422 | return false; | ||
423 | } | ||
424 | return true; | ||
425 | } | ||