diff options
68 files changed, 3439 insertions, 3433 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index 6024f0f6..2fef0081 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -407,7 +407,9 @@ struct sway_config { | |||
407 | struct output_config *output_config; | 407 | struct output_config *output_config; |
408 | struct seat_config *seat_config; | 408 | struct seat_config *seat_config; |
409 | struct sway_seat *seat; | 409 | struct sway_seat *seat; |
410 | struct sway_container *current_container; | 410 | struct sway_node *node; |
411 | struct sway_container *container; | ||
412 | struct sway_workspace *workspace; | ||
411 | bool using_criteria; | 413 | bool using_criteria; |
412 | struct { | 414 | struct { |
413 | int argc; | 415 | int argc; |
@@ -486,8 +488,7 @@ struct output_config *new_output_config(const char *name); | |||
486 | 488 | ||
487 | void merge_output_config(struct output_config *dst, struct output_config *src); | 489 | void merge_output_config(struct output_config *dst, struct output_config *src); |
488 | 490 | ||
489 | void apply_output_config(struct output_config *oc, | 491 | void apply_output_config(struct output_config *oc, struct sway_output *output); |
490 | struct sway_container *output); | ||
491 | 492 | ||
492 | struct output_config *store_output_config(struct output_config *oc); | 493 | struct output_config *store_output_config(struct output_config *oc); |
493 | 494 | ||
diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h index 7ac924e7..66e8c9a2 100644 --- a/include/sway/desktop/transaction.h +++ b/include/sway/desktop/transaction.h | |||
@@ -1,7 +1,6 @@ | |||
1 | #ifndef _SWAY_TRANSACTION_H | 1 | #ifndef _SWAY_TRANSACTION_H |
2 | #define _SWAY_TRANSACTION_H | 2 | #define _SWAY_TRANSACTION_H |
3 | #include <wlr/render/wlr_texture.h> | 3 | #include <stdint.h> |
4 | #include "sway/tree/container.h" | ||
5 | 4 | ||
6 | /** | 5 | /** |
7 | * Transactions enable us to perform atomic layout updates. | 6 | * Transactions enable us to perform atomic layout updates. |
@@ -21,6 +20,7 @@ | |||
21 | */ | 20 | */ |
22 | 21 | ||
23 | struct sway_transaction_instruction; | 22 | struct sway_transaction_instruction; |
23 | struct sway_view; | ||
24 | 24 | ||
25 | /** | 25 | /** |
26 | * Find all dirty containers, create and commit a transaction containing them, | 26 | * Find all dirty containers, create and commit a transaction containing them, |
diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index aa2f6f19..bde3cf46 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h | |||
@@ -37,10 +37,10 @@ struct sway_input_manager { | |||
37 | struct sway_input_manager *input_manager_create(struct sway_server *server); | 37 | struct sway_input_manager *input_manager_create(struct sway_server *server); |
38 | 38 | ||
39 | bool input_manager_has_focus(struct sway_input_manager *input, | 39 | bool input_manager_has_focus(struct sway_input_manager *input, |
40 | struct sway_container *container); | 40 | struct sway_node *node); |
41 | 41 | ||
42 | void input_manager_set_focus(struct sway_input_manager *input, | 42 | void input_manager_set_focus(struct sway_input_manager *input, |
43 | struct sway_container *container); | 43 | struct sway_node *node); |
44 | 44 | ||
45 | void input_manager_configure_xcursor(struct sway_input_manager *input); | 45 | void input_manager_configure_xcursor(struct sway_input_manager *input); |
46 | 46 | ||
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 5c404ecd..8a7e5450 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -13,9 +13,9 @@ struct sway_seat_device { | |||
13 | struct wl_list link; // sway_seat::devices | 13 | struct wl_list link; // sway_seat::devices |
14 | }; | 14 | }; |
15 | 15 | ||
16 | struct sway_seat_container { | 16 | struct sway_seat_node { |
17 | struct sway_seat *seat; | 17 | struct sway_seat *seat; |
18 | struct sway_container *container; | 18 | struct sway_node *node; |
19 | 19 | ||
20 | struct wl_list link; // sway_seat::focus_stack | 20 | struct wl_list link; // sway_seat::focus_stack |
21 | 21 | ||
@@ -76,7 +76,7 @@ struct sway_seat { | |||
76 | uint32_t last_button_serial; | 76 | uint32_t last_button_serial; |
77 | 77 | ||
78 | struct wl_listener focus_destroy; | 78 | struct wl_listener focus_destroy; |
79 | struct wl_listener new_container; | 79 | struct wl_listener new_node; |
80 | struct wl_listener new_drag_icon; | 80 | struct wl_listener new_drag_icon; |
81 | 81 | ||
82 | struct wl_list devices; // sway_seat_device::link | 82 | struct wl_list devices; // sway_seat_device::link |
@@ -100,10 +100,10 @@ void seat_remove_device(struct sway_seat *seat, | |||
100 | 100 | ||
101 | void seat_configure_xcursor(struct sway_seat *seat); | 101 | void seat_configure_xcursor(struct sway_seat *seat); |
102 | 102 | ||
103 | void seat_set_focus(struct sway_seat *seat, struct sway_container *container); | 103 | void seat_set_focus(struct sway_seat *seat, struct sway_node *node); |
104 | 104 | ||
105 | void seat_set_focus_warp(struct sway_seat *seat, | 105 | void seat_set_focus_warp(struct sway_seat *seat, |
106 | struct sway_container *container, bool warp, bool notify); | 106 | struct sway_node *node, bool warp, bool notify); |
107 | 107 | ||
108 | void seat_set_focus_surface(struct sway_seat *seat, | 108 | void seat_set_focus_surface(struct sway_seat *seat, |
109 | struct wlr_surface *surface, bool unfocus); | 109 | struct wlr_surface *surface, bool unfocus); |
@@ -114,7 +114,11 @@ void seat_set_focus_layer(struct sway_seat *seat, | |||
114 | void seat_set_exclusive_client(struct sway_seat *seat, | 114 | void seat_set_exclusive_client(struct sway_seat *seat, |
115 | struct wl_client *client); | 115 | struct wl_client *client); |
116 | 116 | ||
117 | struct sway_container *seat_get_focus(struct sway_seat *seat); | 117 | struct sway_node *seat_get_focus(struct sway_seat *seat); |
118 | |||
119 | struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat); | ||
120 | |||
121 | struct sway_container *seat_get_focused_container(struct sway_seat *seat); | ||
118 | 122 | ||
119 | /** | 123 | /** |
120 | * Return the last container to be focused for the seat (or the most recently | 124 | * Return the last container to be focused for the seat (or the most recently |
@@ -125,32 +129,31 @@ struct sway_container *seat_get_focus(struct sway_seat *seat); | |||
125 | * is destroyed, or focus moves to a container with children and we need to | 129 | * is destroyed, or focus moves to a container with children and we need to |
126 | * descend into the next leaf in focus order. | 130 | * descend into the next leaf in focus order. |
127 | */ | 131 | */ |
128 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | 132 | struct sway_node *seat_get_focus_inactive(struct sway_seat *seat, |
129 | struct sway_container *container); | 133 | struct sway_node *node); |
130 | 134 | ||
131 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, | 135 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, |
132 | struct sway_container *container); | 136 | struct sway_workspace *workspace); |
133 | 137 | ||
134 | /** | 138 | /** |
135 | * Descend into the focus stack to find the focus-inactive view. Useful for | 139 | * Descend into the focus stack to find the focus-inactive view. Useful for |
136 | * container placement when they change position in the tree. | 140 | * container placement when they change position in the tree. |
137 | */ | 141 | */ |
138 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, | 142 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, |
139 | struct sway_container *container); | 143 | struct sway_node *ancestor); |
140 | 144 | ||
141 | /** | 145 | /** |
142 | * Return the immediate child of container which was most recently focused. | 146 | * Return the immediate child of container which was most recently focused. |
143 | */ | 147 | */ |
144 | struct sway_container *seat_get_active_child(struct sway_seat *seat, | 148 | struct sway_node *seat_get_active_child(struct sway_seat *seat, |
145 | struct sway_container *container); | 149 | struct sway_node *parent); |
146 | 150 | ||
147 | /** | 151 | /** |
148 | * Iterate over the focus-inactive children of the container calling the | 152 | * Iterate over the focus-inactive children of the container calling the |
149 | * function on each. | 153 | * function on each. |
150 | */ | 154 | */ |
151 | void seat_focus_inactive_children_for_each(struct sway_seat *seat, | 155 | void seat_for_each_node(struct sway_seat *seat, |
152 | struct sway_container *container, | 156 | void (*f)(struct sway_node *node, void *data), void *data); |
153 | void (*f)(struct sway_container *container, void *data), void *data); | ||
154 | 157 | ||
155 | void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config); | 158 | void seat_apply_config(struct sway_seat *seat, struct seat_config *seat_config); |
156 | 159 | ||
@@ -173,7 +176,7 @@ void seat_begin_resize_tiling(struct sway_seat *seat, | |||
173 | struct sway_container *con, uint32_t button, enum wlr_edges edge); | 176 | struct sway_container *con, uint32_t button, enum wlr_edges edge); |
174 | 177 | ||
175 | struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, | 178 | struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, |
176 | struct sway_container *container); | 179 | struct sway_workspace *workspace); |
177 | 180 | ||
178 | void seat_end_mouse_operation(struct sway_seat *seat); | 181 | void seat_end_mouse_operation(struct sway_seat *seat); |
179 | 182 | ||
diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h index eaaa2164..fef243e3 100644 --- a/include/sway/ipc-json.h +++ b/include/sway/ipc-json.h | |||
@@ -7,8 +7,8 @@ | |||
7 | json_object *ipc_json_get_version(); | 7 | json_object *ipc_json_get_version(); |
8 | 8 | ||
9 | json_object *ipc_json_describe_disabled_output(struct sway_output *o); | 9 | json_object *ipc_json_describe_disabled_output(struct sway_output *o); |
10 | json_object *ipc_json_describe_container(struct sway_container *c); | 10 | json_object *ipc_json_describe_node(struct sway_node *node); |
11 | json_object *ipc_json_describe_container_recursive(struct sway_container *c); | 11 | json_object *ipc_json_describe_node_recursive(struct sway_node *node); |
12 | json_object *ipc_json_describe_input(struct sway_input_device *device); | 12 | json_object *ipc_json_describe_input(struct sway_input_device *device); |
13 | json_object *ipc_json_describe_seat(struct sway_seat *seat); | 13 | json_object *ipc_json_describe_seat(struct sway_seat *seat); |
14 | json_object *ipc_json_describe_bar_config(struct bar_config *bar); | 14 | json_object *ipc_json_describe_bar_config(struct bar_config *bar); |
diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 4b6d0e25..80180ec4 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h | |||
@@ -11,8 +11,8 @@ void ipc_init(struct sway_server *server); | |||
11 | 11 | ||
12 | struct sockaddr_un *ipc_user_sockaddr(void); | 12 | struct sockaddr_un *ipc_user_sockaddr(void); |
13 | 13 | ||
14 | void ipc_event_workspace(struct sway_container *old, | 14 | void ipc_event_workspace(struct sway_workspace *old, |
15 | struct sway_container *new, const char *change); | 15 | struct sway_workspace *new, const char *change); |
16 | void ipc_event_window(struct sway_container *window, const char *change); | 16 | void ipc_event_window(struct sway_container *window, const char *change); |
17 | void ipc_event_barconfig_update(struct bar_config *bar); | 17 | void ipc_event_barconfig_update(struct bar_config *bar); |
18 | void ipc_event_mode(const char *mode, bool pango); | 18 | void ipc_event_mode(const char *mode, bool pango); |
diff --git a/include/sway/output.h b/include/sway/output.h index 651fdfe7..540ed8a0 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -6,14 +6,20 @@ | |||
6 | #include <wlr/types/wlr_box.h> | 6 | #include <wlr/types/wlr_box.h> |
7 | #include <wlr/types/wlr_output.h> | 7 | #include <wlr/types/wlr_output.h> |
8 | #include "config.h" | 8 | #include "config.h" |
9 | #include "sway/tree/node.h" | ||
9 | #include "sway/tree/view.h" | 10 | #include "sway/tree/view.h" |
10 | 11 | ||
11 | struct sway_server; | 12 | struct sway_server; |
12 | struct sway_container; | 13 | struct sway_container; |
13 | 14 | ||
15 | struct sway_output_state { | ||
16 | list_t *workspaces; | ||
17 | struct sway_workspace *active_workspace; | ||
18 | }; | ||
19 | |||
14 | struct sway_output { | 20 | struct sway_output { |
21 | struct sway_node node; | ||
15 | struct wlr_output *wlr_output; | 22 | struct wlr_output *wlr_output; |
16 | struct sway_container *swayc; | ||
17 | struct sway_server *server; | 23 | struct sway_server *server; |
18 | 24 | ||
19 | struct wl_list layers[4]; // sway_layer_surface::link | 25 | struct wl_list layers[4]; // sway_layer_surface::link |
@@ -22,11 +28,15 @@ struct sway_output { | |||
22 | struct timespec last_frame; | 28 | struct timespec last_frame; |
23 | struct wlr_output_damage *damage; | 29 | struct wlr_output_damage *damage; |
24 | 30 | ||
31 | bool enabled; | ||
32 | list_t *workspaces; | ||
33 | |||
34 | struct sway_output_state current; | ||
35 | |||
25 | struct wl_listener destroy; | 36 | struct wl_listener destroy; |
26 | struct wl_listener mode; | 37 | struct wl_listener mode; |
27 | struct wl_listener transform; | 38 | struct wl_listener transform; |
28 | struct wl_listener scale; | 39 | struct wl_listener scale; |
29 | |||
30 | struct wl_listener damage_destroy; | 40 | struct wl_listener damage_destroy; |
31 | struct wl_listener damage_frame; | 41 | struct wl_listener damage_frame; |
32 | 42 | ||
@@ -39,13 +49,19 @@ struct sway_output { | |||
39 | } events; | 49 | } events; |
40 | }; | 50 | }; |
41 | 51 | ||
42 | struct sway_container *output_create(struct sway_output *sway_output); | 52 | struct sway_output *output_create(struct wlr_output *wlr_output); |
53 | |||
54 | void output_destroy(struct sway_output *output); | ||
55 | |||
56 | void output_begin_destroy(struct sway_output *output); | ||
43 | 57 | ||
44 | void output_destroy(struct sway_container *output); | 58 | struct sway_output *output_from_wlr_output(struct wlr_output *output); |
45 | 59 | ||
46 | void output_begin_destroy(struct sway_container *output); | 60 | struct sway_output *output_get_in_direction(struct sway_output *reference, |
61 | enum movement_direction direction); | ||
47 | 62 | ||
48 | struct sway_container *output_from_wlr_output(struct wlr_output *output); | 63 | void output_add_workspace(struct sway_output *output, |
64 | struct sway_workspace *workspace); | ||
49 | 65 | ||
50 | typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, | 66 | typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, |
51 | struct wlr_surface *surface, struct wlr_box *box, float rotation, | 67 | struct wlr_surface *surface, struct wlr_box *box, float rotation, |
@@ -64,15 +80,19 @@ void output_damage_box(struct sway_output *output, struct wlr_box *box); | |||
64 | void output_damage_whole_container(struct sway_output *output, | 80 | void output_damage_whole_container(struct sway_output *output, |
65 | struct sway_container *con); | 81 | struct sway_container *con); |
66 | 82 | ||
67 | struct sway_container *output_by_name(const char *name); | 83 | struct sway_output *output_by_name(const char *name); |
68 | 84 | ||
69 | void output_sort_workspaces(struct sway_container *output); | 85 | void output_sort_workspaces(struct sway_output *output); |
70 | 86 | ||
71 | void output_enable(struct sway_output *output); | 87 | struct output_config *output_find_config(struct sway_output *output); |
88 | |||
89 | void output_enable(struct sway_output *output, struct output_config *oc); | ||
90 | |||
91 | void output_disable(struct sway_output *output); | ||
72 | 92 | ||
73 | bool output_has_opaque_overlay_layer_surface(struct sway_output *output); | 93 | bool output_has_opaque_overlay_layer_surface(struct sway_output *output); |
74 | 94 | ||
75 | struct sway_container *output_get_active_workspace(struct sway_output *output); | 95 | struct sway_workspace *output_get_active_workspace(struct sway_output *output); |
76 | 96 | ||
77 | void output_render(struct sway_output *output, struct timespec *when, | 97 | void output_render(struct sway_output *output, struct timespec *when, |
78 | pixman_region32_t *damage); | 98 | pixman_region32_t *damage); |
@@ -103,16 +123,23 @@ void output_drag_icons_for_each_surface(struct sway_output *output, | |||
103 | struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, | 123 | struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, |
104 | void *user_data); | 124 | void *user_data); |
105 | 125 | ||
106 | void output_for_each_workspace(struct sway_container *output, | 126 | void output_for_each_workspace(struct sway_output *output, |
107 | void (*f)(struct sway_container *con, void *data), void *data); | 127 | void (*f)(struct sway_workspace *ws, void *data), void *data); |
108 | 128 | ||
109 | void output_for_each_container(struct sway_container *output, | 129 | void output_for_each_container(struct sway_output *output, |
110 | void (*f)(struct sway_container *con, void *data), void *data); | 130 | void (*f)(struct sway_container *con, void *data), void *data); |
111 | 131 | ||
112 | struct sway_container *output_find_workspace(struct sway_container *output, | 132 | struct sway_workspace *output_find_workspace(struct sway_output *output, |
113 | bool (*test)(struct sway_container *con, void *data), void *data); | 133 | bool (*test)(struct sway_workspace *ws, void *data), void *data); |
114 | 134 | ||
115 | struct sway_container *output_find_container(struct sway_container *output, | 135 | struct sway_container *output_find_container(struct sway_output *output, |
116 | bool (*test)(struct sway_container *con, void *data), void *data); | 136 | bool (*test)(struct sway_container *con, void *data), void *data); |
117 | 137 | ||
138 | void output_get_box(struct sway_output *output, struct wlr_box *box); | ||
139 | |||
140 | enum sway_container_layout output_get_default_layout( | ||
141 | struct sway_output *output); | ||
142 | |||
143 | void output_add_listeners(struct sway_output *output); | ||
144 | |||
118 | #endif | 145 | #endif |
diff --git a/include/sway/server.h b/include/sway/server.h index 1e20f2c8..07e0949a 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -56,7 +56,7 @@ struct sway_server { | |||
56 | 56 | ||
57 | size_t txn_timeout_ms; | 57 | size_t txn_timeout_ms; |
58 | list_t *transactions; | 58 | list_t *transactions; |
59 | list_t *dirty_containers; | 59 | list_t *dirty_nodes; |
60 | }; | 60 | }; |
61 | 61 | ||
62 | struct sway_server server; | 62 | struct sway_server server; |
diff --git a/include/sway/tree/arrange.h b/include/sway/tree/arrange.h index f47e8db5..06a2279c 100644 --- a/include/sway/tree/arrange.h +++ b/include/sway/tree/arrange.h | |||
@@ -1,16 +1,19 @@ | |||
1 | #ifndef _SWAY_ARRANGE_H | 1 | #ifndef _SWAY_ARRANGE_H |
2 | #define _SWAY_ARRANGE_H | 2 | #define _SWAY_ARRANGE_H |
3 | 3 | ||
4 | struct sway_output; | ||
5 | struct sway_workspace; | ||
4 | struct sway_container; | 6 | struct sway_container; |
7 | struct sway_node; | ||
5 | 8 | ||
6 | void arrange_container(struct sway_container *container); | 9 | void arrange_container(struct sway_container *container); |
7 | 10 | ||
8 | void arrange_workspace(struct sway_container *workspace); | 11 | void arrange_workspace(struct sway_workspace *workspace); |
9 | 12 | ||
10 | void arrange_output(struct sway_container *output); | 13 | void arrange_output(struct sway_output *output); |
11 | 14 | ||
12 | void arrange_root(void); | 15 | void arrange_root(void); |
13 | 16 | ||
14 | void arrange_windows(struct sway_container *container); | 17 | void arrange_node(struct sway_node *node); |
15 | 18 | ||
16 | #endif | 19 | #endif |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index e4071cfe..c51425c9 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -5,8 +5,7 @@ | |||
5 | #include <wlr/types/wlr_box.h> | 5 | #include <wlr/types/wlr_box.h> |
6 | #include <wlr/types/wlr_surface.h> | 6 | #include <wlr/types/wlr_surface.h> |
7 | #include "list.h" | 7 | #include "list.h" |
8 | 8 | #include "sway/tree/node.h" | |
9 | extern struct sway_container root_container; | ||
10 | 9 | ||
11 | struct sway_view; | 10 | struct sway_view; |
12 | struct sway_seat; | 11 | struct sway_seat; |
@@ -17,23 +16,6 @@ struct sway_seat; | |||
17 | #define TITLEBAR_H_PADDING 3 | 16 | #define TITLEBAR_H_PADDING 3 |
18 | #define TITLEBAR_V_PADDING 4 | 17 | #define TITLEBAR_V_PADDING 4 |
19 | 18 | ||
20 | /** | ||
21 | * Different kinds of containers. | ||
22 | * | ||
23 | * This enum is in order. A container will never be inside of a container below | ||
24 | * it on this list. | ||
25 | */ | ||
26 | enum sway_container_type { | ||
27 | C_ROOT, | ||
28 | C_OUTPUT, | ||
29 | C_WORKSPACE, | ||
30 | C_CONTAINER, | ||
31 | C_VIEW, | ||
32 | |||
33 | // Keep last | ||
34 | C_TYPES, | ||
35 | }; | ||
36 | |||
37 | enum sway_container_layout { | 19 | enum sway_container_layout { |
38 | L_NONE, | 20 | L_NONE, |
39 | L_HORIZ, | 21 | L_HORIZ, |
@@ -57,18 +39,14 @@ enum movement_direction; | |||
57 | enum wlr_direction; | 39 | enum wlr_direction; |
58 | 40 | ||
59 | struct sway_container_state { | 41 | struct sway_container_state { |
60 | // Container/swayc properties | 42 | // Container properties |
61 | enum sway_container_layout layout; | 43 | enum sway_container_layout layout; |
62 | double swayc_x, swayc_y; | 44 | double con_x, con_y; |
63 | double swayc_width, swayc_height; | 45 | double con_width, con_height; |
64 | 46 | ||
65 | bool is_fullscreen; | 47 | bool is_fullscreen; |
66 | 48 | ||
67 | bool has_gaps; | 49 | struct sway_workspace *workspace; |
68 | double current_gaps; | ||
69 | double gaps_inner; | ||
70 | double gaps_outer; | ||
71 | |||
72 | struct sway_container *parent; | 50 | struct sway_container *parent; |
73 | list_t *children; | 51 | list_t *children; |
74 | 52 | ||
@@ -86,35 +64,19 @@ struct sway_container_state { | |||
86 | bool border_left; | 64 | bool border_left; |
87 | bool border_right; | 65 | bool border_right; |
88 | bool using_csd; | 66 | bool using_csd; |
89 | |||
90 | // Workspace properties | ||
91 | struct sway_container *ws_fullscreen; | ||
92 | list_t *ws_floating; | ||
93 | }; | 67 | }; |
94 | 68 | ||
95 | struct sway_container { | 69 | struct sway_container { |
96 | union { | 70 | struct sway_node node; |
97 | // TODO: Encapsulate state for other node types as well like C_CONTAINER | 71 | struct sway_view *view; |
98 | struct sway_root *sway_root; | ||
99 | struct sway_output *sway_output; | ||
100 | struct sway_workspace *sway_workspace; | ||
101 | struct sway_view *sway_view; | ||
102 | }; | ||
103 | |||
104 | /** | ||
105 | * A unique ID to identify this container. Primarily used in the | ||
106 | * get_tree JSON output. | ||
107 | */ | ||
108 | size_t id; | ||
109 | 72 | ||
110 | // The pending state is the main container properties, and the current state is in the below struct. | 73 | // The pending state is the main container properties, and the current state is in the below struct. |
111 | // This means most places of the code can refer to the main variables (pending state) and it'll just work. | 74 | // This means most places of the code can refer to the main variables (pending state) and it'll just work. |
112 | struct sway_container_state current; | 75 | struct sway_container_state current; |
113 | 76 | ||
114 | char *name; // The view's title (unformatted) | 77 | char *title; // The view's title (unformatted) |
115 | char *formatted_title; // The title displayed in the title bar | 78 | char *formatted_title; // The title displayed in the title bar |
116 | 79 | ||
117 | enum sway_container_type type; | ||
118 | enum sway_container_layout layout; | 80 | enum sway_container_layout layout; |
119 | enum sway_container_layout prev_split_layout; | 81 | enum sway_container_layout prev_split_layout; |
120 | 82 | ||
@@ -132,14 +94,13 @@ struct sway_container { | |||
132 | 94 | ||
133 | // The gaps currently applied to the container. | 95 | // The gaps currently applied to the container. |
134 | double current_gaps; | 96 | double current_gaps; |
135 | |||
136 | bool has_gaps; | 97 | bool has_gaps; |
137 | double gaps_inner; | 98 | double gaps_inner; |
138 | double gaps_outer; | 99 | double gaps_outer; |
139 | 100 | ||
140 | list_t *children; | 101 | struct sway_workspace *workspace; // NULL when hidden in the scratchpad |
141 | 102 | struct sway_container *parent; // NULL if container in root of workspace | |
142 | struct sway_container *parent; | 103 | list_t *children; // struct sway_container |
143 | 104 | ||
144 | // Outputs currently being intersected | 105 | // Outputs currently being intersected |
145 | list_t *outputs; // struct sway_output | 106 | list_t *outputs; // struct sway_output |
@@ -157,42 +118,17 @@ struct sway_container { | |||
157 | struct wlr_texture *title_urgent; | 118 | struct wlr_texture *title_urgent; |
158 | size_t title_height; | 119 | size_t title_height; |
159 | 120 | ||
160 | // The number of transactions which reference this container. | ||
161 | size_t ntxnrefs; | ||
162 | |||
163 | // If this container is a view and is waiting for the client to respond to a | ||
164 | // configure then this will be populated, otherwise NULL. | ||
165 | struct sway_transaction_instruction *instruction; | ||
166 | |||
167 | bool destroying; | ||
168 | |||
169 | // If true, indicates that the container has pending state that differs from | ||
170 | // the current. | ||
171 | bool dirty; | ||
172 | |||
173 | struct { | 121 | struct { |
174 | struct wl_signal destroy; | 122 | struct wl_signal destroy; |
175 | } events; | 123 | } events; |
176 | }; | 124 | }; |
177 | 125 | ||
178 | struct sway_container *container_create(enum sway_container_type type); | 126 | struct sway_container *container_create(struct sway_view *view); |
179 | |||
180 | const char *container_type_to_str(enum sway_container_type type); | ||
181 | |||
182 | /* | ||
183 | * Create a new view container. A view can be a child of a workspace container | ||
184 | * or a container container and are rendered in the order and structure of | ||
185 | * how they are attached to the tree. | ||
186 | */ | ||
187 | struct sway_container *container_view_create( | ||
188 | struct sway_container *sibling, struct sway_view *sway_view); | ||
189 | 127 | ||
190 | void container_destroy(struct sway_container *con); | 128 | void container_destroy(struct sway_container *con); |
191 | 129 | ||
192 | void container_begin_destroy(struct sway_container *con); | 130 | void container_begin_destroy(struct sway_container *con); |
193 | 131 | ||
194 | struct sway_container *container_close(struct sway_container *container); | ||
195 | |||
196 | /** | 132 | /** |
197 | * Search a container's descendants a container based on test criteria. Returns | 133 | * Search a container's descendants a container based on test criteria. Returns |
198 | * the first container that passes the test. | 134 | * the first container that passes the test. |
@@ -201,22 +137,16 @@ struct sway_container *container_find_child(struct sway_container *container, | |||
201 | bool (*test)(struct sway_container *view, void *data), void *data); | 137 | bool (*test)(struct sway_container *view, void *data), void *data); |
202 | 138 | ||
203 | /** | 139 | /** |
204 | * Finds a parent container with the given struct sway_containerype. | ||
205 | */ | ||
206 | struct sway_container *container_parent(struct sway_container *container, | ||
207 | enum sway_container_type type); | ||
208 | |||
209 | /** | ||
210 | * Find a container at the given coordinates. Returns the the surface and | 140 | * Find a container at the given coordinates. Returns the the surface and |
211 | * surface-local coordinates of the given layout coordinates if the container | 141 | * surface-local coordinates of the given layout coordinates if the container |
212 | * is a view and the view contains a surface at those coordinates. | 142 | * is a view and the view contains a surface at those coordinates. |
213 | */ | 143 | */ |
214 | struct sway_container *container_at(struct sway_container *workspace, | 144 | struct sway_container *container_at(struct sway_workspace *workspace, |
215 | double lx, double ly, struct wlr_surface **surface, | 145 | double lx, double ly, struct wlr_surface **surface, |
216 | double *sx, double *sy); | 146 | double *sx, double *sy); |
217 | 147 | ||
218 | struct sway_container *tiling_container_at( | 148 | struct sway_container *tiling_container_at( |
219 | struct sway_container *con, double lx, double ly, | 149 | struct sway_node *parent, double lx, double ly, |
220 | struct wlr_surface **surface, double *sx, double *sy); | 150 | struct wlr_surface **surface, double *sx, double *sy); |
221 | 151 | ||
222 | void container_for_each_child(struct sway_container *container, | 152 | void container_for_each_child(struct sway_container *container, |
@@ -228,16 +158,11 @@ void container_for_each_child(struct sway_container *container, | |||
228 | bool container_has_ancestor(struct sway_container *container, | 158 | bool container_has_ancestor(struct sway_container *container, |
229 | struct sway_container *ancestor); | 159 | struct sway_container *ancestor); |
230 | 160 | ||
231 | int container_count_descendants_of_type(struct sway_container *con, | ||
232 | enum sway_container_type type); | ||
233 | |||
234 | void container_create_notify(struct sway_container *container); | ||
235 | |||
236 | void container_update_textures_recursive(struct sway_container *con); | 161 | void container_update_textures_recursive(struct sway_container *con); |
237 | 162 | ||
238 | void container_damage_whole(struct sway_container *container); | 163 | void container_damage_whole(struct sway_container *container); |
239 | 164 | ||
240 | struct sway_container *container_reap_empty(struct sway_container *con); | 165 | void container_reap_empty(struct sway_container *con); |
241 | 166 | ||
242 | struct sway_container *container_flatten(struct sway_container *container); | 167 | struct sway_container *container_flatten(struct sway_container *container); |
243 | 168 | ||
@@ -248,11 +173,10 @@ void container_update_title_textures(struct sway_container *container); | |||
248 | */ | 173 | */ |
249 | void container_calculate_title_height(struct sway_container *container); | 174 | void container_calculate_title_height(struct sway_container *container); |
250 | 175 | ||
251 | /** | 176 | size_t container_build_representation(enum sway_container_layout layout, |
252 | * Notify a container that a tree modification has changed in its children, | 177 | list_t *children, char *buffer); |
253 | * so the container can update its tree representation. | 178 | |
254 | */ | 179 | void container_update_representation(struct sway_container *container); |
255 | void container_notify_subtree_changed(struct sway_container *container); | ||
256 | 180 | ||
257 | /** | 181 | /** |
258 | * Return the height of a regular title bar. | 182 | * Return the height of a regular title bar. |
@@ -288,8 +212,7 @@ void container_floating_translate(struct sway_container *con, | |||
288 | /** | 212 | /** |
289 | * Choose an output for the floating container's new position. | 213 | * Choose an output for the floating container's new position. |
290 | */ | 214 | */ |
291 | struct sway_container *container_floating_find_output( | 215 | struct sway_output *container_floating_find_output(struct sway_container *con); |
292 | struct sway_container *con); | ||
293 | 216 | ||
294 | /** | 217 | /** |
295 | * Move a floating container to a new layout-local position. | 218 | * Move a floating container to a new layout-local position. |
@@ -302,12 +225,6 @@ void container_floating_move_to(struct sway_container *con, | |||
302 | */ | 225 | */ |
303 | void container_floating_move_to_center(struct sway_container *con); | 226 | void container_floating_move_to_center(struct sway_container *con); |
304 | 227 | ||
305 | /** | ||
306 | * Mark a container as dirty if it isn't already. Dirty containers will be | ||
307 | * included in the next transaction then unmarked as dirty. | ||
308 | */ | ||
309 | void container_set_dirty(struct sway_container *container); | ||
310 | |||
311 | bool container_has_urgent_child(struct sway_container *container); | 228 | bool container_has_urgent_child(struct sway_container *container); |
312 | 229 | ||
313 | /** | 230 | /** |
@@ -342,10 +259,18 @@ void container_remove_gaps(struct sway_container *container); | |||
342 | 259 | ||
343 | void container_add_gaps(struct sway_container *container); | 260 | void container_add_gaps(struct sway_container *container); |
344 | 261 | ||
262 | enum sway_container_layout container_parent_layout(struct sway_container *con); | ||
263 | |||
264 | enum sway_container_layout container_current_parent_layout( | ||
265 | struct sway_container *con); | ||
266 | |||
267 | list_t *container_get_siblings(const struct sway_container *container); | ||
268 | |||
345 | int container_sibling_index(const struct sway_container *child); | 269 | int container_sibling_index(const struct sway_container *child); |
346 | 270 | ||
347 | void container_handle_fullscreen_reparent(struct sway_container *con, | 271 | list_t *container_get_current_siblings(struct sway_container *container); |
348 | struct sway_container *old_parent); | 272 | |
273 | void container_handle_fullscreen_reparent(struct sway_container *con); | ||
349 | 274 | ||
350 | void container_add_child(struct sway_container *parent, | 275 | void container_add_child(struct sway_container *parent, |
351 | struct sway_container *child); | 276 | struct sway_container *child); |
@@ -353,19 +278,16 @@ void container_add_child(struct sway_container *parent, | |||
353 | void container_insert_child(struct sway_container *parent, | 278 | void container_insert_child(struct sway_container *parent, |
354 | struct sway_container *child, int i); | 279 | struct sway_container *child, int i); |
355 | 280 | ||
356 | struct sway_container *container_add_sibling(struct sway_container *parent, | 281 | void container_add_sibling(struct sway_container *parent, |
357 | struct sway_container *child); | 282 | struct sway_container *child, int offset); |
358 | 283 | ||
359 | struct sway_container *container_remove_child(struct sway_container *child); | 284 | void container_detach(struct sway_container *child); |
360 | 285 | ||
361 | struct sway_container *container_replace_child(struct sway_container *child, | 286 | void container_replace(struct sway_container *container, |
362 | struct sway_container *new_child); | 287 | struct sway_container *replacement); |
363 | 288 | ||
364 | bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out); | 289 | bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out); |
365 | 290 | ||
366 | enum sway_container_layout container_get_default_layout( | ||
367 | struct sway_container *con); | ||
368 | |||
369 | struct sway_container *container_split(struct sway_container *child, | 291 | struct sway_container *container_split(struct sway_container *child, |
370 | enum sway_container_layout layout); | 292 | enum sway_container_layout layout); |
371 | 293 | ||
diff --git a/include/sway/tree/node.h b/include/sway/tree/node.h new file mode 100644 index 00000000..5b8c1909 --- /dev/null +++ b/include/sway/tree/node.h | |||
@@ -0,0 +1,74 @@ | |||
1 | #ifndef _SWAY_NODE_H | ||
2 | #define _SWAY_NODE_H | ||
3 | #include <stdbool.h> | ||
4 | #include "list.h" | ||
5 | |||
6 | struct sway_root; | ||
7 | struct sway_output; | ||
8 | struct sway_workspace; | ||
9 | struct sway_container; | ||
10 | struct sway_transaction_instruction; | ||
11 | struct wlr_box; | ||
12 | |||
13 | enum sway_node_type { | ||
14 | N_ROOT, | ||
15 | N_OUTPUT, | ||
16 | N_WORKSPACE, | ||
17 | N_CONTAINER, | ||
18 | }; | ||
19 | |||
20 | struct sway_node { | ||
21 | enum sway_node_type type; | ||
22 | union { | ||
23 | struct sway_root *sway_root; | ||
24 | struct sway_output *sway_output; | ||
25 | struct sway_workspace *sway_workspace; | ||
26 | struct sway_container *sway_container; | ||
27 | }; | ||
28 | |||
29 | /** | ||
30 | * A unique ID to identify this node. | ||
31 | * Primarily used in the get_tree JSON output. | ||
32 | */ | ||
33 | size_t id; | ||
34 | |||
35 | struct sway_transaction_instruction *instruction; | ||
36 | size_t ntxnrefs; | ||
37 | bool destroying; | ||
38 | |||
39 | // If true, indicates that the container has pending state that differs from | ||
40 | // the current. | ||
41 | bool dirty; | ||
42 | |||
43 | struct { | ||
44 | struct wl_signal destroy; | ||
45 | } events; | ||
46 | }; | ||
47 | |||
48 | void node_init(struct sway_node *node, enum sway_node_type type, void *thing); | ||
49 | |||
50 | const char *node_type_to_str(enum sway_node_type type); | ||
51 | |||
52 | /** | ||
53 | * Mark a node as dirty if it isn't already. Dirty nodes will be included in the | ||
54 | * next transaction then unmarked as dirty. | ||
55 | */ | ||
56 | void node_set_dirty(struct sway_node *node); | ||
57 | |||
58 | bool node_is_view(struct sway_node *node); | ||
59 | |||
60 | char *node_get_name(struct sway_node *node); | ||
61 | |||
62 | void node_get_box(struct sway_node *node, struct wlr_box *box); | ||
63 | |||
64 | struct sway_output *node_get_output(struct sway_node *node); | ||
65 | |||
66 | enum sway_container_layout node_get_layout(struct sway_node *node); | ||
67 | |||
68 | struct sway_node *node_get_parent(struct sway_node *node); | ||
69 | |||
70 | list_t *node_get_children(struct sway_node *node); | ||
71 | |||
72 | bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor); | ||
73 | |||
74 | #endif | ||
diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index ec6516c9..a2d464f9 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h | |||
@@ -5,12 +5,14 @@ | |||
5 | #include <wlr/types/wlr_output_layout.h> | 5 | #include <wlr/types/wlr_output_layout.h> |
6 | #include <wlr/render/wlr_texture.h> | 6 | #include <wlr/render/wlr_texture.h> |
7 | #include "sway/tree/container.h" | 7 | #include "sway/tree/container.h" |
8 | #include "sway/tree/node.h" | ||
8 | #include "config.h" | 9 | #include "config.h" |
9 | #include "list.h" | 10 | #include "list.h" |
10 | 11 | ||
11 | extern struct sway_container root_container; | 12 | extern struct sway_root *root; |
12 | 13 | ||
13 | struct sway_root { | 14 | struct sway_root { |
15 | struct sway_node node; | ||
14 | struct wlr_output_layout *output_layout; | 16 | struct wlr_output_layout *output_layout; |
15 | 17 | ||
16 | struct wl_listener output_layout_change; | 18 | struct wl_listener output_layout_change; |
@@ -24,17 +26,21 @@ struct sway_root { | |||
24 | // Includes disabled outputs | 26 | // Includes disabled outputs |
25 | struct wl_list all_outputs; // sway_output::link | 27 | struct wl_list all_outputs; // sway_output::link |
26 | 28 | ||
29 | double x, y; | ||
30 | double width, height; | ||
31 | |||
32 | list_t *outputs; // struct sway_output | ||
27 | list_t *scratchpad; // struct sway_container | 33 | list_t *scratchpad; // struct sway_container |
28 | list_t *saved_workspaces; // For when there's no connected outputs | 34 | list_t *saved_workspaces; // For when there's no connected outputs |
29 | 35 | ||
30 | struct { | 36 | struct { |
31 | struct wl_signal new_container; | 37 | struct wl_signal new_node; |
32 | } events; | 38 | } events; |
33 | }; | 39 | }; |
34 | 40 | ||
35 | void root_create(void); | 41 | struct sway_root *root_create(void); |
36 | 42 | ||
37 | void root_destroy(void); | 43 | void root_destroy(struct sway_root *root); |
38 | 44 | ||
39 | /** | 45 | /** |
40 | * Move a container to the scratchpad. | 46 | * Move a container to the scratchpad. |
@@ -56,23 +62,25 @@ void root_scratchpad_show(struct sway_container *con); | |||
56 | */ | 62 | */ |
57 | void root_scratchpad_hide(struct sway_container *con); | 63 | void root_scratchpad_hide(struct sway_container *con); |
58 | 64 | ||
59 | struct sway_container *root_workspace_for_pid(pid_t pid); | 65 | struct sway_workspace *root_workspace_for_pid(pid_t pid); |
60 | 66 | ||
61 | void root_record_workspace_pid(pid_t pid); | 67 | void root_record_workspace_pid(pid_t pid); |
62 | 68 | ||
63 | void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), | 69 | void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), |
64 | void *data); | 70 | void *data); |
65 | 71 | ||
66 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), | 72 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), |
67 | void *data); | 73 | void *data); |
68 | 74 | ||
69 | struct sway_container *root_find_output( | 75 | struct sway_output *root_find_output( |
70 | bool (*test)(struct sway_container *con, void *data), void *data); | 76 | bool (*test)(struct sway_output *output, void *data), void *data); |
71 | 77 | ||
72 | struct sway_container *root_find_workspace( | 78 | struct sway_workspace *root_find_workspace( |
73 | bool (*test)(struct sway_container *con, void *data), void *data); | 79 | bool (*test)(struct sway_workspace *ws, void *data), void *data); |
74 | 80 | ||
75 | struct sway_container *root_find_container( | 81 | struct sway_container *root_find_container( |
76 | bool (*test)(struct sway_container *con, void *data), void *data); | 82 | bool (*test)(struct sway_container *con, void *data), void *data); |
77 | 83 | ||
84 | void root_get_box(struct sway_root *root, struct wlr_box *box); | ||
85 | |||
78 | #endif | 86 | #endif |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 30d3e742..439dc1bf 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -58,7 +58,7 @@ struct sway_view { | |||
58 | enum sway_view_type type; | 58 | enum sway_view_type type; |
59 | const struct sway_view_impl *impl; | 59 | const struct sway_view_impl *impl; |
60 | 60 | ||
61 | struct sway_container *swayc; // NULL for unmapped views | 61 | struct sway_container *container; // NULL if unmapped and transactions finished |
62 | struct wlr_surface *surface; // NULL for unmapped views | 62 | struct wlr_surface *surface; // NULL for unmapped views |
63 | 63 | ||
64 | // Geometry of the view itself (excludes borders) in layout coordinates | 64 | // Geometry of the view itself (excludes borders) in layout coordinates |
@@ -254,7 +254,7 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, | |||
254 | int height); | 254 | int height); |
255 | 255 | ||
256 | /** | 256 | /** |
257 | * Configure the view's position and size based on the swayc's position and | 257 | * Configure the view's position and size based on the container's position and |
258 | * size, taking borders into consideration. | 258 | * size, taking borders into consideration. |
259 | */ | 259 | */ |
260 | void view_autoconfigure(struct sway_view *view); | 260 | void view_autoconfigure(struct sway_view *view); |
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 04325919..af9a071a 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -3,66 +3,98 @@ | |||
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/node.h" | ||
6 | 7 | ||
7 | struct sway_view; | 8 | struct sway_view; |
8 | 9 | ||
10 | struct sway_workspace_state { | ||
11 | struct sway_container *fullscreen; | ||
12 | double x, y; | ||
13 | int width, height; | ||
14 | enum sway_container_layout layout; | ||
15 | struct sway_output *output; | ||
16 | list_t *floating; | ||
17 | list_t *tiling; | ||
18 | |||
19 | struct sway_container *focused_inactive_child; | ||
20 | bool focused; | ||
21 | }; | ||
22 | |||
9 | struct sway_workspace { | 23 | struct sway_workspace { |
10 | struct sway_container *swayc; | 24 | struct sway_node node; |
11 | struct sway_container *fullscreen; | 25 | struct sway_container *fullscreen; |
12 | list_t *floating; // struct sway_container | 26 | |
27 | char *name; | ||
28 | char *representation; | ||
29 | |||
30 | double x, y; | ||
31 | int width, height; | ||
32 | enum sway_container_layout layout; | ||
33 | enum sway_container_layout prev_split_layout; | ||
34 | |||
35 | double current_gaps; | ||
36 | bool has_gaps; | ||
37 | double gaps_inner; | ||
38 | double gaps_outer; | ||
39 | |||
40 | struct sway_output *output; // NULL if no outputs are connected | ||
41 | list_t *floating; // struct sway_container | ||
42 | list_t *tiling; // struct sway_container | ||
13 | list_t *output_priority; | 43 | list_t *output_priority; |
14 | bool urgent; | 44 | bool urgent; |
45 | |||
46 | struct sway_workspace_state current; | ||
15 | }; | 47 | }; |
16 | 48 | ||
17 | extern char *prev_workspace_name; | 49 | extern char *prev_workspace_name; |
18 | 50 | ||
19 | struct sway_container *workspace_get_initial_output(const char *name); | 51 | struct sway_output *workspace_get_initial_output(const char *name); |
20 | 52 | ||
21 | struct sway_container *workspace_create(struct sway_container *output, | 53 | struct sway_workspace *workspace_create(struct sway_output *output, |
22 | const char *name); | 54 | const char *name); |
23 | 55 | ||
24 | void workspace_destroy(struct sway_container *workspace); | 56 | void workspace_destroy(struct sway_workspace *workspace); |
25 | 57 | ||
26 | void workspace_begin_destroy(struct sway_container *workspace); | 58 | void workspace_begin_destroy(struct sway_workspace *workspace); |
27 | 59 | ||
28 | void workspace_consider_destroy(struct sway_container *ws); | 60 | void workspace_consider_destroy(struct sway_workspace *ws); |
29 | 61 | ||
30 | char *workspace_next_name(const char *output_name); | 62 | char *workspace_next_name(const char *output_name); |
31 | 63 | ||
32 | bool workspace_switch(struct sway_container *workspace, | 64 | bool workspace_switch(struct sway_workspace *workspace, |
33 | bool no_auto_back_and_forth); | 65 | bool no_auto_back_and_forth); |
34 | 66 | ||
35 | struct sway_container *workspace_by_number(const char* name); | 67 | struct sway_workspace *workspace_by_number(const char* name); |
36 | 68 | ||
37 | struct sway_container *workspace_by_name(const char*); | 69 | struct sway_workspace *workspace_by_name(const char*); |
38 | 70 | ||
39 | struct sway_container *workspace_output_next(struct sway_container *current); | 71 | struct sway_workspace *workspace_output_next(struct sway_workspace *current); |
40 | 72 | ||
41 | struct sway_container *workspace_next(struct sway_container *current); | 73 | struct sway_workspace *workspace_next(struct sway_workspace *current); |
42 | 74 | ||
43 | struct sway_container *workspace_output_prev(struct sway_container *current); | 75 | struct sway_workspace *workspace_output_prev(struct sway_workspace *current); |
44 | 76 | ||
45 | struct sway_container *workspace_prev(struct sway_container *current); | 77 | struct sway_workspace *workspace_prev(struct sway_workspace *current); |
46 | 78 | ||
47 | bool workspace_is_visible(struct sway_container *ws); | 79 | bool workspace_is_visible(struct sway_workspace *ws); |
48 | 80 | ||
49 | bool workspace_is_empty(struct sway_container *ws); | 81 | bool workspace_is_empty(struct sway_workspace *ws); |
50 | 82 | ||
51 | void workspace_output_raise_priority(struct sway_container *workspace, | 83 | void workspace_output_raise_priority(struct sway_workspace *workspace, |
52 | struct sway_container *old_output, struct sway_container *new_output); | 84 | struct sway_output *old_output, struct sway_output *new_output); |
53 | 85 | ||
54 | void workspace_output_add_priority(struct sway_container *workspace, | 86 | void workspace_output_add_priority(struct sway_workspace *workspace, |
55 | struct sway_container *output); | 87 | struct sway_output *output); |
56 | 88 | ||
57 | struct sway_container *workspace_output_get_highest_available( | 89 | struct sway_output *workspace_output_get_highest_available( |
58 | struct sway_container *ws, struct sway_container *exclude); | 90 | struct sway_workspace *ws, struct sway_output *exclude); |
59 | 91 | ||
60 | void workspace_detect_urgent(struct sway_container *workspace); | 92 | void workspace_detect_urgent(struct sway_workspace *workspace); |
61 | 93 | ||
62 | void workspace_for_each_container(struct sway_container *ws, | 94 | void workspace_for_each_container(struct sway_workspace *ws, |
63 | void (*f)(struct sway_container *con, void *data), void *data); | 95 | void (*f)(struct sway_container *con, void *data), void *data); |
64 | 96 | ||
65 | struct sway_container *workspace_find_container(struct sway_container *ws, | 97 | struct sway_container *workspace_find_container(struct sway_workspace *ws, |
66 | bool (*test)(struct sway_container *con, void *data), void *data); | 98 | bool (*test)(struct sway_container *con, void *data), void *data); |
67 | 99 | ||
68 | /** | 100 | /** |
@@ -70,13 +102,28 @@ struct sway_container *workspace_find_container(struct sway_container *ws, | |||
70 | * The new container will be the only direct tiling child of the workspace. | 102 | * The new container will be the only direct tiling child of the workspace. |
71 | * The new container is returned. | 103 | * The new container is returned. |
72 | */ | 104 | */ |
73 | struct sway_container *workspace_wrap_children(struct sway_container *ws); | 105 | struct sway_container *workspace_wrap_children(struct sway_workspace *ws); |
74 | 106 | ||
75 | void workspace_add_floating(struct sway_container *workspace, | 107 | void workspace_detach(struct sway_workspace *workspace); |
108 | |||
109 | void workspace_add_tiling(struct sway_workspace *workspace, | ||
110 | struct sway_container *con); | ||
111 | |||
112 | void workspace_add_floating(struct sway_workspace *workspace, | ||
76 | struct sway_container *con); | 113 | struct sway_container *con); |
77 | 114 | ||
78 | void workspace_remove_gaps(struct sway_container *ws); | 115 | void workspace_insert_tiling(struct sway_workspace *workspace, |
116 | struct sway_container *con, int index); | ||
117 | |||
118 | void workspace_remove_gaps(struct sway_workspace *ws); | ||
119 | |||
120 | void workspace_add_gaps(struct sway_workspace *ws); | ||
121 | |||
122 | struct sway_container *workspace_split(struct sway_workspace *workspace, | ||
123 | enum sway_container_layout layout); | ||
124 | |||
125 | void workspace_update_representation(struct sway_workspace *ws); | ||
79 | 126 | ||
80 | void workspace_add_gaps(struct sway_container *ws); | 127 | void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box); |
81 | 128 | ||
82 | #endif | 129 | #endif |
diff --git a/sway/commands.c b/sway/commands.c index e72b8916..b32628cd 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -212,6 +212,24 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, | |||
212 | return res; | 212 | return res; |
213 | } | 213 | } |
214 | 214 | ||
215 | static void set_config_node(struct sway_node *node) { | ||
216 | config->handler_context.node = node; | ||
217 | switch (node->type) { | ||
218 | case N_CONTAINER: | ||
219 | config->handler_context.container = node->sway_container; | ||
220 | config->handler_context.workspace = node->sway_container->workspace; | ||
221 | break; | ||
222 | case N_WORKSPACE: | ||
223 | config->handler_context.container = NULL; | ||
224 | config->handler_context.workspace = node->sway_workspace; | ||
225 | break; | ||
226 | default: | ||
227 | config->handler_context.container = NULL; | ||
228 | config->handler_context.workspace = NULL; | ||
229 | break; | ||
230 | } | ||
231 | } | ||
232 | |||
215 | struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | 233 | struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { |
216 | // Even though this function will process multiple commands we will only | 234 | // Even though this function will process multiple commands we will only |
217 | // return the last error, if any (for now). (Since we have access to an | 235 | // return the last error, if any (for now). (Since we have access to an |
@@ -295,12 +313,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | |||
295 | if (!config->handler_context.using_criteria) { | 313 | if (!config->handler_context.using_criteria) { |
296 | // without criteria, the command acts upon the focused | 314 | // without criteria, the command acts upon the focused |
297 | // container | 315 | // container |
298 | config->handler_context.current_container = | 316 | set_config_node(seat_get_focus_inactive(seat, &root->node)); |
299 | seat_get_focus_inactive(seat, &root_container); | ||
300 | if (!sway_assert(config->handler_context.current_container, | ||
301 | "could not get focus-inactive for root container")) { | ||
302 | return NULL; | ||
303 | } | ||
304 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 317 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
305 | if (res->status != CMD_SUCCESS) { | 318 | if (res->status != CMD_SUCCESS) { |
306 | free_argv(argc, argv); | 319 | free_argv(argc, argv); |
@@ -314,7 +327,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { | |||
314 | } else { | 327 | } else { |
315 | for (int i = 0; i < views->length; ++i) { | 328 | for (int i = 0; i < views->length; ++i) { |
316 | struct sway_view *view = views->items[i]; | 329 | struct sway_view *view = views->items[i]; |
317 | config->handler_context.current_container = view->swayc; | 330 | set_config_node(&view->container->node); |
318 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 331 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
319 | if (res->status != CMD_SUCCESS) { | 332 | if (res->status != CMD_SUCCESS) { |
320 | free_argv(argc, argv); | 333 | free_argv(argc, argv); |
diff --git a/sway/commands/border.c b/sway/commands/border.c index 9502c877..95498b2f 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -13,13 +13,12 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
13 | return error; | 13 | return error; |
14 | } | 14 | } |
15 | 15 | ||
16 | struct sway_container *container = | 16 | struct sway_container *container = config->handler_context.container; |
17 | config->handler_context.current_container; | 17 | if (!container->view) { |
18 | if (container->type != C_VIEW) { | ||
19 | return cmd_results_new(CMD_INVALID, "border", | 18 | return cmd_results_new(CMD_INVALID, "border", |
20 | "Only views can have borders"); | 19 | "Only views can have borders"); |
21 | } | 20 | } |
22 | struct sway_view *view = container->sway_view; | 21 | struct sway_view *view = container->view; |
23 | 22 | ||
24 | if (strcmp(argv[0], "none") == 0) { | 23 | if (strcmp(argv[0], "none") == 0) { |
25 | view->border = B_NONE; | 24 | view->border = B_NONE; |
@@ -38,11 +37,11 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
38 | view->border_thickness = atoi(argv[1]); | 37 | view->border_thickness = atoi(argv[1]); |
39 | } | 38 | } |
40 | 39 | ||
41 | if (container_is_floating(view->swayc)) { | 40 | if (container_is_floating(view->container)) { |
42 | container_set_geometry_from_floating_view(view->swayc); | 41 | container_set_geometry_from_floating_view(view->container); |
43 | } | 42 | } |
44 | 43 | ||
45 | arrange_windows(view->swayc); | 44 | arrange_container(view->container); |
46 | 45 | ||
47 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 46 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
48 | if (seat->cursor) { | 47 | if (seat->cursor) { |
diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 436376e3..d8729094 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c | |||
@@ -15,24 +15,23 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
15 | if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { | 15 | if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { |
16 | return error; | 16 | return error; |
17 | } | 17 | } |
18 | struct sway_container *container = | 18 | struct sway_container *container = config->handler_context.container; |
19 | config->handler_context.current_container; | 19 | struct sway_workspace *workspace = config->handler_context.workspace; |
20 | if (container->type == C_WORKSPACE && container->children->length == 0) { | 20 | if (!container && workspace->tiling->length == 0) { |
21 | return cmd_results_new(CMD_INVALID, "floating", | 21 | return cmd_results_new(CMD_INVALID, "floating", |
22 | "Can't float an empty workspace"); | 22 | "Can't float an empty workspace"); |
23 | } | 23 | } |
24 | if (container->type == C_WORKSPACE) { | 24 | if (!container) { |
25 | // Wrap the workspace's children in a container so we can float it | 25 | // Wrap the workspace's children in a container so we can float it |
26 | struct sway_container *workspace = container; | 26 | container = workspace_wrap_children(workspace); |
27 | container = workspace_wrap_children(container); | ||
28 | workspace->layout = L_HORIZ; | 27 | workspace->layout = L_HORIZ; |
29 | seat_set_focus(config->handler_context.seat, container); | 28 | seat_set_focus(config->handler_context.seat, &container->node); |
30 | } | 29 | } |
31 | 30 | ||
32 | // If the container is in a floating split container, | 31 | // If the container is in a floating split container, |
33 | // operate on the split container instead of the child. | 32 | // operate on the split container instead of the child. |
34 | if (container_is_floating_or_child(container)) { | 33 | if (container_is_floating_or_child(container)) { |
35 | while (container->parent->type != C_WORKSPACE) { | 34 | while (container->parent) { |
36 | container = container->parent; | 35 | container = container->parent; |
37 | } | 36 | } |
38 | } | 37 | } |
@@ -51,8 +50,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
51 | 50 | ||
52 | container_set_floating(container, wants_floating); | 51 | container_set_floating(container, wants_floating); |
53 | 52 | ||
54 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | 53 | arrange_workspace(container->workspace); |
55 | arrange_windows(workspace); | ||
56 | 54 | ||
57 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 55 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
58 | } | 56 | } |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index f342e524..e31898af 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -34,211 +34,139 @@ static bool parse_movement_direction(const char *name, | |||
34 | } | 34 | } |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * Get swayc in the direction of newly entered output. | 37 | * Get node in the direction of newly entered output. |
38 | */ | 38 | */ |
39 | static struct sway_container *get_swayc_in_output_direction( | 39 | static struct sway_node *get_node_in_output_direction( |
40 | struct sway_container *output, enum movement_direction dir, | 40 | struct sway_output *output, enum movement_direction dir) { |
41 | struct sway_seat *seat) { | 41 | struct sway_seat *seat = config->handler_context.seat; |
42 | if (!output) { | 42 | struct sway_workspace *ws = output_get_active_workspace(output); |
43 | return NULL; | 43 | if (ws->fullscreen) { |
44 | } | 44 | return seat_get_focus_inactive(seat, &ws->fullscreen->node); |
45 | |||
46 | struct sway_container *ws = seat_get_focus_inactive(seat, output); | ||
47 | if (ws->type != C_WORKSPACE) { | ||
48 | ws = container_parent(ws, C_WORKSPACE); | ||
49 | } | ||
50 | |||
51 | if (ws == NULL) { | ||
52 | wlr_log(WLR_ERROR, "got an output without a workspace"); | ||
53 | return NULL; | ||
54 | } | 45 | } |
46 | struct sway_container *container = NULL; | ||
55 | 47 | ||
56 | if (ws->children->length > 0) { | 48 | if (ws->tiling->length > 0) { |
57 | switch (dir) { | 49 | switch (dir) { |
58 | case MOVE_LEFT: | 50 | case MOVE_LEFT: |
59 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { | 51 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { |
60 | // get most right child of new output | 52 | // get most right child of new output |
61 | return ws->children->items[ws->children->length-1]; | 53 | container = ws->tiling->items[ws->tiling->length-1]; |
62 | } else { | 54 | } else { |
63 | return seat_get_focus_inactive(seat, ws); | 55 | container = seat_get_focus_inactive_tiling(seat, ws); |
64 | } | 56 | } |
57 | return &container->node; | ||
65 | case MOVE_RIGHT: | 58 | case MOVE_RIGHT: |
66 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { | 59 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { |
67 | // get most left child of new output | 60 | // get most left child of new output |
68 | return ws->children->items[0]; | 61 | container = ws->tiling->items[0]; |
69 | } else { | 62 | } else { |
70 | return seat_get_focus_inactive(seat, ws); | 63 | container = seat_get_focus_inactive_tiling(seat, ws); |
71 | } | 64 | } |
65 | return &container->node; | ||
72 | case MOVE_UP: | 66 | case MOVE_UP: |
67 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { | ||
68 | // get most bottom child of new output | ||
69 | container = ws->tiling->items[ws->tiling->length-1]; | ||
70 | } else { | ||
71 | container = seat_get_focus_inactive_tiling(seat, ws); | ||
72 | } | ||
73 | return &container->node; | ||
73 | case MOVE_DOWN: { | 74 | case MOVE_DOWN: { |
74 | struct sway_container *focused = | 75 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { |
75 | seat_get_focus_inactive(seat, ws); | 76 | // get most top child of new output |
76 | if (focused && focused->parent) { | 77 | container = ws->tiling->items[0]; |
77 | struct sway_container *parent = focused->parent; | 78 | } else { |
78 | if (parent->layout == L_VERT) { | 79 | container = seat_get_focus_inactive_tiling(seat, ws); |
79 | if (dir == MOVE_UP) { | ||
80 | // get child furthest down on new output | ||
81 | int idx = parent->children->length - 1; | ||
82 | return parent->children->items[idx]; | ||
83 | } else if (dir == MOVE_DOWN) { | ||
84 | // get child furthest up on new output | ||
85 | return parent->children->items[0]; | ||
86 | } | ||
87 | } | ||
88 | return focused; | ||
89 | } | 80 | } |
90 | break; | 81 | return &container->node; |
91 | } | 82 | } |
92 | default: | 83 | default: |
93 | break; | 84 | break; |
94 | } | 85 | } |
95 | } | 86 | } |
96 | 87 | ||
97 | return ws; | 88 | return &ws->node; |
98 | } | 89 | } |
99 | 90 | ||
100 | static struct sway_container *container_get_in_direction( | 91 | static struct sway_node *node_get_in_direction(struct sway_container *container, |
101 | struct sway_container *container, struct sway_seat *seat, | 92 | struct sway_seat *seat, enum movement_direction dir) { |
102 | enum movement_direction dir) { | ||
103 | struct sway_container *parent = container->parent; | ||
104 | |||
105 | if (dir == MOVE_CHILD) { | 93 | if (dir == MOVE_CHILD) { |
106 | return seat_get_focus_inactive(seat, container); | 94 | return seat_get_active_child(seat, &container->node); |
107 | } | 95 | } |
108 | if (container->is_fullscreen) { | 96 | if (container->is_fullscreen) { |
109 | if (dir == MOVE_PARENT) { | 97 | if (dir == MOVE_PARENT) { |
110 | return NULL; | 98 | return NULL; |
111 | } | 99 | } |
112 | container = container_parent(container, C_OUTPUT); | 100 | // Fullscreen container with a direction - go straight to outputs |
113 | parent = container->parent; | 101 | struct sway_output *output = container->workspace->output; |
114 | } else { | 102 | struct sway_output *new_output = output_get_in_direction(output, dir); |
115 | if (dir == MOVE_PARENT) { | 103 | return get_node_in_output_direction(new_output, dir); |
116 | if (parent->type == C_OUTPUT || container_is_floating(container)) { | 104 | } |
117 | return NULL; | 105 | if (dir == MOVE_PARENT) { |
118 | } else { | 106 | return node_get_parent(&container->node); |
119 | return parent; | ||
120 | } | ||
121 | } | ||
122 | } | 107 | } |
123 | 108 | ||
124 | struct sway_container *wrap_candidate = NULL; | 109 | struct sway_container *wrap_candidate = NULL; |
125 | while (true) { | 110 | struct sway_container *current = container; |
111 | while (current) { | ||
126 | bool can_move = false; | 112 | bool can_move = false; |
127 | int desired; | 113 | int desired; |
128 | int idx = list_find(container->parent->children, container); | 114 | int idx = container_sibling_index(current); |
129 | if (idx == -1) { | 115 | enum sway_container_layout parent_layout = |
130 | return NULL; | 116 | container_parent_layout(current); |
131 | } | 117 | list_t *siblings = container_get_siblings(current); |
132 | if (parent->type == C_ROOT) { | ||
133 | enum wlr_direction wlr_dir = 0; | ||
134 | if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), | ||
135 | "got invalid direction: %d", dir)) { | ||
136 | return NULL; | ||
137 | } | ||
138 | int lx = container->x + container->width / 2; | ||
139 | int ly = container->y + container->height / 2; | ||
140 | struct wlr_output_layout *layout = | ||
141 | root_container.sway_root->output_layout; | ||
142 | struct wlr_output *wlr_adjacent = | ||
143 | wlr_output_layout_adjacent_output(layout, wlr_dir, | ||
144 | container->sway_output->wlr_output, lx, ly); | ||
145 | struct sway_container *adjacent = | ||
146 | output_from_wlr_output(wlr_adjacent); | ||
147 | 118 | ||
148 | if (!adjacent || adjacent == container) { | 119 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { |
149 | if (!wrap_candidate) { | 120 | if (parent_layout == L_HORIZ || parent_layout == L_TABBED) { |
150 | return NULL; | 121 | can_move = true; |
151 | } | 122 | desired = idx + (dir == MOVE_LEFT ? -1 : 1); |
152 | return seat_get_focus_inactive_view(seat, wrap_candidate); | ||
153 | } | ||
154 | struct sway_container *next = | ||
155 | get_swayc_in_output_direction(adjacent, dir, seat); | ||
156 | if (next == NULL) { | ||
157 | return NULL; | ||
158 | } | ||
159 | struct sway_container *next_workspace = next; | ||
160 | if (next_workspace->type != C_WORKSPACE) { | ||
161 | next_workspace = container_parent(next_workspace, C_WORKSPACE); | ||
162 | } | ||
163 | sway_assert(next_workspace, "Next container has no workspace"); | ||
164 | if (next_workspace->sway_workspace->fullscreen) { | ||
165 | return seat_get_focus_inactive(seat, | ||
166 | next_workspace->sway_workspace->fullscreen); | ||
167 | } | ||
168 | if (next->children && next->children->length) { | ||
169 | // TODO consider floating children as well | ||
170 | return seat_get_focus_inactive_view(seat, next); | ||
171 | } else { | ||
172 | return next; | ||
173 | } | 123 | } |
174 | } else { | 124 | } else { |
175 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { | 125 | if (parent_layout == L_VERT || parent_layout == L_STACKED) { |
176 | if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { | 126 | can_move = true; |
177 | can_move = true; | 127 | desired = idx + (dir == MOVE_UP ? -1 : 1); |
178 | desired = idx + (dir == MOVE_LEFT ? -1 : 1); | ||
179 | } | ||
180 | } else { | ||
181 | if (parent->layout == L_VERT || parent->layout == L_STACKED) { | ||
182 | can_move = true; | ||
183 | desired = idx + (dir == MOVE_UP ? -1 : 1); | ||
184 | } | ||
185 | } | 128 | } |
186 | } | 129 | } |
187 | 130 | ||
188 | if (can_move) { | 131 | if (can_move) { |
189 | // TODO handle floating | 132 | if (desired < 0 || desired >= siblings->length) { |
190 | if (desired < 0 || desired >= parent->children->length) { | ||
191 | can_move = false; | 133 | can_move = false; |
192 | int len = parent->children->length; | 134 | int len = siblings->length; |
193 | if (config->focus_wrapping != WRAP_NO && !wrap_candidate | 135 | if (config->focus_wrapping != WRAP_NO && !wrap_candidate |
194 | && len > 1) { | 136 | && len > 1) { |
195 | if (desired < 0) { | 137 | if (desired < 0) { |
196 | wrap_candidate = parent->children->items[len-1]; | 138 | wrap_candidate = siblings->items[len-1]; |
197 | } else { | 139 | } else { |
198 | wrap_candidate = parent->children->items[0]; | 140 | wrap_candidate = siblings->items[0]; |
199 | } | 141 | } |
200 | if (config->focus_wrapping == WRAP_FORCE) { | 142 | if (config->focus_wrapping == WRAP_FORCE) { |
201 | return seat_get_focus_inactive_view(seat, | 143 | struct sway_container *c = seat_get_focus_inactive_view( |
202 | wrap_candidate); | 144 | seat, &wrap_candidate->node); |
145 | return &c->node; | ||
203 | } | 146 | } |
204 | } | 147 | } |
205 | } else { | 148 | } else { |
206 | struct sway_container *desired_con = | 149 | struct sway_container *desired_con = siblings->items[desired]; |
207 | parent->children->items[desired]; | 150 | struct sway_container *c = seat_get_focus_inactive_view( |
208 | wlr_log(WLR_DEBUG, | 151 | seat, &desired_con->node); |
209 | "cont %d-%p dir %i sibling %d: %p", idx, | 152 | return &c->node; |
210 | container, dir, desired, desired_con); | ||
211 | return seat_get_focus_inactive_view(seat, desired_con); | ||
212 | } | 153 | } |
213 | } | 154 | } |
214 | 155 | ||
215 | if (!can_move) { | 156 | current = current->parent; |
216 | container = parent; | ||
217 | parent = parent->parent; | ||
218 | if (!parent) { | ||
219 | // wrapping is the last chance | ||
220 | if (!wrap_candidate) { | ||
221 | return NULL; | ||
222 | } | ||
223 | return seat_get_focus_inactive_view(seat, wrap_candidate); | ||
224 | } | ||
225 | } | ||
226 | } | 157 | } |
227 | } | ||
228 | 158 | ||
229 | static struct cmd_results *focus_mode(struct sway_container *con, | 159 | // Check a different output |
230 | struct sway_seat *seat, bool floating) { | 160 | struct sway_output *output = container->workspace->output; |
231 | struct sway_container *ws = con->type == C_WORKSPACE ? | 161 | struct sway_output *new_output = output_get_in_direction(output, dir); |
232 | con : container_parent(con, C_WORKSPACE); | 162 | if (new_output) { |
233 | 163 | return get_node_in_output_direction(new_output, dir); | |
234 | // If the container is in a floating split container, | ||
235 | // operate on the split container instead of the child. | ||
236 | if (container_is_floating_or_child(con)) { | ||
237 | while (con->parent->type != C_WORKSPACE) { | ||
238 | con = con->parent; | ||
239 | } | ||
240 | } | 164 | } |
165 | return NULL; | ||
166 | } | ||
241 | 167 | ||
168 | static struct cmd_results *focus_mode(struct sway_workspace *ws, | ||
169 | struct sway_seat *seat, bool floating) { | ||
242 | struct sway_container *new_focus = NULL; | 170 | struct sway_container *new_focus = NULL; |
243 | if (floating) { | 171 | if (floating) { |
244 | new_focus = seat_get_focus_inactive_floating(seat, ws); | 172 | new_focus = seat_get_focus_inactive_floating(seat, ws); |
@@ -246,7 +174,7 @@ static struct cmd_results *focus_mode(struct sway_container *con, | |||
246 | new_focus = seat_get_focus_inactive_tiling(seat, ws); | 174 | new_focus = seat_get_focus_inactive_tiling(seat, ws); |
247 | } | 175 | } |
248 | if (new_focus) { | 176 | if (new_focus) { |
249 | seat_set_focus(seat, new_focus); | 177 | seat_set_focus(seat, &new_focus->node); |
250 | } else { | 178 | } else { |
251 | return cmd_results_new(CMD_FAILURE, "focus", | 179 | return cmd_results_new(CMD_FAILURE, "focus", |
252 | "Failed to find a %s container in workspace", | 180 | "Failed to find a %s container in workspace", |
@@ -255,14 +183,14 @@ static struct cmd_results *focus_mode(struct sway_container *con, | |||
255 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 183 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
256 | } | 184 | } |
257 | 185 | ||
258 | static struct cmd_results *focus_output(struct sway_container *con, | 186 | static struct cmd_results *focus_output(struct sway_seat *seat, |
259 | struct sway_seat *seat, int argc, char **argv) { | 187 | int argc, char **argv) { |
260 | if (!argc) { | 188 | if (!argc) { |
261 | return cmd_results_new(CMD_INVALID, "focus", | 189 | return cmd_results_new(CMD_INVALID, "focus", |
262 | "Expected 'focus output <direction|name>'"); | 190 | "Expected 'focus output <direction|name>'"); |
263 | } | 191 | } |
264 | char *identifier = join_args(argv, argc); | 192 | char *identifier = join_args(argv, argc); |
265 | struct sway_container *output = output_by_name(identifier); | 193 | struct sway_output *output = output_by_name(identifier); |
266 | 194 | ||
267 | if (!output) { | 195 | if (!output) { |
268 | enum movement_direction direction; | 196 | enum movement_direction direction; |
@@ -272,14 +200,13 @@ static struct cmd_results *focus_output(struct sway_container *con, | |||
272 | return cmd_results_new(CMD_INVALID, "focus", | 200 | return cmd_results_new(CMD_INVALID, "focus", |
273 | "There is no output with that name"); | 201 | "There is no output with that name"); |
274 | } | 202 | } |
275 | struct sway_container *focus = seat_get_focus(seat); | 203 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
276 | focus = container_parent(focus, C_OUTPUT); | 204 | output = output_get_in_direction(ws->output, direction); |
277 | output = container_get_in_direction(focus, seat, direction); | ||
278 | } | 205 | } |
279 | 206 | ||
280 | free(identifier); | 207 | free(identifier); |
281 | if (output) { | 208 | if (output) { |
282 | seat_set_focus(seat, seat_get_focus_inactive(seat, output)); | 209 | seat_set_focus(seat, seat_get_focus_inactive(seat, &output->node)); |
283 | } | 210 | } |
284 | 211 | ||
285 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 212 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
@@ -289,29 +216,32 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
289 | if (config->reading || !config->active) { | 216 | if (config->reading || !config->active) { |
290 | return cmd_results_new(CMD_DEFER, NULL, NULL); | 217 | return cmd_results_new(CMD_DEFER, NULL, NULL); |
291 | } | 218 | } |
292 | struct sway_container *con = config->handler_context.current_container; | 219 | struct sway_node *node = config->handler_context.node; |
220 | struct sway_container *container = config->handler_context.container; | ||
221 | struct sway_workspace *workspace = config->handler_context.workspace; | ||
293 | struct sway_seat *seat = config->handler_context.seat; | 222 | struct sway_seat *seat = config->handler_context.seat; |
294 | if (con->type < C_WORKSPACE) { | 223 | if (node->type < N_WORKSPACE) { |
295 | return cmd_results_new(CMD_FAILURE, "focus", | 224 | return cmd_results_new(CMD_FAILURE, "focus", |
296 | "Command 'focus' cannot be used above the workspace level"); | 225 | "Command 'focus' cannot be used above the workspace level"); |
297 | } | 226 | } |
298 | 227 | ||
299 | if (argc == 0) { | 228 | if (argc == 0) { |
300 | seat_set_focus(seat, con); | 229 | seat_set_focus(seat, node); |
301 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 230 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
302 | } | 231 | } |
303 | 232 | ||
304 | if (strcmp(argv[0], "floating") == 0) { | 233 | if (strcmp(argv[0], "floating") == 0) { |
305 | return focus_mode(con, seat, true); | 234 | return focus_mode(workspace, seat, true); |
306 | } else if (strcmp(argv[0], "tiling") == 0) { | 235 | } else if (strcmp(argv[0], "tiling") == 0) { |
307 | return focus_mode(con, seat, false); | 236 | return focus_mode(workspace, seat, false); |
308 | } else if (strcmp(argv[0], "mode_toggle") == 0) { | 237 | } else if (strcmp(argv[0], "mode_toggle") == 0) { |
309 | return focus_mode(con, seat, !container_is_floating_or_child(con)); | 238 | bool floating = container && container_is_floating_or_child(container); |
239 | return focus_mode(workspace, seat, !floating); | ||
310 | } | 240 | } |
311 | 241 | ||
312 | if (strcmp(argv[0], "output") == 0) { | 242 | if (strcmp(argv[0], "output") == 0) { |
313 | argc--; argv++; | 243 | argc--; argv++; |
314 | return focus_output(con, seat, argc, argv); | 244 | return focus_output(seat, argc, argv); |
315 | } | 245 | } |
316 | 246 | ||
317 | enum movement_direction direction = 0; | 247 | enum movement_direction direction = 0; |
@@ -321,8 +251,18 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
321 | "or 'focus output <direction|name>'"); | 251 | "or 'focus output <direction|name>'"); |
322 | } | 252 | } |
323 | 253 | ||
324 | struct sway_container *next_focus = container_get_in_direction( | 254 | if (node->type == N_WORKSPACE) { |
325 | con, seat, direction); | 255 | // A workspace is focused, so just jump to the next output |
256 | struct sway_output *new_output = | ||
257 | output_get_in_direction(workspace->output, direction); | ||
258 | struct sway_node *node = | ||
259 | get_node_in_output_direction(new_output, direction); | ||
260 | seat_set_focus(seat, node); | ||
261 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
262 | } | ||
263 | |||
264 | struct sway_node *next_focus = | ||
265 | node_get_in_direction(container, seat, direction); | ||
326 | if (next_focus) { | 266 | if (next_focus) { |
327 | seat_set_focus(seat, next_focus); | 267 | seat_set_focus(seat, next_focus); |
328 | } | 268 | } |
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index ac65dffb..3bbe00c5 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c | |||
@@ -12,18 +12,18 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
12 | if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) { | 12 | if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) { |
13 | return error; | 13 | return error; |
14 | } | 14 | } |
15 | struct sway_container *container = | 15 | struct sway_node *node = config->handler_context.node; |
16 | config->handler_context.current_container; | 16 | struct sway_container *container = config->handler_context.container; |
17 | if (container->type == C_WORKSPACE && container->children->length == 0) { | 17 | struct sway_workspace *workspace = config->handler_context.workspace; |
18 | if (node->type == N_WORKSPACE && workspace->tiling->length == 0) { | ||
18 | return cmd_results_new(CMD_INVALID, "fullscreen", | 19 | return cmd_results_new(CMD_INVALID, "fullscreen", |
19 | "Can't fullscreen an empty workspace"); | 20 | "Can't fullscreen an empty workspace"); |
20 | } | 21 | } |
21 | if (container->type == C_WORKSPACE) { | 22 | if (node->type == N_WORKSPACE) { |
22 | // Wrap the workspace's children in a container so we can fullscreen it | 23 | // Wrap the workspace's children in a container so we can fullscreen it |
23 | struct sway_container *workspace = container; | 24 | container = workspace_wrap_children(workspace); |
24 | container = workspace_wrap_children(container); | ||
25 | workspace->layout = L_HORIZ; | 25 | workspace->layout = L_HORIZ; |
26 | seat_set_focus(config->handler_context.seat, container); | 26 | seat_set_focus(config->handler_context.seat, &container->node); |
27 | } | 27 | } |
28 | bool enable = !container->is_fullscreen; | 28 | bool enable = !container->is_fullscreen; |
29 | 29 | ||
@@ -32,9 +32,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | container_set_fullscreen(container, enable); | 34 | container_set_fullscreen(container, enable); |
35 | 35 | arrange_workspace(workspace); | |
36 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | ||
37 | arrange_windows(workspace->parent); | ||
38 | 36 | ||
39 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 37 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
40 | } | 38 | } |
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 3906eb70..d676e475 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/tree/arrange.h" | 4 | #include "sway/tree/arrange.h" |
5 | #include "sway/tree/workspace.h" | ||
5 | #include "log.h" | 6 | #include "log.h" |
6 | #include "stringop.h" | 7 | #include "stringop.h" |
7 | #include <math.h> | 8 | #include <math.h> |
@@ -43,7 +44,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { | |||
43 | return cmd_results_new(CMD_INVALID, "gaps", | 44 | return cmd_results_new(CMD_INVALID, "gaps", |
44 | "gaps edge_gaps on|off|toggle"); | 45 | "gaps edge_gaps on|off|toggle"); |
45 | } | 46 | } |
46 | arrange_windows(&root_container); | 47 | arrange_root(); |
47 | } else { | 48 | } else { |
48 | int amount_idx = 0; // the current index in argv | 49 | int amount_idx = 0; // the current index in argv |
49 | enum gaps_op op = GAPS_OP_SET; | 50 | enum gaps_op op = GAPS_OP_SET; |
@@ -124,7 +125,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { | |||
124 | if (amount_idx == 0) { // gaps <amount> | 125 | if (amount_idx == 0) { // gaps <amount> |
125 | config->gaps_inner = val; | 126 | config->gaps_inner = val; |
126 | config->gaps_outer = val; | 127 | config->gaps_outer = val; |
127 | arrange_windows(&root_container); | 128 | arrange_root(); |
128 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 129 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
129 | } | 130 | } |
130 | // Other variants. The middle-length variant (gaps inner|outer <amount>) | 131 | // Other variants. The middle-length variant (gaps inner|outer <amount>) |
@@ -155,21 +156,27 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { | |||
155 | } else { | 156 | } else { |
156 | config->gaps_outer = total; | 157 | config->gaps_outer = total; |
157 | } | 158 | } |
158 | arrange_windows(&root_container); | 159 | arrange_root(); |
159 | } else { | 160 | } else { |
160 | struct sway_container *c = | 161 | if (scope == GAPS_SCOPE_WORKSPACE) { |
161 | config->handler_context.current_container; | 162 | struct sway_workspace *ws = config->handler_context.workspace; |
162 | if (scope == GAPS_SCOPE_WORKSPACE && c->type != C_WORKSPACE) { | 163 | ws->has_gaps = true; |
163 | c = container_parent(c, C_WORKSPACE); | 164 | if (inner) { |
164 | } | 165 | ws->gaps_inner = total; |
165 | c->has_gaps = true; | 166 | } else { |
166 | if (inner) { | 167 | ws->gaps_outer = total; |
167 | c->gaps_inner = total; | 168 | } |
169 | arrange_workspace(ws); | ||
168 | } else { | 170 | } else { |
169 | c->gaps_outer = total; | 171 | struct sway_container *c = config->handler_context.container; |
172 | c->has_gaps = true; | ||
173 | if (inner) { | ||
174 | c->gaps_inner = total; | ||
175 | } else { | ||
176 | c->gaps_outer = total; | ||
177 | } | ||
178 | arrange_workspace(c->workspace); | ||
170 | } | 179 | } |
171 | |||
172 | arrange_windows(c->parent ? c->parent : &root_container); | ||
173 | } | 180 | } |
174 | } | 181 | } |
175 | 182 | ||
diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c index e494f6aa..0a5c7f28 100644 --- a/sway/commands/hide_edge_borders.c +++ b/sway/commands/hide_edge_borders.c | |||
@@ -5,8 +5,8 @@ | |||
5 | #include "sway/tree/view.h" | 5 | #include "sway/tree/view.h" |
6 | 6 | ||
7 | static void _configure_view(struct sway_container *con, void *data) { | 7 | static void _configure_view(struct sway_container *con, void *data) { |
8 | if (con->type == C_VIEW) { | 8 | if (con->view) { |
9 | view_autoconfigure(con->sway_view); | 9 | view_autoconfigure(con->view); |
10 | } | 10 | } |
11 | } | 11 | } |
12 | 12 | ||
diff --git a/sway/commands/kill.c b/sway/commands/kill.c index f3fa52f1..85ca0f33 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c | |||
@@ -2,15 +2,27 @@ | |||
2 | #include "log.h" | 2 | #include "log.h" |
3 | #include "sway/input/input-manager.h" | 3 | #include "sway/input/input-manager.h" |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | #include "sway/tree/view.h" | ||
6 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | ||
7 | #include "sway/tree/workspace.h" | ||
7 | #include "sway/commands.h" | 8 | #include "sway/commands.h" |
8 | 9 | ||
10 | static void close_container_iterator(struct sway_container *con, void *data) { | ||
11 | if (con->view) { | ||
12 | view_close(con->view); | ||
13 | } | ||
14 | } | ||
15 | |||
9 | struct cmd_results *cmd_kill(int argc, char **argv) { | 16 | struct cmd_results *cmd_kill(int argc, char **argv) { |
10 | struct sway_container *con = | 17 | struct sway_container *con = config->handler_context.container; |
11 | config->handler_context.current_container; | 18 | struct sway_workspace *ws = config->handler_context.workspace; |
12 | 19 | ||
13 | container_close(con); | 20 | if (con) { |
21 | close_container_iterator(con, NULL); | ||
22 | container_for_each_child(con, close_container_iterator, NULL); | ||
23 | } else { | ||
24 | workspace_for_each_container(ws, close_container_iterator, NULL); | ||
25 | } | ||
14 | 26 | ||
15 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 27 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
16 | } | 28 | } |
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index a06832de..8fa1ce98 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c | |||
@@ -4,21 +4,20 @@ | |||
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/tree/arrange.h" | 5 | #include "sway/tree/arrange.h" |
6 | #include "sway/tree/container.h" | 6 | #include "sway/tree/container.h" |
7 | #include "sway/tree/workspace.h" | ||
7 | #include "log.h" | 8 | #include "log.h" |
8 | 9 | ||
9 | static bool parse_layout_string(char *s, enum sway_container_layout *ptr) { | 10 | static enum sway_container_layout parse_layout_string(char *s) { |
10 | if (strcasecmp(s, "splith") == 0) { | 11 | if (strcasecmp(s, "splith") == 0) { |
11 | *ptr = L_HORIZ; | 12 | return L_HORIZ; |
12 | } else if (strcasecmp(s, "splitv") == 0) { | 13 | } else if (strcasecmp(s, "splitv") == 0) { |
13 | *ptr = L_VERT; | 14 | return L_VERT; |
14 | } else if (strcasecmp(s, "tabbed") == 0) { | 15 | } else if (strcasecmp(s, "tabbed") == 0) { |
15 | *ptr = L_TABBED; | 16 | return L_TABBED; |
16 | } else if (strcasecmp(s, "stacking") == 0) { | 17 | } else if (strcasecmp(s, "stacking") == 0) { |
17 | *ptr = L_STACKED; | 18 | return L_STACKED; |
18 | } else { | ||
19 | return false; | ||
20 | } | 19 | } |
21 | return true; | 20 | return L_NONE; |
22 | } | 21 | } |
23 | 22 | ||
24 | static const char* expected_syntax = | 23 | static const char* expected_syntax = |
@@ -26,84 +25,129 @@ static const char* expected_syntax = | |||
26 | "'layout toggle [split|all]' or " | 25 | "'layout toggle [split|all]' or " |
27 | "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; | 26 | "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; |
28 | 27 | ||
28 | static enum sway_container_layout get_layout_toggle(int argc, char **argv, | ||
29 | enum sway_container_layout layout, | ||
30 | enum sway_container_layout prev_split_layout) { | ||
31 | // "layout toggle" | ||
32 | if (argc == 0) { | ||
33 | return layout == L_HORIZ ? L_VERT : L_HORIZ; | ||
34 | } | ||
35 | |||
36 | if (argc == 2) { | ||
37 | // "layout toggle split" (same as "layout toggle") | ||
38 | if (strcasecmp(argv[1], "split") == 0) { | ||
39 | return layout == L_HORIZ ? L_VERT : L_HORIZ; | ||
40 | } | ||
41 | // "layout toggle all" | ||
42 | if (strcasecmp(argv[1], "all") == 0) { | ||
43 | return layout == L_HORIZ ? L_VERT : | ||
44 | layout == L_VERT ? L_STACKED : | ||
45 | layout == L_STACKED ? L_TABBED : L_HORIZ; | ||
46 | } | ||
47 | return L_NONE; | ||
48 | } | ||
49 | |||
50 | enum sway_container_layout parsed; | ||
51 | int curr = 1; | ||
52 | for (; curr < argc; curr++) { | ||
53 | parsed = parse_layout_string(argv[curr]); | ||
54 | if (parsed == layout || (strcmp(argv[curr], "split") == 0 && | ||
55 | (layout == L_VERT || layout == L_HORIZ))) { | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | for (int i = curr + 1; i != curr; ++i) { | ||
60 | // cycle round to find next valid layout | ||
61 | if (i >= argc) { | ||
62 | i = 1; | ||
63 | } | ||
64 | parsed = parse_layout_string(argv[i]); | ||
65 | if (parsed != L_NONE) { | ||
66 | return parsed; | ||
67 | } | ||
68 | if (strcmp(argv[i], "split") == 0) { | ||
69 | return layout == L_HORIZ ? L_VERT : | ||
70 | layout == L_VERT ? L_HORIZ : prev_split_layout; | ||
71 | } | ||
72 | // invalid layout strings are silently ignored | ||
73 | } | ||
74 | return L_NONE; | ||
75 | } | ||
76 | |||
77 | static enum sway_container_layout get_layout(int argc, char **argv, | ||
78 | enum sway_container_layout layout, | ||
79 | enum sway_container_layout prev_split_layout) { | ||
80 | // Check if assigned directly | ||
81 | enum sway_container_layout parsed = parse_layout_string(argv[0]); | ||
82 | if (parsed != L_NONE) { | ||
83 | return parsed; | ||
84 | } | ||
85 | |||
86 | if (strcasecmp(argv[0], "default") == 0) { | ||
87 | return prev_split_layout; | ||
88 | } | ||
89 | |||
90 | if (strcasecmp(argv[0], "toggle") == 0) { | ||
91 | argc--; argv++; | ||
92 | return get_layout_toggle(argc, argv, layout, prev_split_layout); | ||
93 | } | ||
94 | |||
95 | return L_NONE; | ||
96 | } | ||
97 | |||
29 | struct cmd_results *cmd_layout(int argc, char **argv) { | 98 | struct cmd_results *cmd_layout(int argc, char **argv) { |
30 | struct cmd_results *error = NULL; | 99 | struct cmd_results *error = NULL; |
31 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { | 100 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { |
32 | return error; | 101 | return error; |
33 | } | 102 | } |
34 | struct sway_container *parent = config->handler_context.current_container; | 103 | struct sway_container *container = config->handler_context.container; |
104 | struct sway_workspace *workspace = config->handler_context.workspace; | ||
35 | 105 | ||
36 | if (container_is_floating(parent)) { | 106 | if (container && container_is_floating(container)) { |
37 | return cmd_results_new(CMD_FAILURE, "layout", | 107 | return cmd_results_new(CMD_FAILURE, "layout", |
38 | "Unable to change layout of floating windows"); | 108 | "Unable to change layout of floating windows"); |
39 | } | 109 | } |
40 | 110 | ||
41 | while (parent->type == C_VIEW) { | 111 | // Typically we change the layout of the current container, but if the |
42 | parent = parent->parent; | 112 | // current container is a view (it usually is) then we'll change the layout |
113 | // of the parent instead, as it doesn't make sense for views to have layout. | ||
114 | if (container && container->view) { | ||
115 | container = container->parent; | ||
43 | } | 116 | } |
44 | 117 | ||
45 | enum sway_container_layout prev = parent->layout; | 118 | // We could be working with a container OR a workspace. These are different |
46 | bool assigned_directly = parse_layout_string(argv[0], &parent->layout); | 119 | // structures, so we set up pointers to they layouts so we can refer them in |
47 | if (!assigned_directly) { | 120 | // an abstract way. |
48 | if (strcasecmp(argv[0], "default") == 0) { | 121 | enum sway_container_layout new_layout = L_NONE; |
49 | parent->layout = parent->prev_split_layout; | 122 | enum sway_container_layout old_layout = L_NONE; |
50 | } else if (strcasecmp(argv[0], "toggle") == 0) { | 123 | if (container) { |
51 | if (argc == 1) { | 124 | old_layout = container->layout; |
52 | parent->layout = | 125 | new_layout = get_layout(argc, argv, |
53 | parent->layout == L_STACKED ? L_TABBED : | 126 | container->layout, container->prev_split_layout); |
54 | parent->layout == L_TABBED ? parent->prev_split_layout : L_STACKED; | 127 | } else { |
55 | } else if (argc == 2) { | 128 | old_layout = workspace->layout; |
56 | if (strcasecmp(argv[1], "all") == 0) { | 129 | new_layout = get_layout(argc, argv, |
57 | parent->layout = | 130 | workspace->layout, workspace->prev_split_layout); |
58 | parent->layout == L_HORIZ ? L_VERT : | ||
59 | parent->layout == L_VERT ? L_STACKED : | ||
60 | parent->layout == L_STACKED ? L_TABBED : L_HORIZ; | ||
61 | } else if (strcasecmp(argv[1], "split") == 0) { | ||
62 | parent->layout = | ||
63 | parent->layout == L_HORIZ ? L_VERT : | ||
64 | parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; | ||
65 | } else { | ||
66 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); | ||
67 | } | ||
68 | } else { | ||
69 | enum sway_container_layout parsed_layout; | ||
70 | int curr = 1; | ||
71 | for (; curr < argc; curr++) { | ||
72 | bool valid = parse_layout_string(argv[curr], &parsed_layout); | ||
73 | if ((valid && parsed_layout == parent->layout) || | ||
74 | (strcmp(argv[curr], "split") == 0 && | ||
75 | (parent->layout == L_VERT || parent->layout == L_HORIZ))) { | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | for (int i = curr + 1; i != curr; ++i) { | ||
80 | // cycle round to find next valid layout | ||
81 | if (i >= argc) { | ||
82 | i = 1; | ||
83 | } | ||
84 | if (parse_layout_string(argv[i], &parent->layout)) { | ||
85 | break; | ||
86 | } else if (strcmp(argv[i], "split") == 0) { | ||
87 | parent->layout = | ||
88 | parent->layout == L_HORIZ ? L_VERT : | ||
89 | parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; | ||
90 | break; | ||
91 | } // invalid layout strings are silently ignored | ||
92 | } | ||
93 | } | ||
94 | } else { | ||
95 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); | ||
96 | } | ||
97 | } | 131 | } |
98 | if (parent->layout == L_NONE) { | 132 | if (new_layout == L_NONE) { |
99 | parent->layout = container_get_default_layout(parent); | 133 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); |
100 | } | 134 | } |
101 | if (prev != parent->layout) { | 135 | if (new_layout != old_layout) { |
102 | if (prev != L_TABBED && prev != L_STACKED) { | 136 | if (container) { |
103 | parent->prev_split_layout = prev; | 137 | if (old_layout != L_TABBED && old_layout != L_STACKED) { |
138 | container->prev_split_layout = old_layout; | ||
139 | } | ||
140 | container->layout = new_layout; | ||
141 | container_update_representation(container); | ||
142 | arrange_container(container); | ||
143 | } else { | ||
144 | if (old_layout != L_TABBED && old_layout != L_STACKED) { | ||
145 | workspace->prev_split_layout = old_layout; | ||
146 | } | ||
147 | workspace->layout = new_layout; | ||
148 | workspace_update_representation(workspace); | ||
149 | arrange_workspace(workspace); | ||
104 | } | 150 | } |
105 | container_notify_subtree_changed(parent); | ||
106 | arrange_windows(parent->parent); | ||
107 | } | 151 | } |
108 | 152 | ||
109 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 153 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/mark.c b/sway/commands/mark.c index 9ea8c301..fb95a7d0 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c | |||
@@ -18,13 +18,12 @@ struct cmd_results *cmd_mark(int argc, char **argv) { | |||
18 | if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { | 18 | if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { |
19 | return error; | 19 | return error; |
20 | } | 20 | } |
21 | struct sway_container *container = | 21 | struct sway_container *container = config->handler_context.container; |
22 | config->handler_context.current_container; | 22 | if (!container->view) { |
23 | if (container->type != C_VIEW) { | ||
24 | return cmd_results_new(CMD_INVALID, "mark", | 23 | return cmd_results_new(CMD_INVALID, "mark", |
25 | "Only views can have marks"); | 24 | "Only views can have marks"); |
26 | } | 25 | } |
27 | struct sway_view *view = container->sway_view; | 26 | struct sway_view *view = container->view; |
28 | 27 | ||
29 | bool add = false, toggle = false; | 28 | bool add = false, toggle = false; |
30 | while (argc > 0 && strncmp(*argv, "--", 2) == 0) { | 29 | while (argc > 0 && strncmp(*argv, "--", 2) == 0) { |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 4426f24e..1b2e830c 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -40,7 +40,7 @@ enum wlr_direction opposite_direction(enum wlr_direction d) { | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | static struct sway_container *output_in_direction(const char *direction_string, | 43 | static struct sway_output *output_in_direction(const char *direction_string, |
44 | struct wlr_output *reference, int ref_lx, int ref_ly) { | 44 | struct wlr_output *reference, int ref_lx, int ref_ly) { |
45 | struct { | 45 | struct { |
46 | char *name; | 46 | char *name; |
@@ -63,447 +63,367 @@ static struct sway_container *output_in_direction(const char *direction_string, | |||
63 | 63 | ||
64 | if (direction) { | 64 | if (direction) { |
65 | struct wlr_output *target = wlr_output_layout_adjacent_output( | 65 | struct wlr_output *target = wlr_output_layout_adjacent_output( |
66 | root_container.sway_root->output_layout, | 66 | root->output_layout, direction, reference, ref_lx, ref_ly); |
67 | direction, reference, ref_lx, ref_ly); | ||
68 | 67 | ||
69 | if (!target) { | 68 | if (!target) { |
70 | target = wlr_output_layout_farthest_output( | 69 | target = wlr_output_layout_farthest_output( |
71 | root_container.sway_root->output_layout, | 70 | root->output_layout, opposite_direction(direction), |
72 | opposite_direction(direction), reference, ref_lx, ref_ly); | 71 | reference, ref_lx, ref_ly); |
73 | } | 72 | } |
74 | 73 | ||
75 | if (target) { | 74 | if (target) { |
76 | struct sway_output *sway_output = target->data; | 75 | return target->data; |
77 | return sway_output->swayc; | ||
78 | } | 76 | } |
79 | } | 77 | } |
80 | 78 | ||
81 | return output_by_name(direction_string); | 79 | return output_by_name(direction_string); |
82 | } | 80 | } |
83 | 81 | ||
84 | static void container_move_to(struct sway_container *container, | 82 | static bool is_parallel(enum sway_container_layout layout, |
85 | struct sway_container *destination) { | 83 | enum movement_direction dir) { |
86 | if (!sway_assert(container->type == C_CONTAINER || | 84 | switch (layout) { |
87 | container->type == C_VIEW, "Expected a container or view")) { | 85 | case L_TABBED: |
88 | return; | 86 | case L_HORIZ: |
87 | return dir == MOVE_LEFT || dir == MOVE_RIGHT; | ||
88 | case L_STACKED: | ||
89 | case L_VERT: | ||
90 | return dir == MOVE_UP || dir == MOVE_DOWN; | ||
91 | default: | ||
92 | return false; | ||
89 | } | 93 | } |
90 | if (container == destination | 94 | } |
91 | || container_has_ancestor(container, destination)) { | 95 | |
96 | /** | ||
97 | * Ensures all seats focus the fullscreen container if needed. | ||
98 | */ | ||
99 | static void workspace_focus_fullscreen(struct sway_workspace *workspace) { | ||
100 | if (!workspace->fullscreen) { | ||
92 | return; | 101 | return; |
93 | } | 102 | } |
94 | struct sway_container *old_parent = NULL; | 103 | struct sway_seat *seat; |
95 | struct sway_container *new_parent = NULL; | 104 | struct sway_workspace *focus_ws; |
96 | if (container_is_floating(container)) { | 105 | wl_list_for_each(seat, &input_manager->seats, link) { |
97 | // Resolve destination into a workspace | 106 | focus_ws = seat_get_focused_workspace(seat); |
98 | struct sway_container *new_ws = NULL; | 107 | if (focus_ws == workspace) { |
99 | if (destination->type == C_OUTPUT) { | 108 | struct sway_node *new_focus = |
100 | new_ws = output_get_active_workspace(destination->sway_output); | 109 | seat_get_focus_inactive(seat, &workspace->fullscreen->node); |
101 | } else if (destination->type == C_WORKSPACE) { | 110 | seat_set_focus(seat, new_focus); |
102 | new_ws = destination; | ||
103 | } else { | ||
104 | new_ws = container_parent(destination, C_WORKSPACE); | ||
105 | } | 111 | } |
106 | if (!new_ws) { | 112 | } |
107 | // This can happen if the user has run "move container to mark foo", | 113 | } |
108 | // where mark foo is on a hidden scratchpad container. | 114 | |
109 | return; | 115 | static void container_move_to_container_from_direction( |
116 | struct sway_container *container, struct sway_container *destination, | ||
117 | enum movement_direction move_dir) { | ||
118 | if (destination->view) { | ||
119 | if (destination->parent == container->parent) { | ||
120 | wlr_log(WLR_DEBUG, "Swapping siblings"); | ||
121 | list_t *siblings = container_get_siblings(container); | ||
122 | int container_index = list_find(siblings, container); | ||
123 | int destination_index = list_find(siblings, destination); | ||
124 | list_swap(siblings, container_index, destination_index); | ||
125 | } else { | ||
126 | wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); | ||
127 | int offset = move_dir == MOVE_LEFT || move_dir == MOVE_UP; | ||
128 | int index = container_sibling_index(destination) + offset; | ||
129 | if (destination->parent) { | ||
130 | container_insert_child(destination->parent, container, index); | ||
131 | } else { | ||
132 | workspace_insert_tiling(destination->workspace, | ||
133 | container, index); | ||
134 | } | ||
135 | container->width = container->height = 0; | ||
110 | } | 136 | } |
111 | struct sway_container *old_output = | 137 | return; |
112 | container_parent(container, C_OUTPUT); | 138 | } |
113 | old_parent = container_remove_child(container); | 139 | |
114 | workspace_add_floating(new_ws, container); | 140 | if (is_parallel(destination->layout, move_dir)) { |
115 | container_handle_fullscreen_reparent(container, old_parent); | 141 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); |
142 | int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? | ||
143 | 0 : destination->children->length; | ||
144 | container_insert_child(destination, container, index); | ||
145 | container->width = container->height = 0; | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); | ||
150 | struct sway_node *focus_inactive = seat_get_active_child( | ||
151 | config->handler_context.seat, &destination->node); | ||
152 | if (!focus_inactive || focus_inactive == &destination->node) { | ||
153 | // The container has no children | ||
154 | container_add_child(destination, container); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | // Try again but with the child | ||
159 | container_move_to_container_from_direction(container, | ||
160 | focus_inactive->sway_container, move_dir); | ||
161 | } | ||
162 | |||
163 | static void container_move_to_workspace_from_direction( | ||
164 | struct sway_container *container, struct sway_workspace *workspace, | ||
165 | enum movement_direction move_dir) { | ||
166 | if (is_parallel(workspace->layout, move_dir)) { | ||
167 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); | ||
168 | int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? | ||
169 | 0 : workspace->tiling->length; | ||
170 | workspace_insert_tiling(workspace, container, index); | ||
171 | return; | ||
172 | } | ||
173 | |||
174 | wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); | ||
175 | struct sway_container *focus_inactive = seat_get_focus_inactive_tiling( | ||
176 | config->handler_context.seat, workspace); | ||
177 | if (!focus_inactive) { | ||
178 | // The workspace has no tiling children | ||
179 | workspace_add_tiling(workspace, container); | ||
180 | return; | ||
181 | } | ||
182 | while (focus_inactive->parent) { | ||
183 | focus_inactive = focus_inactive->parent; | ||
184 | } | ||
185 | container_move_to_container_from_direction(container, focus_inactive, | ||
186 | move_dir); | ||
187 | } | ||
188 | |||
189 | static void container_move_to_workspace(struct sway_container *container, | ||
190 | struct sway_workspace *workspace) { | ||
191 | if (container->workspace == workspace) { | ||
192 | return; | ||
193 | } | ||
194 | struct sway_workspace *old_workspace = container->workspace; | ||
195 | if (container_is_floating(container)) { | ||
196 | struct sway_output *old_output = container->workspace->output; | ||
197 | container_detach(container); | ||
198 | workspace_add_floating(workspace, container); | ||
199 | container_handle_fullscreen_reparent(container); | ||
116 | // If changing output, center it within the workspace | 200 | // If changing output, center it within the workspace |
117 | if (old_output != new_ws->parent && !container->is_fullscreen) { | 201 | if (old_output != workspace->output && !container->is_fullscreen) { |
118 | container_floating_move_to_center(container); | 202 | container_floating_move_to_center(container); |
119 | } | 203 | } |
120 | } else { | 204 | } else { |
121 | old_parent = container_remove_child(container); | 205 | container_detach(container); |
122 | container->width = container->height = 0; | 206 | container->width = container->height = 0; |
123 | container->saved_width = container->saved_height = 0; | 207 | container->saved_width = container->saved_height = 0; |
124 | 208 | workspace_add_tiling(workspace, container); | |
125 | if (destination->type == C_VIEW) { | 209 | container_update_representation(container); |
126 | new_parent = container_add_sibling(destination, container); | ||
127 | } else { | ||
128 | new_parent = destination; | ||
129 | container_add_child(destination, container); | ||
130 | } | ||
131 | } | 210 | } |
132 | 211 | if (container->view) { | |
133 | if (container->type == C_VIEW) { | ||
134 | ipc_event_window(container, "move"); | 212 | ipc_event_window(container, "move"); |
135 | } | 213 | } |
136 | container_notify_subtree_changed(old_parent); | 214 | workspace_detect_urgent(old_workspace); |
137 | container_notify_subtree_changed(new_parent); | 215 | workspace_detect_urgent(workspace); |
138 | 216 | workspace_focus_fullscreen(workspace); | |
139 | // If view was moved to a fullscreen workspace, refocus the fullscreen view | 217 | } |
140 | struct sway_container *new_workspace = container; | 218 | |
141 | if (new_workspace->type != C_WORKSPACE) { | 219 | static void container_move_to_container(struct sway_container *container, |
142 | new_workspace = container_parent(new_workspace, C_WORKSPACE); | 220 | struct sway_container *destination) { |
143 | } | 221 | if (container == destination |
144 | if (new_workspace->sway_workspace->fullscreen) { | 222 | || container_has_ancestor(container, destination) |
145 | struct sway_seat *seat; | 223 | || container_has_ancestor(destination, container)) { |
146 | struct sway_container *focus, *focus_ws; | 224 | return; |
147 | wl_list_for_each(seat, &input_manager->seats, link) { | ||
148 | focus = seat_get_focus(seat); | ||
149 | focus_ws = focus; | ||
150 | if (focus_ws->type != C_WORKSPACE) { | ||
151 | focus_ws = container_parent(focus_ws, C_WORKSPACE); | ||
152 | } | ||
153 | if (focus_ws == new_workspace) { | ||
154 | struct sway_container *new_focus = seat_get_focus_inactive(seat, | ||
155 | new_workspace->sway_workspace->fullscreen); | ||
156 | seat_set_focus(seat, new_focus); | ||
157 | } | ||
158 | } | ||
159 | } | 225 | } |
160 | // Update workspace urgent state | 226 | if (container_is_floating(container)) { |
161 | struct sway_container *old_workspace = old_parent; | 227 | return; |
162 | if (old_workspace->type != C_WORKSPACE) { | ||
163 | old_workspace = container_parent(old_workspace, C_WORKSPACE); | ||
164 | } | ||
165 | if (new_workspace != old_workspace) { | ||
166 | workspace_detect_urgent(new_workspace); | ||
167 | if (old_workspace) { | ||
168 | workspace_detect_urgent(old_workspace); | ||
169 | } | ||
170 | } | 228 | } |
171 | } | 229 | struct sway_workspace *old_workspace = container->workspace; |
172 | 230 | ||
173 | static bool is_parallel(enum sway_container_layout layout, | 231 | container_detach(container); |
174 | enum movement_direction dir) { | 232 | container->width = container->height = 0; |
175 | switch (layout) { | 233 | container->saved_width = container->saved_height = 0; |
176 | case L_TABBED: | 234 | |
177 | case L_HORIZ: | 235 | if (destination->view) { |
178 | return dir == MOVE_LEFT || dir == MOVE_RIGHT; | 236 | container_add_sibling(destination, container, 1); |
179 | case L_STACKED: | 237 | } else { |
180 | case L_VERT: | 238 | container_add_child(destination, container); |
181 | return dir == MOVE_UP || dir == MOVE_DOWN; | ||
182 | default: | ||
183 | return false; | ||
184 | } | 239 | } |
185 | } | ||
186 | 240 | ||
187 | static enum movement_direction invert_movement(enum movement_direction dir) { | 241 | if (container->view) { |
188 | switch (dir) { | 242 | ipc_event_window(container, "move"); |
189 | case MOVE_LEFT: | ||
190 | return MOVE_RIGHT; | ||
191 | case MOVE_RIGHT: | ||
192 | return MOVE_LEFT; | ||
193 | case MOVE_UP: | ||
194 | return MOVE_DOWN; | ||
195 | case MOVE_DOWN: | ||
196 | return MOVE_UP; | ||
197 | default: | ||
198 | sway_assert(0, "This function expects left|right|up|down"); | ||
199 | return MOVE_LEFT; | ||
200 | } | 243 | } |
201 | } | ||
202 | 244 | ||
203 | static int move_offs(enum movement_direction move_dir) { | 245 | workspace_focus_fullscreen(destination->workspace); |
204 | return move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; | ||
205 | } | ||
206 | 246 | ||
207 | /* Gets the index of the most extreme member based on the movement offset */ | 247 | // Update workspace urgent state |
208 | static int container_limit(struct sway_container *container, | 248 | workspace_detect_urgent(destination->workspace); |
209 | enum movement_direction move_dir) { | 249 | if (old_workspace != destination->workspace) { |
210 | return move_offs(move_dir) < 0 ? 0 : container->children->length; | 250 | workspace_detect_urgent(old_workspace); |
251 | } | ||
211 | } | 252 | } |
212 | 253 | ||
213 | /* Takes one child, sets it aside, wraps the rest of the children in a new | 254 | /* Takes one child, sets it aside, wraps the rest of the children in a new |
214 | * container, switches the layout of the workspace, and drops the child back in. | 255 | * container, switches the layout of the workspace, and drops the child back in. |
215 | * In other words, rejigger it. */ | 256 | * In other words, rejigger it. */ |
216 | static void workspace_rejigger(struct sway_container *ws, | 257 | static void workspace_rejigger(struct sway_workspace *ws, |
217 | struct sway_container *child, enum movement_direction move_dir) { | 258 | struct sway_container *child, enum movement_direction move_dir) { |
218 | struct sway_container *original_parent = child->parent; | 259 | if (!sway_assert(child->parent == NULL, "Expected a root child")) { |
219 | struct sway_container *new_parent = | 260 | return; |
220 | container_split(ws, ws->layout); | ||
221 | |||
222 | container_remove_child(child); | ||
223 | for (int i = 0; i < ws->children->length; ++i) { | ||
224 | struct sway_container *_child = ws->children->items[i]; | ||
225 | container_move_to(new_parent, _child); | ||
226 | } | 261 | } |
262 | container_detach(child); | ||
263 | workspace_wrap_children(ws); | ||
227 | 264 | ||
228 | int index = move_offs(move_dir); | 265 | int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1; |
229 | container_insert_child(ws, child, index < 0 ? 0 : 1); | 266 | workspace_insert_tiling(ws, child, index); |
230 | ws->layout = | 267 | ws->layout = |
231 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 268 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; |
232 | 269 | workspace_update_representation(ws); | |
233 | container_flatten(ws); | ||
234 | container_reap_empty(original_parent); | ||
235 | container_create_notify(new_parent); | ||
236 | } | 270 | } |
237 | 271 | ||
238 | static void move_out_of_tabs_stacks(struct sway_container *container, | 272 | static void move_out_of_tabs_stacks(struct sway_container *container, |
239 | struct sway_container *current, enum movement_direction move_dir, | 273 | struct sway_container *current, enum movement_direction move_dir, |
240 | int offs) { | 274 | int offs) { |
241 | if (container->parent == current->parent | 275 | enum sway_container_layout layout = move_dir == |
242 | && current->parent->children->length == 1) { | 276 | MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; |
243 | wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id); | 277 | list_t *siblings = container_get_siblings(container); |
244 | current->parent->layout = move_dir == | 278 | if (container == current && siblings->length == 1) { |
245 | MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 279 | wlr_log(WLR_DEBUG, "Changing layout of parent"); |
280 | if (container->parent) { | ||
281 | container->parent->layout = layout; | ||
282 | container_update_representation(container); | ||
283 | } else { | ||
284 | container->workspace->layout = layout; | ||
285 | workspace_update_representation(container->workspace); | ||
286 | } | ||
246 | return; | 287 | return; |
247 | } | 288 | } |
248 | 289 | ||
249 | wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); | 290 | wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); |
250 | bool is_workspace = current->parent->type == C_WORKSPACE; | 291 | if (container->parent) { |
251 | struct sway_container *new_parent = container_split(current->parent, | 292 | struct sway_container *new_parent = |
252 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); | 293 | container_split(current->parent, layout); |
253 | if (is_workspace) { | ||
254 | container_insert_child(new_parent->parent, container, offs < 0 ? 0 : 1); | ||
255 | } else { | ||
256 | container_insert_child(new_parent, container, offs < 0 ? 0 : 1); | 294 | container_insert_child(new_parent, container, offs < 0 ? 0 : 1); |
257 | container_reap_empty(new_parent->parent); | 295 | container_reap_empty(new_parent); |
258 | container_flatten(new_parent->parent); | 296 | container_flatten(new_parent); |
297 | } else { | ||
298 | // Changing a workspace | ||
299 | struct sway_workspace *workspace = container->workspace; | ||
300 | workspace_split(workspace, layout); | ||
301 | workspace_insert_tiling(workspace, container, offs < 0 ? 0 : 1); | ||
259 | } | 302 | } |
260 | container_create_notify(new_parent); | ||
261 | container_notify_subtree_changed(new_parent); | ||
262 | } | 303 | } |
263 | 304 | ||
264 | static void container_move(struct sway_container *container, | 305 | // Returns true if moved |
265 | enum movement_direction move_dir, int move_amt) { | 306 | static bool container_move_in_direction(struct sway_container *container, |
266 | if (!sway_assert( | 307 | enum movement_direction move_dir) { |
267 | container->type != C_CONTAINER || container->type != C_VIEW, | ||
268 | "Can only move containers and views")) { | ||
269 | return; | ||
270 | } | ||
271 | int offs = move_offs(move_dir); | ||
272 | |||
273 | struct sway_container *sibling = NULL; | ||
274 | struct sway_container *current = container; | ||
275 | struct sway_container *parent = current->parent; | ||
276 | struct sway_container *top = &root_container; | ||
277 | |||
278 | // If moving a fullscreen view, only consider outputs | 308 | // If moving a fullscreen view, only consider outputs |
279 | if (container->is_fullscreen) { | 309 | if (container->is_fullscreen) { |
280 | current = container_parent(container, C_OUTPUT); | 310 | struct sway_output *new_output = |
281 | } else if (container_is_fullscreen_or_child(container) || | 311 | output_get_in_direction(container->workspace->output, move_dir); |
282 | container_is_floating_or_child(container)) { | 312 | if (!new_output) { |
283 | // If we've fullscreened a split container, only allow the child to move | 313 | return false; |
284 | // around within the fullscreen parent. | 314 | } |
285 | // Same with floating a split container. | 315 | struct sway_workspace *ws = output_get_active_workspace(new_output); |
286 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | 316 | container_move_to_workspace(container, ws); |
287 | top = ws->sway_workspace->fullscreen; | 317 | return true; |
288 | } | ||
289 | |||
290 | struct sway_container *new_parent = container_flatten(parent); | ||
291 | if (new_parent != parent) { | ||
292 | // Special case: we were the last one in this container, so leave | ||
293 | return; | ||
294 | } | 318 | } |
295 | 319 | ||
296 | while (!sibling) { | 320 | // If container is in a split container by itself, move out of the split |
297 | if (current == top) { | 321 | if (container->parent) { |
298 | return; | 322 | struct sway_container *new_parent = |
323 | container_flatten(container->parent); | ||
324 | if (new_parent != container->parent) { | ||
325 | return true; | ||
299 | } | 326 | } |
327 | } | ||
300 | 328 | ||
301 | parent = current->parent; | 329 | // Look for a suitable *container* sibling or parent. |
302 | wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current, | 330 | // The below loop stops once we hit the workspace because current->parent |
303 | container_type_to_str(current->type), current->name); | 331 | // is NULL for the topmost containers in a workspace. |
304 | 332 | struct sway_container *current = container; | |
305 | int index = container_sibling_index(current); | 333 | int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; |
306 | 334 | ||
307 | switch (current->type) { | 335 | while (current) { |
308 | case C_OUTPUT: { | 336 | struct sway_container *parent = current->parent; |
309 | enum wlr_direction wlr_dir = 0; | 337 | list_t *siblings = container_get_siblings(current); |
310 | if (!sway_assert(sway_dir_to_wlr(move_dir, &wlr_dir), | 338 | enum sway_container_layout layout = container_parent_layout(current); |
311 | "got invalid direction: %d", move_dir)) { | 339 | int index = list_find(siblings, current); |
312 | return; | 340 | int desired = index + offs; |
313 | } | 341 | |
314 | double ref_lx = current->x + current->width / 2; | 342 | if (is_parallel(layout, move_dir)) { |
315 | double ref_ly = current->y + current->height / 2; | 343 | if (desired == -1 || desired == siblings->length) { |
316 | struct wlr_output *next = wlr_output_layout_adjacent_output( | 344 | if (current->parent == container->parent) { |
317 | root_container.sway_root->output_layout, wlr_dir, | 345 | if (!(parent && parent->is_fullscreen) && |
318 | current->sway_output->wlr_output, ref_lx, ref_ly); | 346 | (layout == L_TABBED || layout == L_STACKED)) { |
319 | if (!next) { | 347 | move_out_of_tabs_stacks(container, current, |
320 | wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); | 348 | move_dir, offs); |
321 | return; | 349 | return true; |
322 | } | ||
323 | struct sway_output *next_output = next->data; | ||
324 | current = next_output->swayc; | ||
325 | wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name); | ||
326 | // Select workspace and get outta here | ||
327 | current = seat_get_focus_inactive( | ||
328 | config->handler_context.seat, current); | ||
329 | if (current->type != C_WORKSPACE) { | ||
330 | current = container_parent(current, C_WORKSPACE); | ||
331 | } | ||
332 | sibling = current; | ||
333 | break; | ||
334 | } | ||
335 | case C_WORKSPACE: | ||
336 | if (!is_parallel(current->layout, move_dir)) { | ||
337 | if (current->children->length >= 2) { | ||
338 | wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)", | ||
339 | current->children->length); | ||
340 | workspace_rejigger(current, container, move_dir); | ||
341 | return; | ||
342 | } else { | ||
343 | wlr_log(WLR_DEBUG, "Selecting output"); | ||
344 | current = current->parent; | ||
345 | } | ||
346 | } else if (current->layout == L_TABBED | ||
347 | || current->layout == L_STACKED) { | ||
348 | wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks"); | ||
349 | workspace_rejigger(current, container, move_dir); | ||
350 | } else { | ||
351 | wlr_log(WLR_DEBUG, "Selecting output"); | ||
352 | current = current->parent; | ||
353 | } | ||
354 | break; | ||
355 | case C_CONTAINER: | ||
356 | case C_VIEW: | ||
357 | if (is_parallel(parent->layout, move_dir)) { | ||
358 | if ((index == parent->children->length - 1 && offs > 0) | ||
359 | || (index == 0 && offs < 0)) { | ||
360 | if (current->parent == container->parent) { | ||
361 | if (!parent->is_fullscreen && | ||
362 | (parent->layout == L_TABBED || | ||
363 | parent->layout == L_STACKED)) { | ||
364 | move_out_of_tabs_stacks(container, current, | ||
365 | move_dir, offs); | ||
366 | return; | ||
367 | } else { | ||
368 | wlr_log(WLR_DEBUG, "Hit limit, selecting parent"); | ||
369 | current = current->parent; | ||
370 | } | ||
371 | } else { | 350 | } else { |
372 | wlr_log(WLR_DEBUG, "Hit limit, " | 351 | current = current->parent; |
373 | "promoting descendant to sibling"); | 352 | continue; |
374 | // Special case | 353 | } |
354 | } else { | ||
355 | // Special case | ||
356 | if (current->parent) { | ||
375 | container_insert_child(current->parent, container, | 357 | container_insert_child(current->parent, container, |
376 | index + (offs < 0 ? 0 : 1)); | 358 | index + (offs < 0 ? 0 : 1)); |
377 | container->width = container->height = 0; | 359 | } else { |
378 | return; | 360 | workspace_insert_tiling(current->workspace, container, |
361 | index + (offs < 0 ? 0 : 1)); | ||
379 | } | 362 | } |
380 | } else { | 363 | return true; |
381 | sibling = parent->children->items[index + offs]; | ||
382 | wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); | ||
383 | } | 364 | } |
384 | } else if (!parent->is_fullscreen && (parent->layout == L_TABBED || | ||
385 | parent->layout == L_STACKED)) { | ||
386 | move_out_of_tabs_stacks(container, current, move_dir, offs); | ||
387 | return; | ||
388 | } else { | 365 | } else { |
389 | wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); | 366 | // Container can move within its siblings |
390 | current = current->parent; | 367 | container_move_to_container_from_direction(container, |
368 | siblings->items[desired], move_dir); | ||
369 | return true; | ||
391 | } | 370 | } |
392 | break; | 371 | } else if (!(parent && parent->is_fullscreen) && |
393 | default: | 372 | (layout == L_TABBED || layout == L_STACKED)) { |
394 | sway_assert(0, "Not expecting to see container of type %s here", | 373 | move_out_of_tabs_stacks(container, current, move_dir, offs); |
395 | container_type_to_str(current->type)); | 374 | return true; |
396 | return; | ||
397 | } | 375 | } |
398 | } | ||
399 | 376 | ||
400 | // Part two: move stuff around | 377 | current = current->parent; |
401 | int index = container_sibling_index(container); | ||
402 | struct sway_container *old_parent = container->parent; | ||
403 | 378 | ||
404 | while (sibling) { | 379 | // Don't allow containers to move out of their |
405 | switch (sibling->type) { | 380 | // fullscreen or floating parent |
406 | case C_VIEW: | 381 | if (current && |
407 | if (sibling->parent == container->parent) { | 382 | (current->is_fullscreen || container_is_floating(current))) { |
408 | wlr_log(WLR_DEBUG, "Swapping siblings"); | 383 | return false; |
409 | sibling->parent->children->items[index + offs] = container; | ||
410 | sibling->parent->children->items[index] = sibling; | ||
411 | } else { | ||
412 | wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); | ||
413 | container_insert_child(sibling->parent, container, | ||
414 | container_sibling_index(sibling) + (offs > 0 ? 0 : 1)); | ||
415 | container->width = container->height = 0; | ||
416 | } | ||
417 | sibling = NULL; | ||
418 | break; | ||
419 | case C_WORKSPACE: // Note: only in the case of moving between outputs | ||
420 | case C_CONTAINER: | ||
421 | if (is_parallel(sibling->layout, move_dir)) { | ||
422 | int limit = container_limit(sibling, invert_movement(move_dir)); | ||
423 | wlr_log(WLR_DEBUG, "limit: %d", limit); | ||
424 | wlr_log(WLR_DEBUG, | ||
425 | "Reparenting container (parallel) to index %d " | ||
426 | "(move dir: %d)", limit, move_dir); | ||
427 | container_insert_child(sibling, container, limit); | ||
428 | container->width = container->height = 0; | ||
429 | sibling = NULL; | ||
430 | } else { | ||
431 | wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); | ||
432 | struct sway_container *focus_inactive = seat_get_focus_inactive( | ||
433 | config->handler_context.seat, sibling); | ||
434 | if (focus_inactive && focus_inactive != sibling) { | ||
435 | while (focus_inactive->parent != sibling) { | ||
436 | focus_inactive = focus_inactive->parent; | ||
437 | } | ||
438 | wlr_log(WLR_DEBUG, "Focus inactive: id:%zd", | ||
439 | focus_inactive->id); | ||
440 | sibling = focus_inactive; | ||
441 | continue; | ||
442 | } else if (sibling->children->length) { | ||
443 | wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily"); | ||
444 | container_remove_child(container); | ||
445 | container_add_sibling(sibling->children->items[0], container); | ||
446 | } else { | ||
447 | wlr_log(WLR_DEBUG, "No kiddos, adding container alone"); | ||
448 | container_remove_child(container); | ||
449 | container_add_child(sibling, container); | ||
450 | } | ||
451 | container->width = container->height = 0; | ||
452 | sibling = NULL; | ||
453 | } | ||
454 | break; | ||
455 | default: | ||
456 | sway_assert(0, "Not expecting to see container of type %s here", | ||
457 | container_type_to_str(sibling->type)); | ||
458 | return; | ||
459 | } | 384 | } |
460 | } | 385 | } |
461 | 386 | ||
462 | container_notify_subtree_changed(old_parent); | 387 | // Maybe rejigger the workspace |
463 | container_notify_subtree_changed(container->parent); | 388 | struct sway_workspace *ws = container->workspace; |
464 | 389 | if (!is_parallel(ws->layout, move_dir)) { | |
465 | if (container->type == C_VIEW) { | 390 | if (ws->tiling->length >= 2) { |
466 | ipc_event_window(container, "move"); | 391 | workspace_rejigger(ws, container, move_dir); |
467 | } | 392 | return true; |
468 | 393 | } | |
469 | if (old_parent) { | 394 | } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) { |
470 | seat_set_focus(config->handler_context.seat, old_parent); | 395 | workspace_rejigger(ws, container, move_dir); |
471 | seat_set_focus(config->handler_context.seat, container); | 396 | return true; |
472 | } | 397 | } |
473 | 398 | ||
474 | struct sway_container *last_ws = old_parent; | 399 | // Try adjacent output |
475 | struct sway_container *next_ws = container->parent; | 400 | struct sway_output *output = |
476 | if (last_ws && last_ws->type != C_WORKSPACE) { | 401 | output_get_in_direction(container->workspace->output, move_dir); |
477 | last_ws = container_parent(last_ws, C_WORKSPACE); | 402 | if (output) { |
478 | } | 403 | struct sway_workspace *ws = output_get_active_workspace(output); |
479 | if (next_ws && next_ws->type != C_WORKSPACE) { | 404 | container_move_to_workspace_from_direction(container, ws, move_dir); |
480 | next_ws = container_parent(next_ws, C_WORKSPACE); | 405 | return true; |
481 | } | 406 | } |
482 | if (last_ws && next_ws && last_ws != next_ws) { | 407 | wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); |
483 | ipc_event_workspace(last_ws, next_ws, "focus"); | 408 | return false; |
484 | workspace_detect_urgent(last_ws); | ||
485 | workspace_detect_urgent(next_ws); | ||
486 | } | ||
487 | container_end_mouse_operation(container); | ||
488 | } | 409 | } |
489 | 410 | ||
490 | static struct cmd_results *cmd_move_container(struct sway_container *current, | 411 | static struct cmd_results *cmd_move_container(int argc, char **argv) { |
491 | int argc, char **argv) { | ||
492 | struct cmd_results *error = NULL; | 412 | struct cmd_results *error = NULL; |
493 | if ((error = checkarg(argc, "move container/window", | 413 | if ((error = checkarg(argc, "move container/window", |
494 | EXPECTED_AT_LEAST, 3))) { | 414 | EXPECTED_AT_LEAST, 3))) { |
495 | return error; | 415 | return error; |
496 | } | 416 | } |
497 | 417 | ||
498 | if (current->type == C_WORKSPACE) { | 418 | struct sway_node *node = config->handler_context.node; |
499 | if (current->children->length == 0) { | 419 | struct sway_workspace *workspace = config->handler_context.workspace; |
420 | struct sway_container *container = config->handler_context.container; | ||
421 | if (node->type == N_WORKSPACE) { | ||
422 | if (workspace->tiling->length == 0) { | ||
500 | return cmd_results_new(CMD_FAILURE, "move", | 423 | return cmd_results_new(CMD_FAILURE, "move", |
501 | "Can't move an empty workspace"); | 424 | "Can't move an empty workspace"); |
502 | } | 425 | } |
503 | current = workspace_wrap_children(current); | 426 | container = workspace_wrap_children(workspace); |
504 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { | ||
505 | return cmd_results_new(CMD_FAILURE, "move", | ||
506 | "Can only move containers and views."); | ||
507 | } | 427 | } |
508 | 428 | ||
509 | bool no_auto_back_and_forth = false; | 429 | bool no_auto_back_and_forth = false; |
@@ -530,15 +450,15 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
530 | } | 450 | } |
531 | 451 | ||
532 | struct sway_seat *seat = config->handler_context.seat; | 452 | struct sway_seat *seat = config->handler_context.seat; |
533 | struct sway_container *old_parent = current->parent; | 453 | struct sway_container *old_parent = container->parent; |
534 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 454 | struct sway_workspace *old_ws = container->workspace; |
535 | struct sway_container *old_output = container_parent(current, C_OUTPUT); | 455 | struct sway_output *old_output = old_ws->output; |
536 | struct sway_container *destination = NULL; | 456 | struct sway_node *destination = NULL; |
537 | 457 | ||
538 | // determine destination | 458 | // determine destination |
539 | if (strcasecmp(argv[1], "workspace") == 0) { | 459 | if (strcasecmp(argv[1], "workspace") == 0) { |
540 | // move container to workspace x | 460 | // move container to workspace x |
541 | struct sway_container *ws = NULL; | 461 | struct sway_workspace *ws = NULL; |
542 | char *ws_name = NULL; | 462 | char *ws_name = NULL; |
543 | if (strcasecmp(argv[2], "next") == 0 || | 463 | if (strcasecmp(argv[2], "next") == 0 || |
544 | strcasecmp(argv[2], "prev") == 0 || | 464 | strcasecmp(argv[2], "prev") == 0 || |
@@ -588,8 +508,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
588 | // We have to create the workspace, but if the container is | 508 | // We have to create the workspace, but if the container is |
589 | // sticky and the workspace is going to be created on the same | 509 | // sticky and the workspace is going to be created on the same |
590 | // output, we'll bail out first. | 510 | // output, we'll bail out first. |
591 | if (current->is_sticky) { | 511 | if (container->is_sticky) { |
592 | struct sway_container *new_output = | 512 | struct sway_output *new_output = |
593 | workspace_get_initial_output(ws_name); | 513 | workspace_get_initial_output(ws_name); |
594 | if (old_output == new_output) { | 514 | if (old_output == new_output) { |
595 | free(ws_name); | 515 | free(ws_name); |
@@ -601,105 +521,113 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
601 | ws = workspace_create(NULL, ws_name); | 521 | ws = workspace_create(NULL, ws_name); |
602 | } | 522 | } |
603 | free(ws_name); | 523 | free(ws_name); |
604 | destination = seat_get_focus_inactive(seat, ws); | 524 | destination = seat_get_focus_inactive(seat, &ws->node); |
605 | } else if (strcasecmp(argv[1], "output") == 0) { | 525 | } else if (strcasecmp(argv[1], "output") == 0) { |
606 | struct sway_container *dest_output = output_in_direction(argv[2], | 526 | struct sway_output *new_output = output_in_direction(argv[2], |
607 | old_output->sway_output->wlr_output, current->x, current->y); | 527 | old_output->wlr_output, container->x, container->y); |
608 | if (!dest_output) { | 528 | if (!new_output) { |
609 | return cmd_results_new(CMD_FAILURE, "move workspace", | 529 | return cmd_results_new(CMD_FAILURE, "move workspace", |
610 | "Can't find output with name/direction '%s'", argv[2]); | 530 | "Can't find output with name/direction '%s'", argv[2]); |
611 | } | 531 | } |
612 | destination = seat_get_focus_inactive(seat, dest_output); | 532 | destination = seat_get_focus_inactive(seat, &new_output->node); |
613 | if (!destination) { | ||
614 | // We've never been to this output before | ||
615 | destination = dest_output->children->items[0]; | ||
616 | } | ||
617 | } else if (strcasecmp(argv[1], "mark") == 0) { | 533 | } else if (strcasecmp(argv[1], "mark") == 0) { |
618 | struct sway_view *dest_view = view_find_mark(argv[2]); | 534 | struct sway_view *dest_view = view_find_mark(argv[2]); |
619 | if (dest_view == NULL) { | 535 | if (dest_view == NULL) { |
620 | return cmd_results_new(CMD_FAILURE, "move", | 536 | return cmd_results_new(CMD_FAILURE, "move", |
621 | "Mark '%s' not found", argv[2]); | 537 | "Mark '%s' not found", argv[2]); |
622 | } | 538 | } |
623 | destination = dest_view->swayc; | 539 | destination = &dest_view->container->node; |
624 | } else { | 540 | } else { |
625 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 541 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
626 | } | 542 | } |
627 | 543 | ||
628 | struct sway_container *new_output = destination->type == C_OUTPUT ? | 544 | if (container->is_sticky && |
629 | destination : container_parent(destination, C_OUTPUT); | 545 | node_has_ancestor(destination, &old_output->node)) { |
630 | if (current->is_sticky && old_output == new_output) { | ||
631 | return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky " | 546 | return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky " |
632 | "container to another workspace on the same output"); | 547 | "container to another workspace on the same output"); |
633 | } | 548 | } |
634 | 549 | ||
635 | struct sway_container *new_output_last_ws = old_output == new_output ? | 550 | struct sway_output *new_output = node_get_output(destination); |
636 | NULL : seat_get_active_child(seat, new_output); | 551 | struct sway_workspace *new_output_last_ws = old_output == new_output ? |
637 | struct sway_container *new_workspace = destination->type == C_WORKSPACE ? | 552 | NULL : output_get_active_workspace(new_output); |
638 | destination : container_parent(destination, C_WORKSPACE); | ||
639 | 553 | ||
640 | // move container, arrange windows and return focus | 554 | // move container, arrange windows and return focus |
641 | container_move_to(current, destination); | 555 | switch (destination->type) { |
556 | case N_WORKSPACE: | ||
557 | container_move_to_workspace(container, destination->sway_workspace); | ||
558 | break; | ||
559 | case N_OUTPUT: { | ||
560 | struct sway_output *output = destination->sway_output; | ||
561 | struct sway_workspace *ws = output_get_active_workspace(output); | ||
562 | container_move_to_workspace(container, ws); | ||
563 | } | ||
564 | break; | ||
565 | case N_CONTAINER: | ||
566 | container_move_to_container(container, destination->sway_container); | ||
567 | break; | ||
568 | case N_ROOT: | ||
569 | break; | ||
570 | } | ||
571 | struct sway_workspace *new_workspace = | ||
572 | output_get_active_workspace(new_output); | ||
642 | if (new_output_last_ws && new_output_last_ws != new_workspace) { | 573 | if (new_output_last_ws && new_output_last_ws != new_workspace) { |
643 | // change focus on destination output back to its last active workspace | 574 | // change focus on destination output back to its last active workspace |
644 | struct sway_container *new_output_last_focus = | 575 | struct sway_node *new_output_last_focus = |
645 | seat_get_focus_inactive(seat, new_output_last_ws); | 576 | seat_get_focus_inactive(seat, &new_output_last_ws->node); |
646 | seat_set_focus_warp(seat, new_output_last_focus, false, false); | 577 | seat_set_focus_warp(seat, new_output_last_focus, false, false); |
647 | } | 578 | } |
648 | struct sway_container *focus = seat_get_focus_inactive(seat, old_parent); | 579 | |
580 | struct sway_node *focus = NULL; | ||
581 | if (old_parent) { | ||
582 | focus = seat_get_focus_inactive(seat, &old_parent->node); | ||
583 | } else { | ||
584 | focus = seat_get_focus_inactive(seat, &old_ws->node); | ||
585 | } | ||
649 | seat_set_focus_warp(seat, focus, true, false); | 586 | seat_set_focus_warp(seat, focus, true, false); |
650 | container_reap_empty(old_parent); | ||
651 | container_reap_empty(destination->parent); | ||
652 | 587 | ||
653 | // TODO: Ideally we would arrange the surviving parent after reaping, | 588 | if (old_parent) { |
654 | // but container_reap_empty does not return it, so we arrange the | 589 | container_reap_empty(old_parent); |
655 | // workspace instead. | 590 | } else { |
656 | arrange_windows(old_ws); | 591 | workspace_consider_destroy(old_ws); |
657 | arrange_windows(destination->parent); | 592 | } |
593 | |||
594 | arrange_workspace(old_ws); | ||
595 | arrange_node(node_get_parent(destination)); | ||
658 | 596 | ||
659 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 597 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
660 | } | 598 | } |
661 | 599 | ||
662 | static void workspace_move_to_output(struct sway_container *workspace, | 600 | static void workspace_move_to_output(struct sway_workspace *workspace, |
663 | struct sway_container *output) { | 601 | struct sway_output *output) { |
664 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 602 | if (workspace->output == output) { |
665 | return; | 603 | return; |
666 | } | 604 | } |
667 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 605 | struct sway_output *old_output = workspace->output; |
668 | return; | 606 | workspace_detach(workspace); |
669 | } | 607 | struct sway_workspace *new_output_old_ws = |
670 | if (workspace->parent == output) { | 608 | output_get_active_workspace(output); |
671 | return; | ||
672 | } | ||
673 | struct sway_container *old_output = container_remove_child(workspace); | ||
674 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | ||
675 | struct sway_container *new_output_focus = | ||
676 | seat_get_focus_inactive(seat, output); | ||
677 | 609 | ||
678 | container_add_child(output, workspace); | 610 | output_add_workspace(output, workspace); |
679 | 611 | ||
680 | // If moving the last workspace from the old output, create a new workspace | 612 | // If moving the last workspace from the old output, create a new workspace |
681 | // on the old output | 613 | // on the old output |
682 | if (old_output->children->length == 0) { | 614 | struct sway_seat *seat = config->handler_context.seat; |
683 | char *ws_name = workspace_next_name(old_output->name); | 615 | if (old_output->workspaces->length == 0) { |
684 | struct sway_container *ws = workspace_create(old_output, ws_name); | 616 | char *ws_name = workspace_next_name(old_output->wlr_output->name); |
617 | struct sway_workspace *ws = workspace_create(old_output, ws_name); | ||
685 | free(ws_name); | 618 | free(ws_name); |
686 | seat_set_focus(seat, ws); | 619 | seat_set_focus(seat, &ws->node); |
687 | } | 620 | } |
688 | 621 | ||
689 | // Try to remove an empty workspace from the destination output. | 622 | workspace_consider_destroy(new_output_old_ws); |
690 | container_reap_empty(new_output_focus); | ||
691 | 623 | ||
692 | output_sort_workspaces(output); | 624 | output_sort_workspaces(output); |
693 | seat_set_focus(seat, output); | 625 | seat_set_focus(seat, &output->node); |
694 | workspace_output_raise_priority(workspace, old_output, output); | 626 | workspace_output_raise_priority(workspace, old_output, output); |
695 | ipc_event_workspace(NULL, workspace, "move"); | 627 | ipc_event_workspace(NULL, workspace, "move"); |
696 | |||
697 | container_notify_subtree_changed(old_output); | ||
698 | container_notify_subtree_changed(output); | ||
699 | } | 628 | } |
700 | 629 | ||
701 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, | 630 | static struct cmd_results *cmd_move_workspace(int argc, char **argv) { |
702 | int argc, char **argv) { | ||
703 | struct cmd_results *error = NULL; | 631 | struct cmd_results *error = NULL; |
704 | if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { | 632 | if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { |
705 | return error; | 633 | return error; |
@@ -716,27 +644,25 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current, | |||
716 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 644 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
717 | } | 645 | } |
718 | 646 | ||
719 | struct sway_container *source = container_parent(current, C_OUTPUT); | 647 | struct sway_workspace *workspace = config->handler_context.workspace; |
720 | int center_x = current->width / 2 + current->x, | 648 | struct sway_output *old_output = workspace->output; |
721 | center_y = current->height / 2 + current->y; | 649 | int center_x = workspace->width / 2 + workspace->x, |
722 | struct sway_container *destination = output_in_direction(argv[2], | 650 | center_y = workspace->height / 2 + workspace->y; |
723 | source->sway_output->wlr_output, center_x, center_y); | 651 | struct sway_output *new_output = output_in_direction(argv[2], |
724 | if (!destination) { | 652 | old_output->wlr_output, center_x, center_y); |
653 | if (!new_output) { | ||
725 | return cmd_results_new(CMD_FAILURE, "move workspace", | 654 | return cmd_results_new(CMD_FAILURE, "move workspace", |
726 | "Can't find output with name/direction '%s'", argv[2]); | 655 | "Can't find output with name/direction '%s'", argv[2]); |
727 | } | 656 | } |
728 | if (current->type != C_WORKSPACE) { | 657 | workspace_move_to_output(workspace, new_output); |
729 | current = container_parent(current, C_WORKSPACE); | ||
730 | } | ||
731 | workspace_move_to_output(current, destination); | ||
732 | 658 | ||
733 | arrange_windows(source); | 659 | arrange_output(old_output); |
734 | arrange_windows(destination); | 660 | arrange_output(new_output); |
735 | 661 | ||
736 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 662 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
737 | } | 663 | } |
738 | 664 | ||
739 | static struct cmd_results *move_in_direction(struct sway_container *container, | 665 | static struct cmd_results *cmd_move_in_direction( |
740 | enum movement_direction direction, int argc, char **argv) { | 666 | enum movement_direction direction, int argc, char **argv) { |
741 | int move_amt = 10; | 667 | int move_amt = 10; |
742 | if (argc > 1) { | 668 | if (argc > 1) { |
@@ -748,7 +674,8 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
748 | } | 674 | } |
749 | } | 675 | } |
750 | 676 | ||
751 | if (container->type == C_WORKSPACE) { | 677 | struct sway_container *container = config->handler_context.container; |
678 | if (!container) { | ||
752 | return cmd_results_new(CMD_FAILURE, "move", | 679 | return cmd_results_new(CMD_FAILURE, "move", |
753 | "Cannot move workspaces in a direction"); | 680 | "Cannot move workspaces in a direction"); |
754 | } | 681 | } |
@@ -780,20 +707,34 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
780 | container_floating_move_to(container, lx, ly); | 707 | container_floating_move_to(container, lx, ly); |
781 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 708 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
782 | } | 709 | } |
783 | // For simplicity, we'll arrange the entire workspace. The reason for this | 710 | struct sway_workspace *old_ws = container->workspace; |
784 | // is moving the container might reap the old parent, and container_move | ||
785 | // does not return a surviving parent. | ||
786 | // TODO: Make container_move return the surviving parent so we can arrange | ||
787 | // just that. | ||
788 | struct sway_container *old_ws = container_parent(container, C_WORKSPACE); | ||
789 | container_move(container, direction, move_amt); | ||
790 | struct sway_container *new_ws = container_parent(container, C_WORKSPACE); | ||
791 | 711 | ||
792 | arrange_windows(old_ws); | 712 | if (!container_move_in_direction(container, direction)) { |
713 | // Container didn't move | ||
714 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
715 | } | ||
716 | |||
717 | struct sway_workspace *new_ws = container->workspace; | ||
718 | |||
719 | arrange_workspace(old_ws); | ||
793 | if (new_ws != old_ws) { | 720 | if (new_ws != old_ws) { |
794 | arrange_windows(new_ws); | 721 | arrange_workspace(new_ws); |
722 | } | ||
723 | |||
724 | if (container->view) { | ||
725 | ipc_event_window(container, "move"); | ||
795 | } | 726 | } |
796 | 727 | ||
728 | seat_set_focus(config->handler_context.seat, &new_ws->node); | ||
729 | seat_set_focus(config->handler_context.seat, &container->node); | ||
730 | |||
731 | if (old_ws != new_ws) { | ||
732 | ipc_event_workspace(old_ws, new_ws, "focus"); | ||
733 | workspace_detect_urgent(old_ws); | ||
734 | workspace_detect_urgent(new_ws); | ||
735 | } | ||
736 | container_end_mouse_operation(container); | ||
737 | |||
797 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 738 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
798 | } | 739 | } |
799 | 740 | ||
@@ -802,9 +743,9 @@ static const char *expected_position_syntax = | |||
802 | "'move [absolute] position center' or " | 743 | "'move [absolute] position center' or " |
803 | "'move position cursor|mouse|pointer'"; | 744 | "'move position cursor|mouse|pointer'"; |
804 | 745 | ||
805 | static struct cmd_results *move_to_position(struct sway_container *container, | 746 | static struct cmd_results *cmd_move_to_position(int argc, char **argv) { |
806 | int argc, char **argv) { | 747 | struct sway_container *container = config->handler_context.container; |
807 | if (!container_is_floating(container)) { | 748 | if (!container || !container_is_floating(container)) { |
808 | return cmd_results_new(CMD_FAILURE, "move", | 749 | return cmd_results_new(CMD_FAILURE, "move", |
809 | "Only floating containers " | 750 | "Only floating containers " |
810 | "can be moved to an absolute position"); | 751 | "can be moved to an absolute position"); |
@@ -842,10 +783,10 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
842 | } else if (strcmp(argv[0], "center") == 0) { | 783 | } else if (strcmp(argv[0], "center") == 0) { |
843 | double lx, ly; | 784 | double lx, ly; |
844 | if (absolute) { | 785 | if (absolute) { |
845 | lx = root_container.x + (root_container.width - container->width) / 2; | 786 | lx = root->x + (root->width - container->width) / 2; |
846 | ly = root_container.y + (root_container.height - container->height) / 2; | 787 | ly = root->y + (root->height - container->height) / 2; |
847 | } else { | 788 | } else { |
848 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | 789 | struct sway_workspace *ws = container->workspace; |
849 | lx = ws->x + (ws->width - container->width) / 2; | 790 | lx = ws->x + (ws->width - container->width) / 2; |
850 | ly = ws->y + (ws->height - container->height) / 2; | 791 | ly = ws->y + (ws->height - container->height) / 2; |
851 | } | 792 | } |
@@ -881,30 +822,31 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
881 | } | 822 | } |
882 | 823 | ||
883 | if (!absolute) { | 824 | if (!absolute) { |
884 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | 825 | lx += container->workspace->x; |
885 | lx += ws->x; | 826 | ly += container->workspace->y; |
886 | ly += ws->y; | ||
887 | } | 827 | } |
888 | container_floating_move_to(container, lx, ly); | 828 | container_floating_move_to(container, lx, ly); |
889 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 829 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
890 | } | 830 | } |
891 | 831 | ||
892 | static struct cmd_results *move_to_scratchpad(struct sway_container *con) { | 832 | static struct cmd_results *cmd_move_to_scratchpad(void) { |
893 | if (con->type == C_WORKSPACE && con->children->length == 0) { | 833 | struct sway_node *node = config->handler_context.node; |
834 | struct sway_container *con = config->handler_context.container; | ||
835 | struct sway_workspace *ws = config->handler_context.workspace; | ||
836 | if (node->type == N_WORKSPACE && ws->tiling->length == 0) { | ||
894 | return cmd_results_new(CMD_INVALID, "move", | 837 | return cmd_results_new(CMD_INVALID, "move", |
895 | "Can't move an empty workspace to the scratchpad"); | 838 | "Can't move an empty workspace to the scratchpad"); |
896 | } | 839 | } |
897 | if (con->type == C_WORKSPACE) { | 840 | if (node->type == N_WORKSPACE) { |
898 | // Wrap the workspace's children in a container | 841 | // Wrap the workspace's children in a container |
899 | struct sway_container *workspace = con; | 842 | con = workspace_wrap_children(ws); |
900 | con = workspace_wrap_children(con); | 843 | ws->layout = L_HORIZ; |
901 | workspace->layout = L_HORIZ; | ||
902 | } | 844 | } |
903 | 845 | ||
904 | // If the container is in a floating split container, | 846 | // If the container is in a floating split container, |
905 | // operate on the split container instead of the child. | 847 | // operate on the split container instead of the child. |
906 | if (container_is_floating_or_child(con)) { | 848 | if (container_is_floating_or_child(con)) { |
907 | while (con->parent->type != C_WORKSPACE) { | 849 | while (con->parent) { |
908 | con = con->parent; | 850 | con = con->parent; |
909 | } | 851 | } |
910 | } | 852 | } |
@@ -922,32 +864,31 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
922 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { | 864 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { |
923 | return error; | 865 | return error; |
924 | } | 866 | } |
925 | struct sway_container *current = config->handler_context.current_container; | ||
926 | 867 | ||
927 | if (strcasecmp(argv[0], "left") == 0) { | 868 | if (strcasecmp(argv[0], "left") == 0) { |
928 | return move_in_direction(current, MOVE_LEFT, argc, argv); | 869 | return cmd_move_in_direction(MOVE_LEFT, argc, argv); |
929 | } else if (strcasecmp(argv[0], "right") == 0) { | 870 | } else if (strcasecmp(argv[0], "right") == 0) { |
930 | return move_in_direction(current, MOVE_RIGHT, argc, argv); | 871 | return cmd_move_in_direction(MOVE_RIGHT, argc, argv); |
931 | } else if (strcasecmp(argv[0], "up") == 0) { | 872 | } else if (strcasecmp(argv[0], "up") == 0) { |
932 | return move_in_direction(current, MOVE_UP, argc, argv); | 873 | return cmd_move_in_direction(MOVE_UP, argc, argv); |
933 | } else if (strcasecmp(argv[0], "down") == 0) { | 874 | } else if (strcasecmp(argv[0], "down") == 0) { |
934 | return move_in_direction(current, MOVE_DOWN, argc, argv); | 875 | return cmd_move_in_direction(MOVE_DOWN, argc, argv); |
935 | } else if ((strcasecmp(argv[0], "container") == 0 | 876 | } else if ((strcasecmp(argv[0], "container") == 0 |
936 | || strcasecmp(argv[0], "window") == 0) || | 877 | || strcasecmp(argv[0], "window") == 0) || |
937 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && | 878 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && argc >= 2 |
938 | (strcasecmp(argv[0], "container") == 0 | 879 | && (strcasecmp(argv[1], "container") == 0 |
939 | || strcasecmp(argv[0], "window") == 0))) { | 880 | || strcasecmp(argv[1], "window") == 0))) { |
940 | return cmd_move_container(current, argc, argv); | 881 | return cmd_move_container(argc, argv); |
941 | } else if (strcasecmp(argv[0], "workspace") == 0) { | 882 | } else if (strcasecmp(argv[0], "workspace") == 0) { |
942 | return cmd_move_workspace(current, argc, argv); | 883 | return cmd_move_workspace(argc, argv); |
943 | } else if (strcasecmp(argv[0], "scratchpad") == 0 | 884 | } else if (strcasecmp(argv[0], "scratchpad") == 0 |
944 | || (strcasecmp(argv[0], "to") == 0 && argc == 2 | 885 | || (strcasecmp(argv[0], "to") == 0 && argc == 2 |
945 | && strcasecmp(argv[1], "scratchpad") == 0)) { | 886 | && strcasecmp(argv[1], "scratchpad") == 0)) { |
946 | return move_to_scratchpad(current); | 887 | return cmd_move_to_scratchpad(); |
947 | } else if (strcasecmp(argv[0], "position") == 0) { | 888 | } else if (strcasecmp(argv[0], "position") == 0) { |
948 | return move_to_position(current, argc, argv); | 889 | return cmd_move_to_position(argc, argv); |
949 | } else if (strcasecmp(argv[0], "absolute") == 0) { | 890 | } else if (strcasecmp(argv[0], "absolute") == 0) { |
950 | return move_to_position(current, argc, argv); | 891 | return cmd_move_to_position(argc, argv); |
951 | } else { | 892 | } else { |
952 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 893 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
953 | } | 894 | } |
diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c index 68fd9f42..9cdaad7f 100644 --- a/sway/commands/opacity.c +++ b/sway/commands/opacity.c | |||
@@ -19,8 +19,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) { | |||
19 | return error; | 19 | return error; |
20 | } | 20 | } |
21 | 21 | ||
22 | struct sway_container *con = | 22 | struct sway_container *con = config->handler_context.container; |
23 | config->handler_context.current_container; | ||
24 | 23 | ||
25 | float opacity = 0.0f; | 24 | float opacity = 0.0f; |
26 | 25 | ||
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index f8ca374d..36fb9092 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -42,7 +42,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) { | |||
42 | } | 42 | } |
43 | list_free(bar_ids); | 43 | list_free(bar_ids); |
44 | 44 | ||
45 | arrange_windows(&root_container); | 45 | arrange_root(); |
46 | 46 | ||
47 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 47 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
48 | } | 48 | } |
diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 21d2aa64..d982f941 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c | |||
@@ -25,14 +25,11 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | int argn = 1; | 27 | int argn = 1; |
28 | struct sway_container *workspace; | 28 | struct sway_workspace *workspace = NULL; |
29 | 29 | ||
30 | if (strcasecmp(argv[1], "to") == 0) { | 30 | if (strcasecmp(argv[1], "to") == 0) { |
31 | // 'rename workspace to new_name' | 31 | // 'rename workspace to new_name' |
32 | workspace = config->handler_context.current_container; | 32 | workspace = config->handler_context.workspace; |
33 | if (workspace->type != C_WORKSPACE) { | ||
34 | workspace = container_parent(workspace, C_WORKSPACE); | ||
35 | } | ||
36 | } else if (strcasecmp(argv[1], "number") == 0) { | 33 | } else if (strcasecmp(argv[1], "number") == 0) { |
37 | // 'rename workspace number x to new_name' | 34 | // 'rename workspace number x to new_name' |
38 | if (!isdigit(argv[2][0])) { | 35 | if (!isdigit(argv[2][0])) { |
@@ -78,7 +75,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
78 | return cmd_results_new(CMD_INVALID, "rename", | 75 | return cmd_results_new(CMD_INVALID, "rename", |
79 | "Cannot use special workspace name '%s'", argv[argn]); | 76 | "Cannot use special workspace name '%s'", argv[argn]); |
80 | } | 77 | } |
81 | struct sway_container *tmp_workspace = workspace_by_name(new_name); | 78 | struct sway_workspace *tmp_workspace = workspace_by_name(new_name); |
82 | if (tmp_workspace) { | 79 | if (tmp_workspace) { |
83 | free(new_name); | 80 | free(new_name); |
84 | return cmd_results_new(CMD_INVALID, "rename", | 81 | return cmd_results_new(CMD_INVALID, "rename", |
@@ -89,7 +86,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
89 | free(workspace->name); | 86 | free(workspace->name); |
90 | workspace->name = new_name; | 87 | workspace->name = new_name; |
91 | 88 | ||
92 | output_sort_workspaces(workspace->parent); | 89 | output_sort_workspaces(workspace->output); |
93 | ipc_event_workspace(NULL, workspace, "rename"); | 90 | ipc_event_workspace(NULL, workspace, "rename"); |
94 | 91 | ||
95 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 92 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index ad659ef5..99e9dbda 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "sway/commands.h" | 10 | #include "sway/commands.h" |
11 | #include "sway/tree/arrange.h" | 11 | #include "sway/tree/arrange.h" |
12 | #include "sway/tree/view.h" | 12 | #include "sway/tree/view.h" |
13 | #include "sway/tree/workspace.h" | ||
13 | #include "log.h" | 14 | #include "log.h" |
14 | 15 | ||
15 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; | 16 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; |
@@ -75,7 +76,7 @@ static int parse_resize_amount(int argc, char **argv, | |||
75 | 76 | ||
76 | static void calculate_constraints(int *min_width, int *max_width, | 77 | static void calculate_constraints(int *min_width, int *max_width, |
77 | int *min_height, int *max_height) { | 78 | int *min_height, int *max_height) { |
78 | struct sway_container *con = config->handler_context.current_container; | 79 | struct sway_container *con = config->handler_context.container; |
79 | 80 | ||
80 | if (config->floating_minimum_width == -1) { // no minimum | 81 | if (config->floating_minimum_width == -1) { // no minimum |
81 | *min_width = 0; | 82 | *min_width = 0; |
@@ -96,8 +97,7 @@ static void calculate_constraints(int *min_width, int *max_width, | |||
96 | if (config->floating_maximum_width == -1) { // no maximum | 97 | if (config->floating_maximum_width == -1) { // no maximum |
97 | *max_width = INT_MAX; | 98 | *max_width = INT_MAX; |
98 | } else if (config->floating_maximum_width == 0) { // automatic | 99 | } else if (config->floating_maximum_width == 0) { // automatic |
99 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 100 | *max_width = con->workspace->width; |
100 | *max_width = ws->width; | ||
101 | } else { | 101 | } else { |
102 | *max_width = config->floating_maximum_width; | 102 | *max_width = config->floating_maximum_width; |
103 | } | 103 | } |
@@ -105,8 +105,7 @@ static void calculate_constraints(int *min_width, int *max_width, | |||
105 | if (config->floating_maximum_height == -1) { // no maximum | 105 | if (config->floating_maximum_height == -1) { // no maximum |
106 | *max_height = INT_MAX; | 106 | *max_height = INT_MAX; |
107 | } else if (config->floating_maximum_height == 0) { // automatic | 107 | } else if (config->floating_maximum_height == 0) { // automatic |
108 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 108 | *max_height = con->workspace->height; |
109 | *max_height = ws->height; | ||
110 | } else { | 109 | } else { |
111 | *max_height = config->floating_maximum_height; | 110 | *max_height = config->floating_maximum_height; |
112 | } | 111 | } |
@@ -191,11 +190,11 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
191 | normalize_axis(axis) == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; | 190 | normalize_axis(axis) == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; |
192 | int minor_weight = 0; | 191 | int minor_weight = 0; |
193 | int major_weight = 0; | 192 | int major_weight = 0; |
194 | while (parent->parent) { | 193 | while (parent) { |
195 | struct sway_container *next = parent->parent; | 194 | list_t *siblings = container_get_siblings(parent); |
196 | if (next->layout == parallel_layout) { | 195 | if (container_parent_layout(parent) == parallel_layout) { |
197 | for (int i = 0; i < next->children->length; i++) { | 196 | for (int i = 0; i < siblings->length; i++) { |
198 | struct sway_container *sibling = next->children->items[i]; | 197 | struct sway_container *sibling = siblings->items[i]; |
199 | 198 | ||
200 | int sibling_pos = parallel_coord(sibling, axis); | 199 | int sibling_pos = parallel_coord(sibling, axis); |
201 | int focused_pos = parallel_coord(focused, axis); | 200 | int focused_pos = parallel_coord(focused, axis); |
@@ -213,17 +212,13 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
213 | break; | 212 | break; |
214 | } | 213 | } |
215 | } | 214 | } |
216 | parent = next; | 215 | parent = parent->parent; |
217 | } | 216 | } |
218 | 217 | if (!parent) { | |
219 | if (parent->type == C_ROOT) { | 218 | // Can't resize in this direction |
220 | return; | 219 | return; |
221 | } | 220 | } |
222 | 221 | ||
223 | wlr_log(WLR_DEBUG, | ||
224 | "Found the proper parent: %p. It has %d l conts, and %d r conts", | ||
225 | parent->parent, minor_weight, major_weight); | ||
226 | |||
227 | // Implement up/down/left/right direction by zeroing one of the weights, | 222 | // Implement up/down/left/right direction by zeroing one of the weights, |
228 | // then setting the axis to be horizontal or vertical | 223 | // then setting the axis to be horizontal or vertical |
229 | if (axis == RESIZE_AXIS_UP || axis == RESIZE_AXIS_LEFT) { | 224 | if (axis == RESIZE_AXIS_UP || axis == RESIZE_AXIS_LEFT) { |
@@ -237,9 +232,10 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
237 | 232 | ||
238 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks | 233 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks |
239 | // ^ ????? | 234 | // ^ ????? |
235 | list_t *siblings = container_get_siblings(parent); | ||
240 | 236 | ||
241 | for (int i = 0; i < parent->parent->children->length; i++) { | 237 | for (int i = 0; i < siblings->length; i++) { |
242 | struct sway_container *sibling = parent->parent->children->items[i]; | 238 | struct sway_container *sibling = siblings->items[i]; |
243 | 239 | ||
244 | int sibling_pos = parallel_coord(sibling, axis); | 240 | int sibling_pos = parallel_coord(sibling, axis); |
245 | int focused_pos = parallel_coord(focused, axis); | 241 | int focused_pos = parallel_coord(focused, axis); |
@@ -277,8 +273,8 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
277 | enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? | 273 | enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? |
278 | WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; | 274 | WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; |
279 | 275 | ||
280 | for (int i = 0; i < parent->parent->children->length; i++) { | 276 | for (int i = 0; i < siblings->length; i++) { |
281 | struct sway_container *sibling = parent->parent->children->items[i]; | 277 | struct sway_container *sibling = siblings->items[i]; |
282 | 278 | ||
283 | int sibling_pos = parallel_coord(sibling, axis); | 279 | int sibling_pos = parallel_coord(sibling, axis); |
284 | int focused_pos = parallel_coord(focused, axis); | 280 | int focused_pos = parallel_coord(focused, axis); |
@@ -316,7 +312,11 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
316 | } | 312 | } |
317 | } | 313 | } |
318 | 314 | ||
319 | arrange_windows(parent->parent); | 315 | if (parent->parent) { |
316 | arrange_container(parent->parent); | ||
317 | } else { | ||
318 | arrange_workspace(parent->workspace); | ||
319 | } | ||
320 | } | 320 | } |
321 | 321 | ||
322 | void container_resize_tiled(struct sway_container *parent, | 322 | void container_resize_tiled(struct sway_container *parent, |
@@ -346,7 +346,7 @@ void container_resize_tiled(struct sway_container *parent, | |||
346 | */ | 346 | */ |
347 | static struct cmd_results *resize_adjust_floating(enum resize_axis axis, | 347 | static struct cmd_results *resize_adjust_floating(enum resize_axis axis, |
348 | struct resize_amount *amount) { | 348 | struct resize_amount *amount) { |
349 | struct sway_container *con = config->handler_context.current_container; | 349 | struct sway_container *con = config->handler_context.container; |
350 | int grow_width = 0, grow_height = 0; | 350 | int grow_width = 0, grow_height = 0; |
351 | switch (axis) { | 351 | switch (axis) { |
352 | case RESIZE_AXIS_HORIZONTAL: | 352 | case RESIZE_AXIS_HORIZONTAL: |
@@ -400,15 +400,15 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, | |||
400 | con->width += grow_width; | 400 | con->width += grow_width; |
401 | con->height += grow_height; | 401 | con->height += grow_height; |
402 | 402 | ||
403 | if (con->type == C_VIEW) { | 403 | if (con->view) { |
404 | struct sway_view *view = con->sway_view; | 404 | struct sway_view *view = con->view; |
405 | view->x += grow_x; | 405 | view->x += grow_x; |
406 | view->y += grow_y; | 406 | view->y += grow_y; |
407 | view->width += grow_width; | 407 | view->width += grow_width; |
408 | view->height += grow_height; | 408 | view->height += grow_height; |
409 | } | 409 | } |
410 | 410 | ||
411 | arrange_windows(con); | 411 | arrange_container(con); |
412 | 412 | ||
413 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 413 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
414 | } | 414 | } |
@@ -418,7 +418,7 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, | |||
418 | */ | 418 | */ |
419 | static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, | 419 | static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, |
420 | struct resize_amount *amount) { | 420 | struct resize_amount *amount) { |
421 | struct sway_container *current = config->handler_context.current_container; | 421 | struct sway_container *current = config->handler_context.container; |
422 | 422 | ||
423 | if (amount->unit == RESIZE_UNIT_DEFAULT) { | 423 | if (amount->unit == RESIZE_UNIT_DEFAULT) { |
424 | amount->unit = RESIZE_UNIT_PPT; | 424 | amount->unit = RESIZE_UNIT_PPT; |
@@ -456,13 +456,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
456 | width->unit == RESIZE_UNIT_DEFAULT) { | 456 | width->unit == RESIZE_UNIT_DEFAULT) { |
457 | // Convert to px | 457 | // Convert to px |
458 | struct sway_container *parent = con->parent; | 458 | struct sway_container *parent = con->parent; |
459 | while (parent->type >= C_WORKSPACE && parent->layout != L_HORIZ) { | 459 | while (parent && parent->layout != L_HORIZ) { |
460 | parent = parent->parent; | 460 | parent = parent->parent; |
461 | } | 461 | } |
462 | if (parent->type >= C_WORKSPACE) { | 462 | if (parent) { |
463 | width->amount = parent->width * width->amount / 100; | 463 | width->amount = parent->width * width->amount / 100; |
464 | width->unit = RESIZE_UNIT_PX; | 464 | } else { |
465 | width->amount = con->workspace->width * width->amount / 100; | ||
465 | } | 466 | } |
467 | width->unit = RESIZE_UNIT_PX; | ||
466 | } | 468 | } |
467 | if (width->unit == RESIZE_UNIT_PX) { | 469 | if (width->unit == RESIZE_UNIT_PX) { |
468 | resize_tiled(con, width->amount - con->width, | 470 | resize_tiled(con, width->amount - con->width, |
@@ -475,13 +477,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
475 | height->unit == RESIZE_UNIT_DEFAULT) { | 477 | height->unit == RESIZE_UNIT_DEFAULT) { |
476 | // Convert to px | 478 | // Convert to px |
477 | struct sway_container *parent = con->parent; | 479 | struct sway_container *parent = con->parent; |
478 | while (parent->type >= C_WORKSPACE && parent->layout != L_VERT) { | 480 | while (parent && parent->layout != L_VERT) { |
479 | parent = parent->parent; | 481 | parent = parent->parent; |
480 | } | 482 | } |
481 | if (parent->type >= C_WORKSPACE) { | 483 | if (parent) { |
482 | height->amount = parent->height * height->amount / 100; | 484 | height->amount = parent->height * height->amount / 100; |
483 | height->unit = RESIZE_UNIT_PX; | 485 | } else { |
486 | height->amount = con->workspace->height * height->amount / 100; | ||
484 | } | 487 | } |
488 | height->unit = RESIZE_UNIT_PX; | ||
485 | } | 489 | } |
486 | if (height->unit == RESIZE_UNIT_PX) { | 490 | if (height->unit == RESIZE_UNIT_PX) { |
487 | resize_tiled(con, height->amount - con->height, | 491 | resize_tiled(con, height->amount - con->height, |
@@ -508,15 +512,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, | |||
508 | con->width = width->amount; | 512 | con->width = width->amount; |
509 | con->height = height->amount; | 513 | con->height = height->amount; |
510 | 514 | ||
511 | if (con->type == C_VIEW) { | 515 | if (con->view) { |
512 | struct sway_view *view = con->sway_view; | 516 | struct sway_view *view = con->view; |
513 | view->x -= grow_width / 2; | 517 | view->x -= grow_width / 2; |
514 | view->y -= grow_height / 2; | 518 | view->y -= grow_height / 2; |
515 | view->width += grow_width; | 519 | view->width += grow_width; |
516 | view->height += grow_height; | 520 | view->height += grow_height; |
517 | } | 521 | } |
518 | 522 | ||
519 | arrange_windows(con); | 523 | arrange_container(con); |
520 | 524 | ||
521 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 525 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
522 | } | 526 | } |
@@ -555,7 +559,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) { | |||
555 | } | 559 | } |
556 | 560 | ||
557 | // If 0, don't resize that dimension | 561 | // If 0, don't resize that dimension |
558 | struct sway_container *con = config->handler_context.current_container; | 562 | struct sway_container *con = config->handler_context.container; |
559 | if (width.amount <= 0) { | 563 | if (width.amount <= 0) { |
560 | width.amount = con->width; | 564 | width.amount = con->width; |
561 | } | 565 | } |
@@ -624,7 +628,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, | |||
624 | first_amount.amount *= multiplier; | 628 | first_amount.amount *= multiplier; |
625 | second_amount.amount *= multiplier; | 629 | second_amount.amount *= multiplier; |
626 | 630 | ||
627 | struct sway_container *con = config->handler_context.current_container; | 631 | struct sway_container *con = config->handler_context.container; |
628 | if (container_is_floating(con)) { | 632 | if (container_is_floating(con)) { |
629 | // Floating containers can only resize in px. Choose an amount which | 633 | // Floating containers can only resize in px. Choose an amount which |
630 | // uses px, with fallback to an amount that specified no unit. | 634 | // uses px, with fallback to an amount that specified no unit. |
@@ -657,14 +661,10 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, | |||
657 | } | 661 | } |
658 | 662 | ||
659 | struct cmd_results *cmd_resize(int argc, char **argv) { | 663 | struct cmd_results *cmd_resize(int argc, char **argv) { |
660 | struct sway_container *current = config->handler_context.current_container; | 664 | struct sway_container *current = config->handler_context.container; |
661 | if (!current) { | 665 | if (!current) { |
662 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); | 666 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); |
663 | } | 667 | } |
664 | if (current->type != C_VIEW && current->type != C_CONTAINER) { | ||
665 | return cmd_results_new(CMD_INVALID, "resize", | ||
666 | "Can only resize views/containers"); | ||
667 | } | ||
668 | 668 | ||
669 | struct cmd_results *error; | 669 | struct cmd_results *error; |
670 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { | 670 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { |
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index 7da20015..d8bae615 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c | |||
@@ -9,36 +9,34 @@ | |||
9 | 9 | ||
10 | static void scratchpad_toggle_auto(void) { | 10 | static void scratchpad_toggle_auto(void) { |
11 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 11 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
12 | struct sway_container *focus = seat_get_focus(seat); | 12 | struct sway_container *focus = seat_get_focused_container(seat); |
13 | struct sway_container *ws = focus->type == C_WORKSPACE ? | 13 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
14 | focus : container_parent(focus, C_WORKSPACE); | ||
15 | 14 | ||
16 | // If the focus is in a floating split container, | 15 | // If the focus is in a floating split container, |
17 | // operate on the split container instead of the child. | 16 | // operate on the split container instead of the child. |
18 | if (container_is_floating_or_child(focus)) { | 17 | if (focus && container_is_floating_or_child(focus)) { |
19 | while (focus->parent->type != C_WORKSPACE) { | 18 | while (focus->parent) { |
20 | focus = focus->parent; | 19 | focus = focus->parent; |
21 | } | 20 | } |
22 | } | 21 | } |
23 | 22 | ||
24 | |||
25 | // Check if the currently focused window is a scratchpad window and should | 23 | // Check if the currently focused window is a scratchpad window and should |
26 | // be hidden again. | 24 | // be hidden again. |
27 | if (focus->scratchpad) { | 25 | if (focus && focus->scratchpad) { |
28 | wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", | 26 | wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", |
29 | focus->name); | 27 | focus->title); |
30 | root_scratchpad_hide(focus); | 28 | root_scratchpad_hide(focus); |
31 | return; | 29 | return; |
32 | } | 30 | } |
33 | 31 | ||
34 | // Check if there is an unfocused scratchpad window on the current workspace | 32 | // Check if there is an unfocused scratchpad window on the current workspace |
35 | // and focus it. | 33 | // and focus it. |
36 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | 34 | for (int i = 0; i < ws->floating->length; ++i) { |
37 | struct sway_container *floater = ws->sway_workspace->floating->items[i]; | 35 | struct sway_container *floater = ws->floating->items[i]; |
38 | if (floater->scratchpad && focus != floater) { | 36 | if (floater->scratchpad && focus != floater) { |
39 | wlr_log(WLR_DEBUG, | 37 | wlr_log(WLR_DEBUG, |
40 | "Focusing other scratchpad window (%s) in this workspace", | 38 | "Focusing other scratchpad window (%s) in this workspace", |
41 | floater->name); | 39 | floater->title); |
42 | root_scratchpad_show(floater); | 40 | root_scratchpad_show(floater); |
43 | return; | 41 | return; |
44 | } | 42 | } |
@@ -46,25 +44,23 @@ static void scratchpad_toggle_auto(void) { | |||
46 | 44 | ||
47 | // Check if there is a visible scratchpad window on another workspace. | 45 | // Check if there is a visible scratchpad window on another workspace. |
48 | // In this case we move it to the current workspace. | 46 | // In this case we move it to the current workspace. |
49 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | 47 | for (int i = 0; i < root->scratchpad->length; ++i) { |
50 | struct sway_container *con = | 48 | struct sway_container *con = root->scratchpad->items[i]; |
51 | root_container.sway_root->scratchpad->items[i]; | ||
52 | if (con->parent) { | 49 | if (con->parent) { |
53 | wlr_log(WLR_DEBUG, | 50 | wlr_log(WLR_DEBUG, |
54 | "Moving a visible scratchpad window (%s) to this workspace", | 51 | "Moving a visible scratchpad window (%s) to this workspace", |
55 | con->name); | 52 | con->title); |
56 | root_scratchpad_show(con); | 53 | root_scratchpad_show(con); |
57 | return; | 54 | return; |
58 | } | 55 | } |
59 | } | 56 | } |
60 | 57 | ||
61 | // Take the container at the bottom of the scratchpad list | 58 | // Take the container at the bottom of the scratchpad list |
62 | if (!sway_assert(root_container.sway_root->scratchpad->length, | 59 | if (!sway_assert(root->scratchpad->length, "Scratchpad is empty")) { |
63 | "Scratchpad is empty")) { | ||
64 | return; | 60 | return; |
65 | } | 61 | } |
66 | struct sway_container *con = root_container.sway_root->scratchpad->items[0]; | 62 | struct sway_container *con = root->scratchpad->items[0]; |
67 | wlr_log(WLR_DEBUG, "Showing %s from list", con->name); | 63 | wlr_log(WLR_DEBUG, "Showing %s from list", con->title); |
68 | root_scratchpad_show(con); | 64 | root_scratchpad_show(con); |
69 | } | 65 | } |
70 | 66 | ||
@@ -74,7 +70,7 @@ static void scratchpad_toggle_container(struct sway_container *con) { | |||
74 | } | 70 | } |
75 | 71 | ||
76 | // Check if it matches a currently visible scratchpad window and hide it. | 72 | // Check if it matches a currently visible scratchpad window and hide it. |
77 | if (con->parent) { | 73 | if (con->workspace) { |
78 | root_scratchpad_hide(con); | 74 | root_scratchpad_hide(con); |
79 | return; | 75 | return; |
80 | } | 76 | } |
@@ -91,18 +87,18 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { | |||
91 | return cmd_results_new(CMD_INVALID, "scratchpad", | 87 | return cmd_results_new(CMD_INVALID, "scratchpad", |
92 | "Expected 'scratchpad show'"); | 88 | "Expected 'scratchpad show'"); |
93 | } | 89 | } |
94 | if (!root_container.sway_root->scratchpad->length) { | 90 | if (!root->scratchpad->length) { |
95 | return cmd_results_new(CMD_INVALID, "scratchpad", | 91 | return cmd_results_new(CMD_INVALID, "scratchpad", |
96 | "Scratchpad is empty"); | 92 | "Scratchpad is empty"); |
97 | } | 93 | } |
98 | 94 | ||
99 | if (config->handler_context.using_criteria) { | 95 | if (config->handler_context.using_criteria) { |
100 | struct sway_container *con = config->handler_context.current_container; | 96 | struct sway_container *con = config->handler_context.container; |
101 | 97 | ||
102 | // If the container is in a floating split container, | 98 | // If the container is in a floating split container, |
103 | // operate on the split container instead of the child. | 99 | // operate on the split container instead of the child. |
104 | if (container_is_floating_or_child(con)) { | 100 | if (container_is_floating_or_child(con)) { |
105 | while (con->parent->type != C_WORKSPACE) { | 101 | while (con->parent) { |
106 | con = con->parent; | 102 | con = con->parent; |
107 | } | 103 | } |
108 | } | 104 | } |
diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 4d0a22c7..cd6630e0 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c | |||
@@ -42,8 +42,8 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { | |||
42 | return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); | 42 | return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); |
43 | } | 43 | } |
44 | // map absolute coords (0..1,0..1) to root container coords | 44 | // map absolute coords (0..1,0..1) to root container coords |
45 | float x = strtof(argv[1], NULL) / root_container.width; | 45 | float x = strtof(argv[1], NULL) / root->width; |
46 | float y = strtof(argv[2], NULL) / root_container.height; | 46 | float y = strtof(argv[2], NULL) / root->height; |
47 | wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); | 47 | wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); |
48 | cursor_send_pointer_motion(cursor, 0, true); | 48 | cursor_send_pointer_motion(cursor, 0, true); |
49 | } else { | 49 | } else { |
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index 1844e917..d501584a 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c | |||
@@ -11,8 +11,8 @@ | |||
11 | #include "util.h" | 11 | #include "util.h" |
12 | 12 | ||
13 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { | 13 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { |
14 | if (con->type == C_VIEW) { | 14 | if (con->view) { |
15 | view_update_marks_textures(con->sway_view); | 15 | view_update_marks_textures(con->view); |
16 | } | 16 | } |
17 | } | 17 | } |
18 | 18 | ||
@@ -28,9 +28,9 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) { | |||
28 | root_for_each_container(rebuild_marks_iterator, NULL); | 28 | root_for_each_container(rebuild_marks_iterator, NULL); |
29 | } | 29 | } |
30 | 30 | ||
31 | for (int i = 0; i < root_container.children->length; ++i) { | 31 | for (int i = 0; i < root->outputs->length; ++i) { |
32 | struct sway_container *con = root_container.children->items[i]; | 32 | struct sway_output *output = root->outputs->items[i]; |
33 | output_damage_whole(con->sway_output); | 33 | output_damage_whole(output); |
34 | } | 34 | } |
35 | 35 | ||
36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c index 7d27e571..273905df 100644 --- a/sway/commands/smart_gaps.c +++ b/sway/commands/smart_gaps.c | |||
@@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) { | |||
23 | "Expected 'smart_gaps <on|off>' "); | 23 | "Expected 'smart_gaps <on|off>' "); |
24 | } | 24 | } |
25 | 25 | ||
26 | arrange_windows(&root_container); | 26 | arrange_root(); |
27 | 27 | ||
28 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 28 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
29 | } | 29 | } |
diff --git a/sway/commands/split.c b/sway/commands/split.c index a8eddf54..9a53f3d3 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c | |||
@@ -4,15 +4,21 @@ | |||
4 | #include "sway/tree/arrange.h" | 4 | #include "sway/tree/arrange.h" |
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | 6 | #include "sway/tree/view.h" |
7 | #include "sway/tree/workspace.h" | ||
7 | #include "sway/input/input-manager.h" | 8 | #include "sway/input/input-manager.h" |
8 | #include "sway/input/seat.h" | 9 | #include "sway/input/seat.h" |
9 | #include "log.h" | 10 | #include "log.h" |
10 | 11 | ||
11 | static struct cmd_results *do_split(int layout) { | 12 | static struct cmd_results *do_split(int layout) { |
12 | struct sway_container *con = config->handler_context.current_container; | 13 | struct sway_container *con = config->handler_context.container; |
13 | struct sway_container *parent = container_split(con, layout); | 14 | struct sway_workspace *ws = config->handler_context.workspace; |
14 | container_create_notify(parent); | 15 | if (con) { |
15 | arrange_windows(parent->parent); | 16 | container_split(con, layout); |
17 | } else { | ||
18 | workspace_split(ws, layout); | ||
19 | } | ||
20 | |||
21 | arrange_workspace(ws); | ||
16 | 22 | ||
17 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 23 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
18 | } | 24 | } |
@@ -29,10 +35,9 @@ struct cmd_results *cmd_split(int argc, char **argv) { | |||
29 | return do_split(L_HORIZ); | 35 | return do_split(L_HORIZ); |
30 | } else if (strcasecmp(argv[0], "t") == 0 || | 36 | } else if (strcasecmp(argv[0], "t") == 0 || |
31 | strcasecmp(argv[0], "toggle") == 0) { | 37 | strcasecmp(argv[0], "toggle") == 0) { |
32 | struct sway_container *focused = | 38 | struct sway_container *focused = config->handler_context.container; |
33 | config->handler_context.current_container; | ||
34 | 39 | ||
35 | if (focused->parent->layout == L_VERT) { | 40 | if (focused && container_parent_layout(focused) == L_VERT) { |
36 | return do_split(L_HORIZ); | 41 | return do_split(L_HORIZ); |
37 | } else { | 42 | } else { |
38 | return do_split(L_VERT); | 43 | return do_split(L_VERT); |
@@ -66,9 +71,9 @@ struct cmd_results *cmd_splitt(int argc, char **argv) { | |||
66 | return error; | 71 | return error; |
67 | } | 72 | } |
68 | 73 | ||
69 | struct sway_container *con = config->handler_context.current_container; | 74 | struct sway_container *con = config->handler_context.container; |
70 | 75 | ||
71 | if (con->parent->layout == L_VERT) { | 76 | if (con && container_parent_layout(con) == L_VERT) { |
72 | return do_split(L_HORIZ); | 77 | return do_split(L_HORIZ); |
73 | } else { | 78 | } else { |
74 | return do_split(L_VERT); | 79 | return do_split(L_VERT); |
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 8692e08d..7995cdd6 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c | |||
@@ -15,8 +15,7 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { | |||
15 | if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { | 15 | if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { |
16 | return error; | 16 | return error; |
17 | } | 17 | } |
18 | struct sway_container *container = | 18 | struct sway_container *container = config->handler_context.container; |
19 | config->handler_context.current_container; | ||
20 | if (!container_is_floating(container)) { | 19 | if (!container_is_floating(container)) { |
21 | return cmd_results_new(CMD_FAILURE, "sticky", | 20 | return cmd_results_new(CMD_FAILURE, "sticky", |
22 | "Can't set sticky on a tiled container"); | 21 | "Can't set sticky on a tiled container"); |
@@ -37,20 +36,16 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { | |||
37 | container->is_sticky = wants_sticky; | 36 | container->is_sticky = wants_sticky; |
38 | 37 | ||
39 | if (wants_sticky) { | 38 | if (wants_sticky) { |
40 | // move container to focused workspace | 39 | // move container to active workspace |
41 | struct sway_container *output = container_parent(container, C_OUTPUT); | 40 | struct sway_workspace *active_workspace = |
42 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 41 | output_get_active_workspace(container->workspace->output); |
43 | struct sway_container *focus = seat_get_focus_inactive(seat, output); | 42 | if (container->workspace != active_workspace) { |
44 | struct sway_container *focused_workspace = container_parent(focus, C_WORKSPACE); | 43 | struct sway_workspace *old_workspace = container->workspace; |
45 | struct sway_container *current_workspace = container_parent(container, C_WORKSPACE); | 44 | container_detach(container); |
46 | if (current_workspace != focused_workspace) { | 45 | workspace_add_floating(active_workspace, container); |
47 | container_remove_child(container); | 46 | container_handle_fullscreen_reparent(container); |
48 | workspace_add_floating(focused_workspace, container); | 47 | arrange_workspace(active_workspace); |
49 | container_handle_fullscreen_reparent(container, current_workspace); | 48 | workspace_consider_destroy(old_workspace); |
50 | arrange_windows(focused_workspace); | ||
51 | if (!container_reap_empty(current_workspace)) { | ||
52 | arrange_windows(current_workspace); | ||
53 | } | ||
54 | } | 49 | } |
55 | } | 50 | } |
56 | 51 | ||
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index f25c43a1..a0ffbda8 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "config.h" | 4 | #include "config.h" |
5 | #include "log.h" | 5 | #include "log.h" |
6 | #include "sway/commands.h" | 6 | #include "sway/commands.h" |
7 | #include "sway/output.h" | ||
7 | #include "sway/tree/arrange.h" | 8 | #include "sway/tree/arrange.h" |
8 | #include "sway/tree/root.h" | 9 | #include "sway/tree/root.h" |
9 | #include "sway/tree/view.h" | 10 | #include "sway/tree/view.h" |
@@ -43,27 +44,28 @@ static void swap_focus(struct sway_container *con1, | |||
43 | struct sway_container *con2, struct sway_seat *seat, | 44 | struct sway_container *con2, struct sway_seat *seat, |
44 | struct sway_container *focus) { | 45 | struct sway_container *focus) { |
45 | if (focus == con1 || focus == con2) { | 46 | if (focus == con1 || focus == con2) { |
46 | struct sway_container *ws1 = container_parent(con1, C_WORKSPACE); | 47 | struct sway_workspace *ws1 = con1->workspace; |
47 | struct sway_container *ws2 = container_parent(con2, C_WORKSPACE); | 48 | struct sway_workspace *ws2 = con2->workspace; |
48 | if (focus == con1 && (con2->parent->layout == L_TABBED | 49 | enum sway_container_layout layout1 = container_parent_layout(con1); |
49 | || con2->parent->layout == L_STACKED)) { | 50 | enum sway_container_layout layout2 = container_parent_layout(con2); |
51 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { | ||
50 | if (workspace_is_visible(ws2)) { | 52 | if (workspace_is_visible(ws2)) { |
51 | seat_set_focus_warp(seat, con2, false, true); | 53 | seat_set_focus_warp(seat, &con2->node, false, true); |
52 | } | 54 | } |
53 | seat_set_focus(seat, ws1 != ws2 ? con2 : con1); | 55 | seat_set_focus(seat, ws1 != ws2 ? &con2->node : &con1->node); |
54 | } else if (focus == con2 && (con1->parent->layout == L_TABBED | 56 | } else if (focus == con2 && (layout1 == L_TABBED |
55 | || con1->parent->layout == L_STACKED)) { | 57 | || layout1 == L_STACKED)) { |
56 | if (workspace_is_visible(ws1)) { | 58 | if (workspace_is_visible(ws1)) { |
57 | seat_set_focus_warp(seat, con1, false, true); | 59 | seat_set_focus_warp(seat, &con1->node, false, true); |
58 | } | 60 | } |
59 | seat_set_focus(seat, ws1 != ws2 ? con1 : con2); | 61 | seat_set_focus(seat, ws1 != ws2 ? &con1->node : &con2->node); |
60 | } else if (ws1 != ws2) { | 62 | } else if (ws1 != ws2) { |
61 | seat_set_focus(seat, focus == con1 ? con2 : con1); | 63 | seat_set_focus(seat, focus == con1 ? &con2->node : &con1->node); |
62 | } else { | 64 | } else { |
63 | seat_set_focus(seat, focus); | 65 | seat_set_focus(seat, &focus->node); |
64 | } | 66 | } |
65 | } else { | 67 | } else { |
66 | seat_set_focus(seat, focus); | 68 | seat_set_focus(seat, &focus->node); |
67 | } | 69 | } |
68 | } | 70 | } |
69 | 71 | ||
@@ -72,10 +74,6 @@ static void container_swap(struct sway_container *con1, | |||
72 | if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { | 74 | if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { |
73 | return; | 75 | return; |
74 | } | 76 | } |
75 | if (!sway_assert(con1->type >= C_CONTAINER && con2->type >= C_CONTAINER, | ||
76 | "Can only swap containers and views")) { | ||
77 | return; | ||
78 | } | ||
79 | if (!sway_assert(!container_has_ancestor(con1, con2) | 77 | if (!sway_assert(!container_has_ancestor(con1, con2) |
80 | && !container_has_ancestor(con2, con1), | 78 | && !container_has_ancestor(con2, con1), |
81 | "Cannot swap ancestor and descendant")) { | 79 | "Cannot swap ancestor and descendant")) { |
@@ -87,10 +85,11 @@ static void container_swap(struct sway_container *con1, | |||
87 | return; | 85 | return; |
88 | } | 86 | } |
89 | 87 | ||
90 | wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); | 88 | wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", |
89 | con1->node.id, con2->node.id); | ||
91 | 90 | ||
92 | int fs1 = con1->is_fullscreen; | 91 | bool fs1 = con1->is_fullscreen; |
93 | int fs2 = con2->is_fullscreen; | 92 | bool fs2 = con2->is_fullscreen; |
94 | if (fs1) { | 93 | if (fs1) { |
95 | container_set_fullscreen(con1, false); | 94 | container_set_fullscreen(con1, false); |
96 | } | 95 | } |
@@ -99,13 +98,11 @@ static void container_swap(struct sway_container *con1, | |||
99 | } | 98 | } |
100 | 99 | ||
101 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | 100 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
102 | struct sway_container *focus = seat_get_focus(seat); | 101 | struct sway_container *focus = seat_get_focused_container(seat); |
103 | struct sway_container *vis1 = container_parent( | 102 | struct sway_workspace *vis1 = |
104 | seat_get_focus_inactive(seat, container_parent(con1, C_OUTPUT)), | 103 | output_get_active_workspace(con1->workspace->output); |
105 | C_WORKSPACE); | 104 | struct sway_workspace *vis2 = |
106 | struct sway_container *vis2 = container_parent( | 105 | output_get_active_workspace(con2->workspace->output); |
107 | seat_get_focus_inactive(seat, container_parent(con2, C_OUTPUT)), | ||
108 | C_WORKSPACE); | ||
109 | 106 | ||
110 | char *stored_prev_name = NULL; | 107 | char *stored_prev_name = NULL; |
111 | if (prev_workspace_name) { | 108 | if (prev_workspace_name) { |
@@ -115,10 +112,10 @@ static void container_swap(struct sway_container *con1, | |||
115 | swap_places(con1, con2); | 112 | swap_places(con1, con2); |
116 | 113 | ||
117 | if (!workspace_is_visible(vis1)) { | 114 | if (!workspace_is_visible(vis1)) { |
118 | seat_set_focus(seat, seat_get_focus_inactive(seat, vis1)); | 115 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node)); |
119 | } | 116 | } |
120 | if (!workspace_is_visible(vis2)) { | 117 | if (!workspace_is_visible(vis2)) { |
121 | seat_set_focus(seat, seat_get_focus_inactive(seat, vis2)); | 118 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node)); |
122 | } | 119 | } |
123 | 120 | ||
124 | swap_focus(con1, con2, seat, focus); | 121 | swap_focus(con1, con2, seat, focus); |
@@ -137,23 +134,22 @@ static void container_swap(struct sway_container *con1, | |||
137 | } | 134 | } |
138 | 135 | ||
139 | static bool test_con_id(struct sway_container *container, void *con_id) { | 136 | static bool test_con_id(struct sway_container *container, void *con_id) { |
140 | return container->id == (size_t)con_id; | 137 | return container->node.id == (size_t)con_id; |
141 | } | 138 | } |
142 | 139 | ||
143 | static bool test_id(struct sway_container *container, void *id) { | 140 | static bool test_id(struct sway_container *container, void *id) { |
144 | #ifdef HAVE_XWAYLAND | 141 | #ifdef HAVE_XWAYLAND |
145 | xcb_window_t *wid = id; | 142 | xcb_window_t *wid = id; |
146 | return (container->type == C_VIEW | 143 | return (container->view && container->view->type == SWAY_VIEW_XWAYLAND |
147 | && container->sway_view->type == SWAY_VIEW_XWAYLAND | 144 | && container->view->wlr_xwayland_surface->window_id == *wid); |
148 | && container->sway_view->wlr_xwayland_surface->window_id == *wid); | ||
149 | #else | 145 | #else |
150 | return false; | 146 | return false; |
151 | #endif | 147 | #endif |
152 | } | 148 | } |
153 | 149 | ||
154 | static bool test_mark(struct sway_container *container, void *mark) { | 150 | static bool test_mark(struct sway_container *container, void *mark) { |
155 | if (container->type == C_VIEW && container->sway_view->marks->length) { | 151 | if (container->view && container->view->marks->length) { |
156 | return !list_seq_find(container->sway_view->marks, | 152 | return !list_seq_find(container->view->marks, |
157 | (int (*)(const void *, const void *))strcmp, mark); | 153 | (int (*)(const void *, const void *))strcmp, mark); |
158 | } | 154 | } |
159 | return false; | 155 | return false; |
@@ -169,7 +165,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
169 | return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); | 165 | return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); |
170 | } | 166 | } |
171 | 167 | ||
172 | struct sway_container *current = config->handler_context.current_container; | 168 | struct sway_container *current = config->handler_context.container; |
173 | struct sway_container *other; | 169 | struct sway_container *other; |
174 | 170 | ||
175 | char *value = join_args(argv + 3, argc - 3); | 171 | char *value = join_args(argv + 3, argc - 3); |
@@ -191,7 +187,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
191 | if (!other) { | 187 | if (!other) { |
192 | error = cmd_results_new(CMD_FAILURE, "swap", | 188 | error = cmd_results_new(CMD_FAILURE, "swap", |
193 | "Failed to find %s '%s'", argv[2], value); | 189 | "Failed to find %s '%s'", argv[2], value); |
194 | } else if (current->type < C_CONTAINER || other->type < C_CONTAINER) { | 190 | } else if (!current) { |
195 | error = cmd_results_new(CMD_FAILURE, "swap", | 191 | error = cmd_results_new(CMD_FAILURE, "swap", |
196 | "Can only swap with containers and views"); | 192 | "Can only swap with containers and views"); |
197 | } else if (container_has_ancestor(current, other) | 193 | } else if (container_has_ancestor(current, other) |
@@ -211,9 +207,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
211 | 207 | ||
212 | container_swap(current, other); | 208 | container_swap(current, other); |
213 | 209 | ||
214 | arrange_windows(current->parent); | 210 | arrange_node(node_get_parent(¤t->node)); |
215 | if (other->parent != current->parent) { | 211 | if (node_get_parent(&other->node) != node_get_parent(¤t->node)) { |
216 | arrange_windows(other->parent); | 212 | arrange_node(node_get_parent(&other->node)); |
217 | } | 213 | } |
218 | 214 | ||
219 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 215 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 3d1c578c..c9ffe8fa 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c | |||
@@ -11,13 +11,12 @@ struct cmd_results *cmd_title_format(int argc, char **argv) { | |||
11 | if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) { | 11 | if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) { |
12 | return error; | 12 | return error; |
13 | } | 13 | } |
14 | struct sway_container *container = | 14 | struct sway_container *container = config->handler_context.container; |
15 | config->handler_context.current_container; | 15 | if (!container->view) { |
16 | if (container->type != C_VIEW) { | ||
17 | return cmd_results_new(CMD_INVALID, "title_format", | 16 | return cmd_results_new(CMD_INVALID, "title_format", |
18 | "Only views can have a title_format"); | 17 | "Only views can have a title_format"); |
19 | } | 18 | } |
20 | struct sway_view *view = container->sway_view; | 19 | struct sway_view *view = container->view; |
21 | char *format = join_args(argv, argc); | 20 | char *format = join_args(argv, argc); |
22 | if (view->title_format) { | 21 | if (view->title_format) { |
23 | free(view->title_format); | 22 | free(view->title_format); |
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index 62127c97..c6251dc8 100644 --- a/sway/commands/unmark.c +++ b/sway/commands/unmark.c | |||
@@ -9,9 +9,9 @@ | |||
9 | #include "stringop.h" | 9 | #include "stringop.h" |
10 | 10 | ||
11 | static void remove_all_marks_iterator(struct sway_container *con, void *data) { | 11 | static void remove_all_marks_iterator(struct sway_container *con, void *data) { |
12 | if (con->type == C_VIEW) { | 12 | if (con->view) { |
13 | view_clear_marks(con->sway_view); | 13 | view_clear_marks(con->view); |
14 | view_update_marks_textures(con->sway_view); | 14 | view_update_marks_textures(con->view); |
15 | } | 15 | } |
16 | } | 16 | } |
17 | 17 | ||
@@ -24,13 +24,12 @@ struct cmd_results *cmd_unmark(int argc, char **argv) { | |||
24 | // Determine the view | 24 | // Determine the view |
25 | struct sway_view *view = NULL; | 25 | struct sway_view *view = NULL; |
26 | if (config->handler_context.using_criteria) { | 26 | if (config->handler_context.using_criteria) { |
27 | struct sway_container *container = | 27 | struct sway_container *container = config->handler_context.container; |
28 | config->handler_context.current_container; | 28 | if (!container->view) { |
29 | if (container->type != C_VIEW) { | ||
30 | return cmd_results_new(CMD_INVALID, "unmark", | 29 | return cmd_results_new(CMD_INVALID, "unmark", |
31 | "Only views can have marks"); | 30 | "Only views can have marks"); |
32 | } | 31 | } |
33 | view = container->sway_view; | 32 | view = container->view; |
34 | } | 33 | } |
35 | 34 | ||
36 | // Determine the mark | 35 | // Determine the mark |
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c index bccb33fe..53c37d4d 100644 --- a/sway/commands/urgent.c +++ b/sway/commands/urgent.c | |||
@@ -11,13 +11,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) { | |||
11 | if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { | 11 | if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { |
12 | return error; | 12 | return error; |
13 | } | 13 | } |
14 | struct sway_container *container = | 14 | struct sway_container *container = config->handler_context.container; |
15 | config->handler_context.current_container; | 15 | if (!container->view) { |
16 | if (container->type != C_VIEW) { | ||
17 | return cmd_results_new(CMD_INVALID, "urgent", | 16 | return cmd_results_new(CMD_INVALID, "urgent", |
18 | "Only views can be urgent"); | 17 | "Only views can be urgent"); |
19 | } | 18 | } |
20 | struct sway_view *view = container->sway_view; | 19 | struct sway_view *view = container->view; |
21 | 20 | ||
22 | if (strcmp(argv[0], "allow") == 0) { | 21 | if (strcmp(argv[0], "allow") == 0) { |
23 | view->allow_request_urgent = true; | 22 | view->allow_request_urgent = true; |
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index ceb4cd6e..f026a39d 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -58,7 +58,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | 60 | ||
61 | struct sway_container *ws = NULL; | 61 | struct sway_workspace *ws = NULL; |
62 | if (strcasecmp(argv[0], "number") == 0) { | 62 | if (strcasecmp(argv[0], "number") == 0) { |
63 | if (argc < 2) { | 63 | if (argc < 2) { |
64 | return cmd_results_new(CMD_INVALID, "workspace", | 64 | return cmd_results_new(CMD_INVALID, "workspace", |
diff --git a/sway/config.c b/sway/config.c index 8105722a..89701640 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -825,6 +825,6 @@ void config_update_font_height(bool recalculate) { | |||
825 | root_for_each_container(find_font_height_iterator, &recalculate); | 825 | root_for_each_container(find_font_height_iterator, &recalculate); |
826 | 826 | ||
827 | if (config->font_height != prev_max_height) { | 827 | if (config->font_height != prev_max_height) { |
828 | arrange_windows(&root_container); | 828 | arrange_root(); |
829 | } | 829 | } |
830 | } | 830 | } |
diff --git a/sway/config/bar.c b/sway/config/bar.c index ae9383d6..f83b37d1 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <strings.h> | 12 | #include <strings.h> |
13 | #include <signal.h> | 13 | #include <signal.h> |
14 | #include "sway/config.h" | 14 | #include "sway/config.h" |
15 | #include "sway/output.h" | ||
15 | #include "stringop.h" | 16 | #include "stringop.h" |
16 | #include "list.h" | 17 | #include "list.h" |
17 | #include "log.h" | 18 | #include "log.h" |
@@ -218,17 +219,6 @@ void invoke_swaybar(struct bar_config *bar) { | |||
218 | close(filedes[1]); | 219 | close(filedes[1]); |
219 | } | 220 | } |
220 | 221 | ||
221 | static bool active_output(const char *name) { | ||
222 | struct sway_container *cont = NULL; | ||
223 | for (int i = 0; i < root_container.children->length; ++i) { | ||
224 | cont = root_container.children->items[i]; | ||
225 | if (cont->type == C_OUTPUT && strcasecmp(name, cont->name) == 0) { | ||
226 | return true; | ||
227 | } | ||
228 | } | ||
229 | return false; | ||
230 | } | ||
231 | |||
232 | void load_swaybars() { | 222 | void load_swaybars() { |
233 | for (int i = 0; i < config->bars->length; ++i) { | 223 | for (int i = 0; i < config->bars->length; ++i) { |
234 | struct bar_config *bar = config->bars->items[i]; | 224 | struct bar_config *bar = config->bars->items[i]; |
@@ -236,7 +226,7 @@ void load_swaybars() { | |||
236 | if (bar->outputs) { | 226 | if (bar->outputs) { |
237 | for (int j = 0; j < bar->outputs->length; ++j) { | 227 | for (int j = 0; j < bar->outputs->length; ++j) { |
238 | char *o = bar->outputs->items[j]; | 228 | char *o = bar->outputs->items[j]; |
239 | if (!strcmp(o, "*") || active_output(o)) { | 229 | if (!strcmp(o, "*") || output_by_name(o)) { |
240 | apply = true; | 230 | apply = true; |
241 | break; | 231 | break; |
242 | } | 232 | } |
diff --git a/sway/config/output.c b/sway/config/output.c index 65f09258..aa53fc46 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -174,21 +174,16 @@ void terminate_swaybg(pid_t pid) { | |||
174 | } | 174 | } |
175 | } | 175 | } |
176 | 176 | ||
177 | void apply_output_config(struct output_config *oc, struct sway_container *output) { | 177 | void apply_output_config(struct output_config *oc, struct sway_output *output) { |
178 | assert(output->type == C_OUTPUT); | 178 | struct wlr_output *wlr_output = output->wlr_output; |
179 | |||
180 | struct wlr_output_layout *output_layout = | ||
181 | root_container.sway_root->output_layout; | ||
182 | struct wlr_output *wlr_output = output->sway_output->wlr_output; | ||
183 | 179 | ||
184 | if (oc && oc->enabled == 0) { | 180 | if (oc && oc->enabled == 0) { |
185 | if (output->sway_output->bg_pid != 0) { | 181 | if (output->bg_pid != 0) { |
186 | terminate_swaybg(output->sway_output->bg_pid); | 182 | terminate_swaybg(output->bg_pid); |
187 | output->sway_output->bg_pid = 0; | 183 | output->bg_pid = 0; |
188 | } | 184 | } |
189 | output_begin_destroy(output); | 185 | output_disable(output); |
190 | wlr_output_layout_remove(root_container.sway_root->output_layout, | 186 | wlr_output_layout_remove(root->output_layout, wlr_output); |
191 | wlr_output); | ||
192 | return; | 187 | return; |
193 | } | 188 | } |
194 | 189 | ||
@@ -213,21 +208,21 @@ void apply_output_config(struct output_config *oc, struct sway_container *output | |||
213 | // Find position for it | 208 | // Find position for it |
214 | if (oc && (oc->x != -1 || oc->y != -1)) { | 209 | if (oc && (oc->x != -1 || oc->y != -1)) { |
215 | wlr_log(WLR_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); | 210 | wlr_log(WLR_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); |
216 | wlr_output_layout_add(output_layout, wlr_output, oc->x, oc->y); | 211 | wlr_output_layout_add(root->output_layout, wlr_output, oc->x, oc->y); |
217 | } else { | 212 | } else { |
218 | wlr_output_layout_add_auto(output_layout, wlr_output); | 213 | wlr_output_layout_add_auto(root->output_layout, wlr_output); |
219 | } | 214 | } |
220 | 215 | ||
221 | int output_i; | 216 | int output_i; |
222 | for (output_i = 0; output_i < root_container.children->length; ++output_i) { | 217 | for (output_i = 0; output_i < root->outputs->length; ++output_i) { |
223 | if (root_container.children->items[output_i] == output) { | 218 | if (root->outputs->items[output_i] == output) { |
224 | break; | 219 | break; |
225 | } | 220 | } |
226 | } | 221 | } |
227 | 222 | ||
228 | if (oc && oc->background) { | 223 | if (oc && oc->background) { |
229 | if (output->sway_output->bg_pid != 0) { | 224 | if (output->bg_pid != 0) { |
230 | terminate_swaybg(output->sway_output->bg_pid); | 225 | terminate_swaybg(output->bg_pid); |
231 | } | 226 | } |
232 | 227 | ||
233 | wlr_log(WLR_DEBUG, "Setting background for output %d to %s", | 228 | wlr_log(WLR_DEBUG, "Setting background for output %d to %s", |
@@ -249,8 +244,8 @@ void apply_output_config(struct output_config *oc, struct sway_container *output | |||
249 | wlr_log(WLR_DEBUG, "-> %s", command); | 244 | wlr_log(WLR_DEBUG, "-> %s", command); |
250 | 245 | ||
251 | char *const cmd[] = { "sh", "-c", command, NULL }; | 246 | char *const cmd[] = { "sh", "-c", command, NULL }; |
252 | output->sway_output->bg_pid = fork(); | 247 | output->bg_pid = fork(); |
253 | if (output->sway_output->bg_pid == 0) { | 248 | if (output->bg_pid == 0) { |
254 | execvp(cmd[0], cmd); | 249 | execvp(cmd[0], cmd); |
255 | } else { | 250 | } else { |
256 | free(command); | 251 | free(command); |
@@ -293,12 +288,11 @@ void apply_output_config_to_outputs(struct output_config *oc) { | |||
293 | bool wildcard = strcmp(oc->name, "*") == 0; | 288 | bool wildcard = strcmp(oc->name, "*") == 0; |
294 | char id[128]; | 289 | char id[128]; |
295 | struct sway_output *sway_output; | 290 | struct sway_output *sway_output; |
296 | wl_list_for_each(sway_output, | 291 | wl_list_for_each(sway_output, &root->all_outputs, link) { |
297 | &root_container.sway_root->all_outputs, link) { | ||
298 | char *name = sway_output->wlr_output->name; | 292 | char *name = sway_output->wlr_output->name; |
299 | output_get_identifier(id, sizeof(id), sway_output); | 293 | output_get_identifier(id, sizeof(id), sway_output); |
300 | if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) { | 294 | if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) { |
301 | if (!sway_output->swayc) { | 295 | if (!sway_output->enabled) { |
302 | if (!oc->enabled) { | 296 | if (!oc->enabled) { |
303 | if (!wildcard) { | 297 | if (!wildcard) { |
304 | break; | 298 | break; |
@@ -306,7 +300,7 @@ void apply_output_config_to_outputs(struct output_config *oc) { | |||
306 | continue; | 300 | continue; |
307 | } | 301 | } |
308 | 302 | ||
309 | output_enable(sway_output); | 303 | output_enable(sway_output, oc); |
310 | } | 304 | } |
311 | 305 | ||
312 | struct output_config *current = oc; | 306 | struct output_config *current = oc; |
@@ -316,7 +310,7 @@ void apply_output_config_to_outputs(struct output_config *oc) { | |||
316 | current = tmp; | 310 | current = tmp; |
317 | } | 311 | } |
318 | } | 312 | } |
319 | apply_output_config(current, sway_output->swayc); | 313 | apply_output_config(current, sway_output); |
320 | 314 | ||
321 | if (!wildcard) { | 315 | if (!wildcard) { |
322 | // Stop looking if the output config isn't applicable to all | 316 | // Stop looking if the output config isn't applicable to all |
@@ -354,8 +348,7 @@ static void default_output_config(struct output_config *oc, | |||
354 | 348 | ||
355 | void create_default_output_configs(void) { | 349 | void create_default_output_configs(void) { |
356 | struct sway_output *sway_output; | 350 | struct sway_output *sway_output; |
357 | wl_list_for_each(sway_output, | 351 | wl_list_for_each(sway_output, &root->all_outputs, link) { |
358 | &root_container.sway_root->all_outputs, link) { | ||
359 | char *name = sway_output->wlr_output->name; | 352 | char *name = sway_output->wlr_output->name; |
360 | struct output_config *oc = new_output_config(name); | 353 | struct output_config *oc = new_output_config(name); |
361 | default_output_config(oc, sway_output->wlr_output); | 354 | default_output_config(oc, sway_output->wlr_output); |
diff --git a/sway/criteria.c b/sway/criteria.c index feca904a..e5b308e0 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "sway/config.h" | 9 | #include "sway/config.h" |
10 | #include "sway/tree/root.h" | 10 | #include "sway/tree/root.h" |
11 | #include "sway/tree/view.h" | 11 | #include "sway/tree/view.h" |
12 | #include "sway/tree/workspace.h" | ||
12 | #include "stringop.h" | 13 | #include "stringop.h" |
13 | #include "list.h" | 14 | #include "list.h" |
14 | #include "log.h" | 15 | #include "log.h" |
@@ -87,12 +88,12 @@ static int cmp_urgent(const void *_a, const void *_b) { | |||
87 | return 0; | 88 | return 0; |
88 | } | 89 | } |
89 | 90 | ||
90 | static void find_urgent_iterator(struct sway_container *swayc, void *data) { | 91 | static void find_urgent_iterator(struct sway_container *con, void *data) { |
91 | if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) { | 92 | if (!con->view || !view_is_urgent(con->view)) { |
92 | return; | 93 | return; |
93 | } | 94 | } |
94 | list_t *urgent_views = data; | 95 | list_t *urgent_views = data; |
95 | list_add(urgent_views, swayc->sway_view); | 96 | list_add(urgent_views, con->view); |
96 | } | 97 | } |
97 | 98 | ||
98 | static bool criteria_matches_view(struct criteria *criteria, | 99 | static bool criteria_matches_view(struct criteria *criteria, |
@@ -132,7 +133,7 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
132 | } | 133 | } |
133 | 134 | ||
134 | if (criteria->con_id) { // Internal ID | 135 | if (criteria->con_id) { // Internal ID |
135 | if (!view->swayc || view->swayc->id != criteria->con_id) { | 136 | if (!view->container || view->container->node.id != criteria->con_id) { |
136 | return false; | 137 | return false; |
137 | } | 138 | } |
138 | } | 139 | } |
@@ -174,13 +175,13 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
174 | #endif | 175 | #endif |
175 | 176 | ||
176 | if (criteria->floating) { | 177 | if (criteria->floating) { |
177 | if (!container_is_floating(view->swayc)) { | 178 | if (!container_is_floating(view->container)) { |
178 | return false; | 179 | return false; |
179 | } | 180 | } |
180 | } | 181 | } |
181 | 182 | ||
182 | if (criteria->tiling) { | 183 | if (criteria->tiling) { |
183 | if (container_is_floating(view->swayc)) { | 184 | if (container_is_floating(view->container)) { |
184 | return false; | 185 | return false; |
185 | } | 186 | } |
186 | } | 187 | } |
@@ -205,10 +206,7 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
205 | } | 206 | } |
206 | 207 | ||
207 | if (criteria->workspace) { | 208 | if (criteria->workspace) { |
208 | if (!view->swayc) { | 209 | struct sway_workspace *ws = view->container->workspace; |
209 | return false; | ||
210 | } | ||
211 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | ||
212 | if (!ws || strcmp(ws->name, criteria->workspace) != 0) { | 210 | if (!ws || strcmp(ws->name, criteria->workspace) != 0) { |
213 | return false; | 211 | return false; |
214 | } | 212 | } |
@@ -237,9 +235,9 @@ struct match_data { | |||
237 | static void criteria_get_views_iterator(struct sway_container *container, | 235 | static void criteria_get_views_iterator(struct sway_container *container, |
238 | void *data) { | 236 | void *data) { |
239 | struct match_data *match_data = data; | 237 | struct match_data *match_data = data; |
240 | if (container->type == C_VIEW) { | 238 | if (!container->view) { |
241 | if (criteria_matches_view(match_data->criteria, container->sway_view)) { | 239 | if (criteria_matches_view(match_data->criteria, container->view)) { |
242 | list_add(match_data->matches, container->sway_view); | 240 | list_add(match_data->matches, container->view); |
243 | } | 241 | } |
244 | } | 242 | } |
245 | } | 243 | } |
@@ -355,12 +353,12 @@ static enum criteria_token token_from_name(char *name) { | |||
355 | */ | 353 | */ |
356 | static char *get_focused_prop(enum criteria_token token) { | 354 | static char *get_focused_prop(enum criteria_token token) { |
357 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 355 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
358 | struct sway_container *focus = seat_get_focus(seat); | 356 | struct sway_container *focus = seat_get_focused_container(seat); |
359 | 357 | ||
360 | if (!focus || focus->type != C_VIEW) { | 358 | if (!focus || !focus->view) { |
361 | return NULL; | 359 | return NULL; |
362 | } | 360 | } |
363 | struct sway_view *view = focus->sway_view; | 361 | struct sway_view *view = focus->view; |
364 | const char *value = NULL; | 362 | const char *value = NULL; |
365 | 363 | ||
366 | switch (token) { | 364 | switch (token) { |
@@ -374,18 +372,15 @@ static char *get_focused_prop(enum criteria_token token) { | |||
374 | value = view_get_title(view); | 372 | value = view_get_title(view); |
375 | break; | 373 | break; |
376 | case T_WORKSPACE: | 374 | case T_WORKSPACE: |
377 | { | 375 | if (focus->workspace) { |
378 | struct sway_container *ws = container_parent(focus, C_WORKSPACE); | 376 | value = focus->workspace->name; |
379 | if (ws) { | ||
380 | value = ws->name; | ||
381 | } | ||
382 | } | 377 | } |
383 | break; | 378 | break; |
384 | case T_CON_ID: | 379 | case T_CON_ID: |
385 | if (view->swayc == NULL) { | 380 | if (view->container == NULL) { |
386 | return NULL; | 381 | return NULL; |
387 | } | 382 | } |
388 | size_t id = view->swayc->id; | 383 | size_t id = view->container->node.id; |
389 | size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; | 384 | size_t id_size = snprintf(NULL, 0, "%zu", id) + 1; |
390 | char *id_str = malloc(id_size); | 385 | char *id_str = malloc(id_size); |
391 | snprintf(id_str, id_size, "%zu", id); | 386 | snprintf(id_str, id_size, "%zu", id); |
diff --git a/sway/debug-tree.c b/sway/debug-tree.c index 2768cf58..2ed3c087 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "sway/server.h" | 10 | #include "sway/server.h" |
11 | #include "sway/tree/container.h" | 11 | #include "sway/tree/container.h" |
12 | #include "sway/tree/root.h" | 12 | #include "sway/tree/root.h" |
13 | #include "sway/tree/workspace.h" | ||
13 | #include "cairo.h" | 14 | #include "cairo.h" |
14 | #include "config.h" | 15 | #include "config.h" |
15 | #include "pango.h" | 16 | #include "pango.h" |
@@ -32,28 +33,78 @@ static const char *layout_to_str(enum sway_container_layout layout) { | |||
32 | return "L_NONE"; | 33 | return "L_NONE"; |
33 | } | 34 | } |
34 | 35 | ||
35 | static int draw_container(cairo_t *cairo, struct sway_container *container, | 36 | static char *get_string(struct sway_node *node) { |
36 | struct sway_container *focus, int x, int y) { | 37 | char *buffer = malloc(512); |
38 | switch (node->type) { | ||
39 | case N_ROOT: | ||
40 | snprintf(buffer, 512, "N_ROOT id:%zd %.fx%.f@%.f,%.f", node->id, | ||
41 | root->width, root->height, root->x, root->y); | ||
42 | break; | ||
43 | case N_OUTPUT: | ||
44 | snprintf(buffer, 512, "N_OUTPUT id:%zd '%s' %dx%d@%d,%d", node->id, | ||
45 | node->sway_output->wlr_output->name, | ||
46 | node->sway_output->wlr_output->width, | ||
47 | node->sway_output->wlr_output->height, | ||
48 | node->sway_output->wlr_output->lx, | ||
49 | node->sway_output->wlr_output->ly); | ||
50 | break; | ||
51 | case N_WORKSPACE: | ||
52 | snprintf(buffer, 512, "N_WORKSPACE id:%zd '%s' %s %dx%d@%.f,%.f", | ||
53 | node->id, node->sway_workspace->name, | ||
54 | layout_to_str(node->sway_workspace->layout), | ||
55 | node->sway_workspace->width, node->sway_workspace->height, | ||
56 | node->sway_workspace->x, node->sway_workspace->y); | ||
57 | break; | ||
58 | case N_CONTAINER: | ||
59 | snprintf(buffer, 512, "N_CONTAINER id:%zd '%s' %s %.fx%.f@%.f,%.f", | ||
60 | node->id, node->sway_container->title, | ||
61 | layout_to_str(node->sway_container->layout), | ||
62 | node->sway_container->width, node->sway_container->height, | ||
63 | node->sway_container->x, node->sway_container->y); | ||
64 | break; | ||
65 | } | ||
66 | return buffer; | ||
67 | } | ||
68 | |||
69 | static list_t *get_children(struct sway_node *node) { | ||
70 | switch (node->type) { | ||
71 | case N_ROOT: | ||
72 | return root->outputs; | ||
73 | case N_OUTPUT: | ||
74 | return node->sway_output->workspaces; | ||
75 | case N_WORKSPACE: | ||
76 | return node->sway_workspace->tiling; | ||
77 | case N_CONTAINER: | ||
78 | return node->sway_container->children; | ||
79 | } | ||
80 | return NULL; | ||
81 | } | ||
82 | |||
83 | static int draw_node(cairo_t *cairo, struct sway_node *node, | ||
84 | struct sway_node *focus, int x, int y) { | ||
37 | int text_width, text_height; | 85 | int text_width, text_height; |
86 | char *buffer = get_string(node); | ||
38 | get_text_size(cairo, "monospace", &text_width, &text_height, | 87 | get_text_size(cairo, "monospace", &text_width, &text_height, |
39 | 1, false, "%s id:%zd '%s' %s %.fx%.f@%.f,%.f", | 88 | 1, false, buffer); |
40 | container_type_to_str(container->type), container->id, container->name, | ||
41 | layout_to_str(container->layout), | ||
42 | container->width, container->height, container->x, container->y); | ||
43 | cairo_save(cairo); | 89 | cairo_save(cairo); |
44 | cairo_rectangle(cairo, x + 2, y, text_width - 2, text_height); | 90 | cairo_rectangle(cairo, x + 2, y, text_width - 2, text_height); |
45 | cairo_set_source_u32(cairo, 0xFFFFFFE0); | 91 | cairo_set_source_u32(cairo, 0xFFFFFFE0); |
46 | cairo_fill(cairo); | 92 | cairo_fill(cairo); |
47 | int height = text_height; | 93 | int height = text_height; |
48 | if (container->children) { | 94 | list_t *children = get_children(node); |
49 | for (int i = 0; i < container->children->length; ++i) { | 95 | if (children) { |
50 | struct sway_container *child = container->children->items[i]; | 96 | for (int i = 0; i < children->length; ++i) { |
51 | if (child->parent == container) { | 97 | // This is really dirty - the list contains specific structs but |
98 | // we're casting them as nodes. This works because node is the first | ||
99 | // item in each specific struct. This is acceptable because this is | ||
100 | // debug code. | ||
101 | struct sway_node *child = children->items[i]; | ||
102 | if (node_get_parent(child) == node) { | ||
52 | cairo_set_source_u32(cairo, 0x000000FF); | 103 | cairo_set_source_u32(cairo, 0x000000FF); |
53 | } else { | 104 | } else { |
54 | cairo_set_source_u32(cairo, 0xFF0000FF); | 105 | cairo_set_source_u32(cairo, 0xFF0000FF); |
55 | } | 106 | } |
56 | height += draw_container(cairo, child, focus, x + 10, y + height); | 107 | height += draw_node(cairo, child, focus, x + 10, y + height); |
57 | } | 108 | } |
58 | } | 109 | } |
59 | cairo_set_source_u32(cairo, 0xFFFFFFE0); | 110 | cairo_set_source_u32(cairo, 0xFFFFFFE0); |
@@ -61,13 +112,11 @@ static int draw_container(cairo_t *cairo, struct sway_container *container, | |||
61 | cairo_fill(cairo); | 112 | cairo_fill(cairo); |
62 | cairo_restore(cairo); | 113 | cairo_restore(cairo); |
63 | cairo_move_to(cairo, x, y); | 114 | cairo_move_to(cairo, x, y); |
64 | if (focus == container) { | 115 | if (focus == node) { |
65 | cairo_set_source_u32(cairo, 0x0000FFFF); | 116 | cairo_set_source_u32(cairo, 0x0000FFFF); |
66 | } | 117 | } |
67 | pango_printf(cairo, "monospace", 1, false, "%s id:%zd '%s' %s %.fx%.f@%.f,%.f", | 118 | pango_printf(cairo, "monospace", 1, false, buffer); |
68 | container_type_to_str(container->type), container->id, container->name, | 119 | free(buffer); |
69 | layout_to_str(container->layout), | ||
70 | container->width, container->height, container->x, container->y); | ||
71 | return height; | 120 | return height; |
72 | } | 121 | } |
73 | 122 | ||
@@ -77,13 +126,13 @@ void update_debug_tree() { | |||
77 | } | 126 | } |
78 | 127 | ||
79 | int width = 640, height = 480; | 128 | int width = 640, height = 480; |
80 | for (int i = 0; i < root_container.children->length; ++i) { | 129 | for (int i = 0; i < root->outputs->length; ++i) { |
81 | struct sway_container *container = root_container.children->items[i]; | 130 | struct sway_output *output = root->outputs->items[i]; |
82 | if (container->width > width) { | 131 | if (output->wlr_output->width > width) { |
83 | width = container->width; | 132 | width = output->wlr_output->width; |
84 | } | 133 | } |
85 | if (container->height > height) { | 134 | if (output->wlr_output->height > height) { |
86 | height = container->height; | 135 | height = output->wlr_output->height; |
87 | } | 136 | } |
88 | } | 137 | } |
89 | cairo_surface_t *surface = | 138 | cairo_surface_t *surface = |
@@ -91,28 +140,22 @@ void update_debug_tree() { | |||
91 | cairo_t *cairo = cairo_create(surface); | 140 | cairo_t *cairo = cairo_create(surface); |
92 | PangoContext *pango = pango_cairo_create_context(cairo); | 141 | PangoContext *pango = pango_cairo_create_context(cairo); |
93 | 142 | ||
94 | struct sway_seat *seat = NULL; | 143 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
95 | wl_list_for_each(seat, &input_manager->seats, link) { | 144 | struct sway_node *focus = seat_get_focus(seat); |
96 | break; | ||
97 | } | ||
98 | 145 | ||
99 | struct sway_container *focus = NULL; | ||
100 | if (seat != NULL) { | ||
101 | focus = seat_get_focus(seat); | ||
102 | } | ||
103 | cairo_set_source_u32(cairo, 0x000000FF); | 146 | cairo_set_source_u32(cairo, 0x000000FF); |
104 | draw_container(cairo, &root_container, focus, 0, 0); | 147 | draw_node(cairo, &root->node, focus, 0, 0); |
105 | 148 | ||
106 | cairo_surface_flush(surface); | 149 | cairo_surface_flush(surface); |
107 | struct wlr_renderer *renderer = wlr_backend_get_renderer(server.backend); | 150 | struct wlr_renderer *renderer = wlr_backend_get_renderer(server.backend); |
108 | if (root_container.sway_root->debug_tree) { | 151 | if (root->debug_tree) { |
109 | wlr_texture_destroy(root_container.sway_root->debug_tree); | 152 | wlr_texture_destroy(root->debug_tree); |
110 | } | 153 | } |
111 | unsigned char *data = cairo_image_surface_get_data(surface); | 154 | unsigned char *data = cairo_image_surface_get_data(surface); |
112 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); | 155 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); |
113 | struct wlr_texture *texture = wlr_texture_from_pixels(renderer, | 156 | struct wlr_texture *texture = wlr_texture_from_pixels(renderer, |
114 | WL_SHM_FORMAT_ARGB8888, stride, width, height, data); | 157 | WL_SHM_FORMAT_ARGB8888, stride, width, height, data); |
115 | root_container.sway_root->debug_tree = texture; | 158 | root->debug_tree = texture; |
116 | cairo_surface_destroy(surface); | 159 | cairo_surface_destroy(surface); |
117 | g_object_unref(pango); | 160 | g_object_unref(pango); |
118 | cairo_destroy(cairo); | 161 | cairo_destroy(cairo); |
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index 72650397..771b58fe 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c | |||
@@ -4,37 +4,32 @@ | |||
4 | 4 | ||
5 | void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, | 5 | void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, |
6 | bool whole) { | 6 | bool whole) { |
7 | for (int i = 0; i < root_container.children->length; ++i) { | 7 | for (int i = 0; i < root->outputs->length; ++i) { |
8 | struct sway_container *cont = root_container.children->items[i]; | 8 | struct sway_output *output = root->outputs->items[i]; |
9 | if (cont->type == C_OUTPUT) { | 9 | output_damage_surface(output, lx - output->wlr_output->lx, |
10 | output_damage_surface(cont->sway_output, | 10 | ly - output->wlr_output->ly, surface, whole); |
11 | lx - cont->current.swayc_x, ly - cont->current.swayc_y, | ||
12 | surface, whole); | ||
13 | } | ||
14 | } | 11 | } |
15 | } | 12 | } |
16 | 13 | ||
17 | void desktop_damage_whole_container(struct sway_container *con) { | 14 | void desktop_damage_whole_container(struct sway_container *con) { |
18 | for (int i = 0; i < root_container.children->length; ++i) { | 15 | for (int i = 0; i < root->outputs->length; ++i) { |
19 | struct sway_container *cont = root_container.children->items[i]; | 16 | struct sway_output *output = root->outputs->items[i]; |
20 | if (cont->type == C_OUTPUT) { | 17 | output_damage_whole_container(output, con); |
21 | output_damage_whole_container(cont->sway_output, con); | ||
22 | } | ||
23 | } | 18 | } |
24 | } | 19 | } |
25 | 20 | ||
26 | void desktop_damage_box(struct wlr_box *box) { | 21 | void desktop_damage_box(struct wlr_box *box) { |
27 | for (int i = 0; i < root_container.children->length; ++i) { | 22 | for (int i = 0; i < root->outputs->length; ++i) { |
28 | struct sway_container *cont = root_container.children->items[i]; | 23 | struct sway_output *output = root->outputs->items[i]; |
29 | output_damage_box(cont->sway_output, box); | 24 | output_damage_box(output, box); |
30 | } | 25 | } |
31 | } | 26 | } |
32 | 27 | ||
33 | void desktop_damage_view(struct sway_view *view) { | 28 | void desktop_damage_view(struct sway_view *view) { |
34 | desktop_damage_whole_container(view->swayc); | 29 | desktop_damage_whole_container(view->container); |
35 | struct wlr_box box = { | 30 | struct wlr_box box = { |
36 | .x = view->swayc->current.view_x - view->geometry.x, | 31 | .x = view->container->current.view_x - view->geometry.x, |
37 | .y = view->swayc->current.view_y - view->geometry.y, | 32 | .y = view->container->current.view_y - view->geometry.y, |
38 | .width = view->surface->current.width, | 33 | .width = view->surface->current.width, |
39 | .height = view->surface->current.height, | 34 | .height = view->surface->current.height, |
40 | }; | 35 | }; |
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index a4f7f928..7d254173 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include "sway/output.h" | 14 | #include "sway/output.h" |
15 | #include "sway/server.h" | 15 | #include "sway/server.h" |
16 | #include "sway/tree/arrange.h" | 16 | #include "sway/tree/arrange.h" |
17 | #include "sway/tree/workspace.h" | ||
17 | #include "log.h" | 18 | #include "log.h" |
18 | 19 | ||
19 | static void apply_exclusive(struct wlr_box *usable_area, | 20 | static void apply_exclusive(struct wlr_box *usable_area, |
@@ -176,7 +177,7 @@ void arrange_layers(struct sway_output *output) { | |||
176 | sizeof(struct wlr_box)) != 0) { | 177 | sizeof(struct wlr_box)) != 0) { |
177 | wlr_log(WLR_DEBUG, "Usable area changed, rearranging output"); | 178 | wlr_log(WLR_DEBUG, "Usable area changed, rearranging output"); |
178 | memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); | 179 | memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); |
179 | arrange_output(output->swayc); | 180 | arrange_output(output); |
180 | } | 181 | } |
181 | 182 | ||
182 | // Arrange non-exlusive surfaces from top->bottom | 183 | // Arrange non-exlusive surfaces from top->bottom |
@@ -256,7 +257,7 @@ static void unmap(struct sway_layer_surface *sway_layer) { | |||
256 | return; | 257 | return; |
257 | } | 258 | } |
258 | struct sway_output *output = wlr_output->data; | 259 | struct sway_output *output = wlr_output->data; |
259 | if (output == NULL || output->swayc == NULL) { | 260 | if (output == NULL) { |
260 | return; | 261 | return; |
261 | } | 262 | } |
262 | output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, | 263 | output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y, |
@@ -283,9 +284,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
283 | wl_list_remove(&sway_layer->surface_commit.link); | 284 | wl_list_remove(&sway_layer->surface_commit.link); |
284 | if (sway_layer->layer_surface->output != NULL) { | 285 | if (sway_layer->layer_surface->output != NULL) { |
285 | struct sway_output *output = sway_layer->layer_surface->output->data; | 286 | struct sway_output *output = sway_layer->layer_surface->output->data; |
286 | if (output != NULL && output->swayc != NULL) { | 287 | if (output != NULL) { |
287 | arrange_layers(output); | 288 | arrange_layers(output); |
288 | arrange_windows(output->swayc); | 289 | arrange_output(output); |
289 | transaction_commit_dirty(); | 290 | transaction_commit_dirty(); |
290 | } | 291 | } |
291 | wl_list_remove(&sway_layer->output_destroy.link); | 292 | wl_list_remove(&sway_layer->output_destroy.link); |
@@ -332,23 +333,21 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
332 | 333 | ||
333 | if (!layer_surface->output) { | 334 | if (!layer_surface->output) { |
334 | // Assign last active output | 335 | // Assign last active output |
335 | struct sway_container *output = NULL; | 336 | struct sway_output *output = NULL; |
336 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | 337 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
337 | if (seat) { | 338 | if (seat) { |
338 | output = seat_get_focus_inactive(seat, &root_container); | 339 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
340 | output = ws->output; | ||
339 | } | 341 | } |
340 | if (!output) { | 342 | if (!output) { |
341 | if (!sway_assert(root_container.children->length, | 343 | if (!sway_assert(root->outputs->length, |
342 | "cannot auto-assign output for layer")) { | 344 | "cannot auto-assign output for layer")) { |
343 | wlr_layer_surface_close(layer_surface); | 345 | wlr_layer_surface_close(layer_surface); |
344 | return; | 346 | return; |
345 | } | 347 | } |
346 | output = root_container.children->items[0]; | 348 | output = root->outputs->items[0]; |
347 | } | 349 | } |
348 | if (output->type != C_OUTPUT) { | 350 | layer_surface->output = output->wlr_output; |
349 | output = container_parent(output, C_OUTPUT); | ||
350 | } | ||
351 | layer_surface->output = output->sway_output->wlr_output; | ||
352 | } | 351 | } |
353 | 352 | ||
354 | struct sway_layer_surface *sway_layer = | 353 | struct sway_layer_surface *sway_layer = |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index c30e52a1..c182bad6 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -28,10 +28,10 @@ | |||
28 | #include "sway/tree/view.h" | 28 | #include "sway/tree/view.h" |
29 | #include "sway/tree/workspace.h" | 29 | #include "sway/tree/workspace.h" |
30 | 30 | ||
31 | struct sway_container *output_by_name(const char *name) { | 31 | struct sway_output *output_by_name(const char *name) { |
32 | for (int i = 0; i < root_container.children->length; ++i) { | 32 | for (int i = 0; i < root->outputs->length; ++i) { |
33 | struct sway_container *output = root_container.children->items[i]; | 33 | struct sway_output *output = root->outputs->items[i]; |
34 | if (strcasecmp(output->name, name) == 0) { | 34 | if (strcasecmp(output->wlr_output->name, name) == 0) { |
35 | return output; | 35 | return output; |
36 | } | 36 | } |
37 | } | 37 | } |
@@ -98,8 +98,8 @@ static bool get_surface_box(struct surface_iterator_data *data, | |||
98 | wlr_box_rotated_bounds(&box, data->rotation, &rotated_box); | 98 | wlr_box_rotated_bounds(&box, data->rotation, &rotated_box); |
99 | 99 | ||
100 | struct wlr_box output_box = { | 100 | struct wlr_box output_box = { |
101 | .width = output->swayc->current.swayc_width, | 101 | .width = output->wlr_output->width, |
102 | .height = output->swayc->current.swayc_height, | 102 | .height = output->wlr_output->height, |
103 | }; | 103 | }; |
104 | 104 | ||
105 | struct wlr_box intersection; | 105 | struct wlr_box intersection; |
@@ -145,12 +145,12 @@ void output_view_for_each_surface(struct sway_output *output, | |||
145 | .user_iterator = iterator, | 145 | .user_iterator = iterator, |
146 | .user_data = user_data, | 146 | .user_data = user_data, |
147 | .output = output, | 147 | .output = output, |
148 | .ox = view->swayc->current.view_x - output->swayc->current.swayc_x | 148 | .ox = view->container->current.view_x - output->wlr_output->lx |
149 | - view->geometry.x, | 149 | - view->geometry.x, |
150 | .oy = view->swayc->current.view_y - output->swayc->current.swayc_y | 150 | .oy = view->container->current.view_y - output->wlr_output->ly |
151 | - view->geometry.y, | 151 | - view->geometry.y, |
152 | .width = view->swayc->current.view_width, | 152 | .width = view->container->current.view_width, |
153 | .height = view->swayc->current.view_height, | 153 | .height = view->container->current.view_height, |
154 | .rotation = 0, // TODO | 154 | .rotation = 0, // TODO |
155 | }; | 155 | }; |
156 | 156 | ||
@@ -164,12 +164,12 @@ void output_view_for_each_popup(struct sway_output *output, | |||
164 | .user_iterator = iterator, | 164 | .user_iterator = iterator, |
165 | .user_data = user_data, | 165 | .user_data = user_data, |
166 | .output = output, | 166 | .output = output, |
167 | .ox = view->swayc->current.view_x - output->swayc->current.swayc_x | 167 | .ox = view->container->current.view_x - output->wlr_output->lx |
168 | - view->geometry.x, | 168 | - view->geometry.x, |
169 | .oy = view->swayc->current.view_y - output->swayc->current.swayc_y | 169 | .oy = view->container->current.view_y - output->wlr_output->ly |
170 | - view->geometry.y, | 170 | - view->geometry.y, |
171 | .width = view->swayc->current.view_width, | 171 | .width = view->container->current.view_width, |
172 | .height = view->swayc->current.view_height, | 172 | .height = view->container->current.view_height, |
173 | .rotation = 0, // TODO | 173 | .rotation = 0, // TODO |
174 | }; | 174 | }; |
175 | 175 | ||
@@ -197,8 +197,8 @@ void output_unmanaged_for_each_surface(struct sway_output *output, | |||
197 | wl_list_for_each(unmanaged_surface, unmanaged, link) { | 197 | wl_list_for_each(unmanaged_surface, unmanaged, link) { |
198 | struct wlr_xwayland_surface *xsurface = | 198 | struct wlr_xwayland_surface *xsurface = |
199 | unmanaged_surface->wlr_xwayland_surface; | 199 | unmanaged_surface->wlr_xwayland_surface; |
200 | double ox = unmanaged_surface->lx - output->swayc->current.swayc_x; | 200 | double ox = unmanaged_surface->lx - output->wlr_output->lx; |
201 | double oy = unmanaged_surface->ly - output->swayc->current.swayc_y; | 201 | double oy = unmanaged_surface->ly - output->wlr_output->ly; |
202 | 202 | ||
203 | output_surface_for_each_surface(output, xsurface->surface, ox, oy, | 203 | output_surface_for_each_surface(output, xsurface->surface, ox, oy, |
204 | iterator, user_data); | 204 | iterator, user_data); |
@@ -211,8 +211,8 @@ void output_drag_icons_for_each_surface(struct sway_output *output, | |||
211 | void *user_data) { | 211 | void *user_data) { |
212 | struct sway_drag_icon *drag_icon; | 212 | struct sway_drag_icon *drag_icon; |
213 | wl_list_for_each(drag_icon, drag_icons, link) { | 213 | wl_list_for_each(drag_icon, drag_icons, link) { |
214 | double ox = drag_icon->x - output->swayc->x; | 214 | double ox = drag_icon->x - output->wlr_output->lx; |
215 | double oy = drag_icon->y - output->swayc->y; | 215 | double oy = drag_icon->y - output->wlr_output->ly; |
216 | 216 | ||
217 | if (drag_icon->wlr_drag_icon->mapped) { | 217 | if (drag_icon->wlr_drag_icon->mapped) { |
218 | output_surface_for_each_surface(output, | 218 | output_surface_for_each_surface(output, |
@@ -229,19 +229,13 @@ static void scale_box(struct wlr_box *box, float scale) { | |||
229 | box->height *= scale; | 229 | box->height *= scale; |
230 | } | 230 | } |
231 | 231 | ||
232 | struct sway_container *output_get_active_workspace(struct sway_output *output) { | 232 | struct sway_workspace *output_get_active_workspace(struct sway_output *output) { |
233 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 233 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
234 | struct sway_container *focus = | 234 | struct sway_node *focus = seat_get_active_child(seat, &output->node); |
235 | seat_get_focus_inactive(seat, output->swayc); | ||
236 | if (!focus) { | 235 | if (!focus) { |
237 | // We've never been to this output before | 236 | return output->workspaces->items[0]; |
238 | focus = output->swayc->current.children->items[0]; | ||
239 | } | 237 | } |
240 | struct sway_container *workspace = focus; | 238 | return focus->sway_workspace; |
241 | if (workspace->type != C_WORKSPACE) { | ||
242 | workspace = container_parent(workspace, C_WORKSPACE); | ||
243 | } | ||
244 | return workspace; | ||
245 | } | 239 | } |
246 | 240 | ||
247 | bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { | 241 | bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { |
@@ -255,8 +249,8 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output) { | |||
255 | struct sway_layer_surface *sway_layer_surface = | 249 | struct sway_layer_surface *sway_layer_surface = |
256 | layer_from_wlr_layer_surface(wlr_layer_surface); | 250 | layer_from_wlr_layer_surface(wlr_layer_surface); |
257 | pixman_box32_t output_box = { | 251 | pixman_box32_t output_box = { |
258 | .x2 = output->swayc->current.swayc_width, | 252 | .x2 = output->wlr_output->width, |
259 | .y2 = output->swayc->current.swayc_height, | 253 | .y2 = output->wlr_output->height, |
260 | }; | 254 | }; |
261 | pixman_region32_t surface_opaque_box; | 255 | pixman_region32_t surface_opaque_box; |
262 | pixman_region32_init(&surface_opaque_box); | 256 | pixman_region32_init(&surface_opaque_box); |
@@ -307,15 +301,15 @@ struct send_frame_done_data { | |||
307 | 301 | ||
308 | static void send_frame_done_container_iterator(struct sway_container *con, | 302 | static void send_frame_done_container_iterator(struct sway_container *con, |
309 | void *_data) { | 303 | void *_data) { |
310 | if (con->type != C_VIEW) { | 304 | if (!con->view) { |
311 | return; | 305 | return; |
312 | } | 306 | } |
313 | if (!view_is_visible(con->sway_view)) { | 307 | if (!view_is_visible(con->view)) { |
314 | return; | 308 | return; |
315 | } | 309 | } |
316 | 310 | ||
317 | struct send_frame_done_data *data = _data; | 311 | struct send_frame_done_data *data = _data; |
318 | output_view_for_each_surface(data->output, con->sway_view, | 312 | output_view_for_each_surface(data->output, con->view, |
319 | send_frame_done_iterator, data->when); | 313 | send_frame_done_iterator, data->when); |
320 | } | 314 | } |
321 | 315 | ||
@@ -328,15 +322,14 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
328 | .output = output, | 322 | .output = output, |
329 | .when = when, | 323 | .when = when, |
330 | }; | 324 | }; |
331 | struct sway_container *workspace = output_get_active_workspace(output); | 325 | struct sway_workspace *workspace = output_get_active_workspace(output); |
332 | if (workspace->current.ws_fullscreen) { | 326 | if (workspace->current.fullscreen) { |
333 | send_frame_done_container_iterator( | 327 | send_frame_done_container_iterator( |
334 | workspace->current.ws_fullscreen, &data); | 328 | workspace->current.fullscreen, &data); |
335 | container_for_each_child(workspace->current.ws_fullscreen, | 329 | container_for_each_child(workspace->current.fullscreen, |
336 | send_frame_done_container_iterator, &data); | 330 | send_frame_done_container_iterator, &data); |
337 | #ifdef HAVE_XWAYLAND | 331 | #ifdef HAVE_XWAYLAND |
338 | send_frame_done_unmanaged(output, | 332 | send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when); |
339 | &root_container.sway_root->xwayland_unmanaged, when); | ||
340 | #endif | 333 | #endif |
341 | } else { | 334 | } else { |
342 | send_frame_done_layer(output, | 335 | send_frame_done_layer(output, |
@@ -348,8 +341,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
348 | send_frame_done_container_iterator, &data); | 341 | send_frame_done_container_iterator, &data); |
349 | 342 | ||
350 | #ifdef HAVE_XWAYLAND | 343 | #ifdef HAVE_XWAYLAND |
351 | send_frame_done_unmanaged(output, | 344 | send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when); |
352 | &root_container.sway_root->xwayland_unmanaged, when); | ||
353 | #endif | 345 | #endif |
354 | send_frame_done_layer(output, | 346 | send_frame_done_layer(output, |
355 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], when); | 347 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], when); |
@@ -358,8 +350,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
358 | send_frame_overlay: | 350 | send_frame_overlay: |
359 | send_frame_done_layer(output, | 351 | send_frame_done_layer(output, |
360 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], when); | 352 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], when); |
361 | send_frame_done_drag_icons(output, &root_container.sway_root->drag_icons, | 353 | send_frame_done_drag_icons(output, &root->drag_icons, when); |
362 | when); | ||
363 | } | 354 | } |
364 | 355 | ||
365 | static void damage_handle_frame(struct wl_listener *listener, void *data) { | 356 | static void damage_handle_frame(struct wl_listener *listener, void *data) { |
@@ -391,7 +382,11 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) { | |||
391 | } | 382 | } |
392 | 383 | ||
393 | void output_damage_whole(struct sway_output *output) { | 384 | void output_damage_whole(struct sway_output *output) { |
394 | wlr_output_damage_add_whole(output->damage); | 385 | // The output can exist with no wlr_output if it's just been disconnected |
386 | // and the transaction to evacuate it has't completed yet. | ||
387 | if (output && output->wlr_output) { | ||
388 | wlr_output_damage_add_whole(output->damage); | ||
389 | } | ||
395 | } | 390 | } |
396 | 391 | ||
397 | static void damage_surface_iterator(struct sway_output *output, | 392 | static void damage_surface_iterator(struct sway_output *output, |
@@ -446,14 +441,9 @@ void output_damage_surface(struct sway_output *output, double ox, double oy, | |||
446 | 441 | ||
447 | static void output_damage_view(struct sway_output *output, | 442 | static void output_damage_view(struct sway_output *output, |
448 | struct sway_view *view, bool whole) { | 443 | struct sway_view *view, bool whole) { |
449 | if (!sway_assert(view->swayc != NULL, "expected a view in the tree")) { | ||
450 | return; | ||
451 | } | ||
452 | |||
453 | if (!view_is_visible(view)) { | 444 | if (!view_is_visible(view)) { |
454 | return; | 445 | return; |
455 | } | 446 | } |
456 | |||
457 | output_view_for_each_surface(output, view, damage_surface_iterator, &whole); | 447 | output_view_for_each_surface(output, view, damage_surface_iterator, &whole); |
458 | } | 448 | } |
459 | 449 | ||
@@ -466,31 +456,29 @@ void output_damage_from_view(struct sway_output *output, | |||
466 | void output_damage_box(struct sway_output *output, struct wlr_box *_box) { | 456 | void output_damage_box(struct sway_output *output, struct wlr_box *_box) { |
467 | struct wlr_box box; | 457 | struct wlr_box box; |
468 | memcpy(&box, _box, sizeof(struct wlr_box)); | 458 | memcpy(&box, _box, sizeof(struct wlr_box)); |
469 | box.x -= output->swayc->current.swayc_x; | 459 | box.x -= output->wlr_output->lx; |
470 | box.y -= output->swayc->current.swayc_y; | 460 | box.y -= output->wlr_output->ly; |
471 | scale_box(&box, output->wlr_output->scale); | 461 | scale_box(&box, output->wlr_output->scale); |
472 | wlr_output_damage_add_box(output->damage, &box); | 462 | wlr_output_damage_add_box(output->damage, &box); |
473 | } | 463 | } |
474 | 464 | ||
475 | static void output_damage_whole_container_iterator(struct sway_container *con, | 465 | static void output_damage_whole_container_iterator(struct sway_container *con, |
476 | void *data) { | 466 | void *data) { |
477 | struct sway_output *output = data; | 467 | if (!sway_assert(con->view, "expected a view")) { |
478 | |||
479 | if (!sway_assert(con->type == C_VIEW, "expected a view")) { | ||
480 | return; | 468 | return; |
481 | } | 469 | } |
482 | 470 | struct sway_output *output = data; | |
483 | output_damage_view(output, con->sway_view, true); | 471 | output_damage_view(output, con->view, true); |
484 | } | 472 | } |
485 | 473 | ||
486 | void output_damage_whole_container(struct sway_output *output, | 474 | void output_damage_whole_container(struct sway_output *output, |
487 | struct sway_container *con) { | 475 | struct sway_container *con) { |
488 | // Pad the box by 1px, because the width is a double and might be a fraction | 476 | // Pad the box by 1px, because the width is a double and might be a fraction |
489 | struct wlr_box box = { | 477 | struct wlr_box box = { |
490 | .x = con->current.swayc_x - output->wlr_output->lx - 1, | 478 | .x = con->current.con_x - output->wlr_output->lx - 1, |
491 | .y = con->current.swayc_y - output->wlr_output->ly - 1, | 479 | .y = con->current.con_y - output->wlr_output->ly - 1, |
492 | .width = con->current.swayc_width + 2, | 480 | .width = con->current.con_width + 2, |
493 | .height = con->current.swayc_height + 2, | 481 | .height = con->current.con_height + 2, |
494 | }; | 482 | }; |
495 | scale_box(&box, output->wlr_output->scale); | 483 | scale_box(&box, output->wlr_output->scale); |
496 | wlr_output_damage_add_box(output->damage, &box); | 484 | wlr_output_damage_add_box(output->damage, &box); |
@@ -499,44 +487,48 @@ void output_damage_whole_container(struct sway_output *output, | |||
499 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { | 487 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { |
500 | struct sway_output *output = | 488 | struct sway_output *output = |
501 | wl_container_of(listener, output, damage_destroy); | 489 | wl_container_of(listener, output, damage_destroy); |
502 | output_begin_destroy(output->swayc); | 490 | output_disable(output); |
491 | transaction_commit_dirty(); | ||
503 | } | 492 | } |
504 | 493 | ||
505 | static void handle_destroy(struct wl_listener *listener, void *data) { | 494 | static void handle_destroy(struct wl_listener *listener, void *data) { |
506 | struct sway_output *output = wl_container_of(listener, output, destroy); | 495 | struct sway_output *output = wl_container_of(listener, output, destroy); |
507 | wl_signal_emit(&output->events.destroy, output); | 496 | wl_signal_emit(&output->events.destroy, output); |
508 | 497 | ||
509 | if (output->swayc) { | 498 | if (output->enabled) { |
510 | output_begin_destroy(output->swayc); | 499 | output_disable(output); |
511 | } | 500 | } |
501 | output_begin_destroy(output); | ||
512 | 502 | ||
513 | wl_list_remove(&output->link); | 503 | transaction_commit_dirty(); |
514 | wl_list_remove(&output->destroy.link); | ||
515 | output->wlr_output->data = NULL; | ||
516 | free(output); | ||
517 | |||
518 | arrange_windows(&root_container); | ||
519 | } | 504 | } |
520 | 505 | ||
521 | static void handle_mode(struct wl_listener *listener, void *data) { | 506 | static void handle_mode(struct wl_listener *listener, void *data) { |
522 | struct sway_output *output = wl_container_of(listener, output, mode); | 507 | struct sway_output *output = wl_container_of(listener, output, mode); |
523 | arrange_layers(output); | 508 | arrange_layers(output); |
524 | arrange_windows(output->swayc); | 509 | arrange_output(output); |
525 | transaction_commit_dirty(); | 510 | transaction_commit_dirty(); |
526 | } | 511 | } |
527 | 512 | ||
528 | static void handle_transform(struct wl_listener *listener, void *data) { | 513 | static void handle_transform(struct wl_listener *listener, void *data) { |
529 | struct sway_output *output = wl_container_of(listener, output, transform); | 514 | struct sway_output *output = wl_container_of(listener, output, transform); |
530 | arrange_layers(output); | 515 | arrange_layers(output); |
531 | arrange_windows(output->swayc); | 516 | arrange_output(output); |
532 | transaction_commit_dirty(); | 517 | transaction_commit_dirty(); |
533 | } | 518 | } |
534 | 519 | ||
520 | static void update_textures(struct sway_container *con, void *data) { | ||
521 | container_update_title_textures(con); | ||
522 | if (con->view) { | ||
523 | view_update_marks_textures(con->view); | ||
524 | } | ||
525 | } | ||
526 | |||
535 | static void handle_scale(struct wl_listener *listener, void *data) { | 527 | static void handle_scale(struct wl_listener *listener, void *data) { |
536 | struct sway_output *output = wl_container_of(listener, output, scale); | 528 | struct sway_output *output = wl_container_of(listener, output, scale); |
537 | arrange_layers(output); | 529 | arrange_layers(output); |
538 | container_update_textures_recursive(output->swayc); | 530 | output_for_each_container(output, update_textures, NULL); |
539 | arrange_windows(output->swayc); | 531 | arrange_output(output); |
540 | transaction_commit_dirty(); | 532 | transaction_commit_dirty(); |
541 | } | 533 | } |
542 | 534 | ||
@@ -545,57 +537,27 @@ void handle_new_output(struct wl_listener *listener, void *data) { | |||
545 | struct wlr_output *wlr_output = data; | 537 | struct wlr_output *wlr_output = data; |
546 | wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); | 538 | wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); |
547 | 539 | ||
548 | struct sway_output *output = calloc(1, sizeof(struct sway_output)); | 540 | struct sway_output *output = output_create(wlr_output); |
549 | if (!output) { | 541 | if (!output) { |
550 | return; | 542 | return; |
551 | } | 543 | } |
552 | output->wlr_output = wlr_output; | ||
553 | wlr_output->data = output; | ||
554 | output->server = server; | 544 | output->server = server; |
555 | output->damage = wlr_output_damage_create(wlr_output); | 545 | output->damage = wlr_output_damage_create(wlr_output); |
556 | |||
557 | wl_signal_add(&wlr_output->events.destroy, &output->destroy); | ||
558 | output->destroy.notify = handle_destroy; | 546 | output->destroy.notify = handle_destroy; |
559 | 547 | ||
560 | wl_list_insert(&root_container.sway_root->all_outputs, &output->link); | 548 | struct output_config *oc = output_find_config(output); |
561 | |||
562 | output_enable(output); | ||
563 | } | ||
564 | |||
565 | void output_enable(struct sway_output *output) { | ||
566 | struct wlr_output *wlr_output = output->wlr_output; | ||
567 | |||
568 | if (!sway_assert(output->swayc == NULL, "output is already enabled")) { | ||
569 | return; | ||
570 | } | ||
571 | |||
572 | output->swayc = output_create(output); | ||
573 | if (!output->swayc) { | ||
574 | // Output is disabled | ||
575 | return; | ||
576 | } | ||
577 | 549 | ||
578 | size_t len = sizeof(output->layers) / sizeof(output->layers[0]); | 550 | if (oc && oc->enabled) { |
579 | for (size_t i = 0; i < len; ++i) { | 551 | output_enable(output, oc); |
580 | wl_list_init(&output->layers[i]); | ||
581 | } | 552 | } |
582 | wl_signal_init(&output->events.destroy); | ||
583 | 553 | ||
584 | input_manager_configure_xcursor(input_manager); | 554 | transaction_commit_dirty(); |
555 | } | ||
585 | 556 | ||
586 | wl_signal_add(&wlr_output->events.mode, &output->mode); | 557 | void output_add_listeners(struct sway_output *output) { |
587 | output->mode.notify = handle_mode; | 558 | output->mode.notify = handle_mode; |
588 | wl_signal_add(&wlr_output->events.transform, &output->transform); | ||
589 | output->transform.notify = handle_transform; | 559 | output->transform.notify = handle_transform; |
590 | wl_signal_add(&wlr_output->events.scale, &output->scale); | ||
591 | output->scale.notify = handle_scale; | 560 | output->scale.notify = handle_scale; |
592 | |||
593 | wl_signal_add(&output->damage->events.frame, &output->damage_frame); | ||
594 | output->damage_frame.notify = damage_handle_frame; | 561 | output->damage_frame.notify = damage_handle_frame; |
595 | wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); | ||
596 | output->damage_destroy.notify = damage_handle_destroy; | 562 | output->damage_destroy.notify = damage_handle_destroy; |
597 | |||
598 | arrange_layers(output); | ||
599 | arrange_windows(&root_container); | ||
600 | transaction_commit_dirty(); | ||
601 | } | 563 | } |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 695213eb..99b2cf3d 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -193,10 +193,10 @@ static void render_view_toplevels(struct sway_view *view, | |||
193 | .alpha = alpha, | 193 | .alpha = alpha, |
194 | }; | 194 | }; |
195 | // Render all toplevels without descending into popups | 195 | // Render all toplevels without descending into popups |
196 | double ox = | 196 | double ox = view->container->current.view_x - |
197 | view->swayc->current.view_x - output->wlr_output->lx - view->geometry.x; | 197 | output->wlr_output->lx - view->geometry.x; |
198 | double oy = | 198 | double oy = view->container->current.view_y - |
199 | view->swayc->current.view_y - output->wlr_output->ly - view->geometry.y; | 199 | output->wlr_output->ly - view->geometry.y; |
200 | output_surface_for_each_surface(output, view->surface, ox, oy, | 200 | output_surface_for_each_surface(output, view->surface, ox, oy, |
201 | render_surface_iterator, &data); | 201 | render_surface_iterator, &data); |
202 | } | 202 | } |
@@ -229,17 +229,17 @@ static void render_saved_view(struct sway_view *view, | |||
229 | return; | 229 | return; |
230 | } | 230 | } |
231 | struct wlr_box box = { | 231 | struct wlr_box box = { |
232 | .x = view->swayc->current.view_x - output->swayc->current.swayc_x - | 232 | .x = view->container->current.view_x - output->wlr_output->lx - |
233 | view->saved_geometry.x, | 233 | view->saved_geometry.x, |
234 | .y = view->swayc->current.view_y - output->swayc->current.swayc_y - | 234 | .y = view->container->current.view_y - output->wlr_output->ly - |
235 | view->saved_geometry.y, | 235 | view->saved_geometry.y, |
236 | .width = view->saved_buffer_width, | 236 | .width = view->saved_buffer_width, |
237 | .height = view->saved_buffer_height, | 237 | .height = view->saved_buffer_height, |
238 | }; | 238 | }; |
239 | 239 | ||
240 | struct wlr_box output_box = { | 240 | struct wlr_box output_box = { |
241 | .width = output->swayc->current.swayc_width, | 241 | .width = output->wlr_output->width, |
242 | .height = output->swayc->current.swayc_height, | 242 | .height = output->wlr_output->height, |
243 | }; | 243 | }; |
244 | 244 | ||
245 | struct wlr_box intersection; | 245 | struct wlr_box intersection; |
@@ -263,14 +263,14 @@ static void render_saved_view(struct sway_view *view, | |||
263 | */ | 263 | */ |
264 | static void render_view(struct sway_output *output, pixman_region32_t *damage, | 264 | static void render_view(struct sway_output *output, pixman_region32_t *damage, |
265 | struct sway_container *con, struct border_colors *colors) { | 265 | struct sway_container *con, struct border_colors *colors) { |
266 | struct sway_view *view = con->sway_view; | 266 | struct sway_view *view = con->view; |
267 | if (view->saved_buffer) { | 267 | if (view->saved_buffer) { |
268 | render_saved_view(view, output, damage, view->swayc->alpha); | 268 | render_saved_view(view, output, damage, view->container->alpha); |
269 | } else { | 269 | } else { |
270 | render_view_toplevels(view, output, damage, view->swayc->alpha); | 270 | render_view_toplevels(view, output, damage, view->container->alpha); |
271 | } | 271 | } |
272 | 272 | ||
273 | if (view->swayc->current.using_csd) { | 273 | if (view->container->current.using_csd) { |
274 | return; | 274 | return; |
275 | } | 275 | } |
276 | 276 | ||
@@ -283,7 +283,7 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
283 | if (state->border_left) { | 283 | if (state->border_left) { |
284 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 284 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
285 | premultiply_alpha(color, con->alpha); | 285 | premultiply_alpha(color, con->alpha); |
286 | box.x = state->swayc_x; | 286 | box.x = state->con_x; |
287 | box.y = state->view_y; | 287 | box.y = state->view_y; |
288 | box.width = state->border_thickness; | 288 | box.width = state->border_thickness; |
289 | box.height = state->view_height; | 289 | box.height = state->view_height; |
@@ -291,9 +291,12 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
291 | render_rect(output->wlr_output, damage, &box, color); | 291 | render_rect(output->wlr_output, damage, &box, color); |
292 | } | 292 | } |
293 | 293 | ||
294 | list_t *siblings = container_get_current_siblings(con); | ||
295 | enum sway_container_layout layout = | ||
296 | container_current_parent_layout(con); | ||
297 | |||
294 | if (state->border_right) { | 298 | if (state->border_right) { |
295 | if (state->parent->current.children->length == 1 | 299 | if (siblings->length == 1 && layout == L_HORIZ) { |
296 | && state->parent->current.layout == L_HORIZ) { | ||
297 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 300 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
298 | } else { | 301 | } else { |
299 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 302 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
@@ -308,16 +311,15 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
308 | } | 311 | } |
309 | 312 | ||
310 | if (state->border_bottom) { | 313 | if (state->border_bottom) { |
311 | if (state->parent->current.children->length == 1 | 314 | if (siblings->length == 1 && layout == L_VERT) { |
312 | && con->current.parent->current.layout == L_VERT) { | ||
313 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 315 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
314 | } else { | 316 | } else { |
315 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 317 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
316 | } | 318 | } |
317 | premultiply_alpha(color, con->alpha); | 319 | premultiply_alpha(color, con->alpha); |
318 | box.x = state->swayc_x; | 320 | box.x = state->con_x; |
319 | box.y = state->view_y + state->view_height; | 321 | box.y = state->view_y + state->view_height; |
320 | box.width = state->swayc_width; | 322 | box.width = state->con_width; |
321 | box.height = state->border_thickness; | 323 | box.height = state->border_thickness; |
322 | scale_box(&box, output_scale); | 324 | scale_box(&box, output_scale); |
323 | render_rect(output->wlr_output, damage, &box, color); | 325 | render_rect(output->wlr_output, damage, &box, color); |
@@ -344,12 +346,12 @@ static void render_titlebar(struct sway_output *output, | |||
344 | float color[4]; | 346 | float color[4]; |
345 | struct sway_container_state *state = &con->current; | 347 | struct sway_container_state *state = &con->current; |
346 | float output_scale = output->wlr_output->scale; | 348 | float output_scale = output->wlr_output->scale; |
347 | enum sway_container_layout layout = state->parent->current.layout; | 349 | enum sway_container_layout layout = container_current_parent_layout(con); |
348 | list_t *children = state->parent->current.children; | 350 | list_t *children = container_get_current_siblings(con); |
349 | bool is_last_child = children->length == 0 || | 351 | bool is_last_child = children->length == 0 || |
350 | children->items[children->length - 1] == con; | 352 | children->items[children->length - 1] == con; |
351 | double output_x = output->swayc->current.swayc_x; | 353 | double output_x = output->wlr_output->lx; |
352 | double output_y = output->swayc->current.swayc_y; | 354 | double output_y = output->wlr_output->ly; |
353 | 355 | ||
354 | // Single pixel bar above title | 356 | // Single pixel bar above title |
355 | memcpy(&color, colors->border, sizeof(float) * 4); | 357 | memcpy(&color, colors->border, sizeof(float) * 4); |
@@ -366,7 +368,7 @@ static void render_titlebar(struct sway_output *output, | |||
366 | bool connects_sides = false; | 368 | bool connects_sides = false; |
367 | if (layout == L_HORIZ || layout == L_VERT || | 369 | if (layout == L_HORIZ || layout == L_VERT || |
368 | (layout == L_STACKED && is_last_child)) { | 370 | (layout == L_STACKED && is_last_child)) { |
369 | if (con->type == C_VIEW) { | 371 | if (con->view) { |
370 | left_offset = state->border_left * state->border_thickness; | 372 | left_offset = state->border_left * state->border_thickness; |
371 | right_offset = state->border_right * state->border_thickness; | 373 | right_offset = state->border_right * state->border_thickness; |
372 | connects_sides = true; | 374 | connects_sides = true; |
@@ -542,14 +544,22 @@ static void render_top_border(struct sway_output *output, | |||
542 | // Child border - top edge | 544 | // Child border - top edge |
543 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 545 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
544 | premultiply_alpha(color, con->alpha); | 546 | premultiply_alpha(color, con->alpha); |
545 | box.x = state->swayc_x; | 547 | box.x = state->con_x; |
546 | box.y = state->swayc_y; | 548 | box.y = state->con_y; |
547 | box.width = state->swayc_width; | 549 | box.width = state->con_width; |
548 | box.height = state->border_thickness; | 550 | box.height = state->border_thickness; |
549 | scale_box(&box, output_scale); | 551 | scale_box(&box, output_scale); |
550 | render_rect(output->wlr_output, output_damage, &box, color); | 552 | render_rect(output->wlr_output, output_damage, &box, color); |
551 | } | 553 | } |
552 | 554 | ||
555 | struct parent_data { | ||
556 | enum sway_container_layout layout; | ||
557 | struct wlr_box box; | ||
558 | list_t *children; | ||
559 | bool focused; | ||
560 | struct sway_container *active_child; | ||
561 | }; | ||
562 | |||
553 | static void render_container(struct sway_output *output, | 563 | static void render_container(struct sway_output *output, |
554 | pixman_region32_t *damage, struct sway_container *con, bool parent_focused); | 564 | pixman_region32_t *damage, struct sway_container *con, bool parent_focused); |
555 | 565 | ||
@@ -559,14 +569,13 @@ static void render_container(struct sway_output *output, | |||
559 | * Wrap child views in borders and leave child containers borderless because | 569 | * Wrap child views in borders and leave child containers borderless because |
560 | * they'll apply their own borders to their children. | 570 | * they'll apply their own borders to their children. |
561 | */ | 571 | */ |
562 | static void render_container_simple(struct sway_output *output, | 572 | static void render_containers_linear(struct sway_output *output, |
563 | pixman_region32_t *damage, struct sway_container *con, | 573 | pixman_region32_t *damage, struct parent_data *parent) { |
564 | bool parent_focused) { | 574 | for (int i = 0; i < parent->children->length; ++i) { |
565 | for (int i = 0; i < con->current.children->length; ++i) { | 575 | struct sway_container *child = parent->children->items[i]; |
566 | struct sway_container *child = con->current.children->items[i]; | 576 | |
567 | 577 | if (child->view) { | |
568 | if (child->type == C_VIEW) { | 578 | struct sway_view *view = child->view; |
569 | struct sway_view *view = child->sway_view; | ||
570 | struct border_colors *colors; | 579 | struct border_colors *colors; |
571 | struct wlr_texture *title_texture; | 580 | struct wlr_texture *title_texture; |
572 | struct wlr_texture *marks_texture; | 581 | struct wlr_texture *marks_texture; |
@@ -576,11 +585,11 @@ static void render_container_simple(struct sway_output *output, | |||
576 | colors = &config->border_colors.urgent; | 585 | colors = &config->border_colors.urgent; |
577 | title_texture = child->title_urgent; | 586 | title_texture = child->title_urgent; |
578 | marks_texture = view->marks_urgent; | 587 | marks_texture = view->marks_urgent; |
579 | } else if (state->focused || parent_focused) { | 588 | } else if (state->focused || parent->focused) { |
580 | colors = &config->border_colors.focused; | 589 | colors = &config->border_colors.focused; |
581 | title_texture = child->title_focused; | 590 | title_texture = child->title_focused; |
582 | marks_texture = view->marks_focused; | 591 | marks_texture = view->marks_focused; |
583 | } else if (con->current.focused_inactive_child == child) { | 592 | } else if (child == parent->active_child) { |
584 | colors = &config->border_colors.focused_inactive; | 593 | colors = &config->border_colors.focused_inactive; |
585 | title_texture = child->title_focused_inactive; | 594 | title_texture = child->title_focused_inactive; |
586 | marks_texture = view->marks_focused_inactive; | 595 | marks_texture = view->marks_focused_inactive; |
@@ -590,10 +599,10 @@ static void render_container_simple(struct sway_output *output, | |||
590 | marks_texture = view->marks_unfocused; | 599 | marks_texture = view->marks_unfocused; |
591 | } | 600 | } |
592 | 601 | ||
593 | if (!view->swayc->current.using_csd) { | 602 | if (!view->container->current.using_csd) { |
594 | if (state->border == B_NORMAL) { | 603 | if (state->border == B_NORMAL) { |
595 | render_titlebar(output, damage, child, state->swayc_x, | 604 | render_titlebar(output, damage, child, state->con_x, |
596 | state->swayc_y, state->swayc_width, colors, | 605 | state->con_y, state->con_width, colors, |
597 | title_texture, marks_texture); | 606 | title_texture, marks_texture); |
598 | } else { | 607 | } else { |
599 | render_top_border(output, damage, child, colors); | 608 | render_top_border(output, damage, child, colors); |
@@ -602,7 +611,7 @@ static void render_container_simple(struct sway_output *output, | |||
602 | render_view(output, damage, child, colors); | 611 | render_view(output, damage, child, colors); |
603 | } else { | 612 | } else { |
604 | render_container(output, damage, child, | 613 | render_container(output, damage, child, |
605 | parent_focused || child->current.focused); | 614 | parent->focused || child->current.focused); |
606 | } | 615 | } |
607 | } | 616 | } |
608 | } | 617 | } |
@@ -610,22 +619,19 @@ static void render_container_simple(struct sway_output *output, | |||
610 | /** | 619 | /** |
611 | * Render a container's children using the L_TABBED layout. | 620 | * Render a container's children using the L_TABBED layout. |
612 | */ | 621 | */ |
613 | static void render_container_tabbed(struct sway_output *output, | 622 | static void render_containers_tabbed(struct sway_output *output, |
614 | pixman_region32_t *damage, struct sway_container *con, | 623 | pixman_region32_t *damage, struct parent_data *parent) { |
615 | bool parent_focused) { | 624 | if (!parent->children->length) { |
616 | if (!con->current.children->length) { | ||
617 | return; | 625 | return; |
618 | } | 626 | } |
619 | struct sway_container_state *pstate = &con->current; | 627 | struct sway_container *current = parent->active_child; |
620 | struct sway_container *current = pstate->focused_inactive_child; | ||
621 | struct border_colors *current_colors = &config->border_colors.unfocused; | 628 | struct border_colors *current_colors = &config->border_colors.unfocused; |
622 | 629 | int tab_width = parent->box.width / parent->children->length; | |
623 | int tab_width = (pstate->swayc_width) / pstate->children->length; | ||
624 | 630 | ||
625 | // Render tabs | 631 | // Render tabs |
626 | for (int i = 0; i < pstate->children->length; ++i) { | 632 | for (int i = 0; i < parent->children->length; ++i) { |
627 | struct sway_container *child = pstate->children->items[i]; | 633 | struct sway_container *child = parent->children->items[i]; |
628 | struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; | 634 | struct sway_view *view = child->view; |
629 | struct sway_container_state *cstate = &child->current; | 635 | struct sway_container_state *cstate = &child->current; |
630 | struct border_colors *colors; | 636 | struct border_colors *colors; |
631 | struct wlr_texture *title_texture; | 637 | struct wlr_texture *title_texture; |
@@ -637,11 +643,11 @@ static void render_container_tabbed(struct sway_output *output, | |||
637 | colors = &config->border_colors.urgent; | 643 | colors = &config->border_colors.urgent; |
638 | title_texture = child->title_urgent; | 644 | title_texture = child->title_urgent; |
639 | marks_texture = view ? view->marks_urgent : NULL; | 645 | marks_texture = view ? view->marks_urgent : NULL; |
640 | } else if (cstate->focused || parent_focused) { | 646 | } else if (cstate->focused || parent->focused) { |
641 | colors = &config->border_colors.focused; | 647 | colors = &config->border_colors.focused; |
642 | title_texture = child->title_focused; | 648 | title_texture = child->title_focused; |
643 | marks_texture = view ? view->marks_focused : NULL; | 649 | marks_texture = view ? view->marks_focused : NULL; |
644 | } else if (child == pstate->focused_inactive_child) { | 650 | } else if (child == parent->active_child) { |
645 | colors = &config->border_colors.focused_inactive; | 651 | colors = &config->border_colors.focused_inactive; |
646 | title_texture = child->title_focused_inactive; | 652 | title_texture = child->title_focused_inactive; |
647 | marks_texture = view ? view->marks_focused_inactive : NULL; | 653 | marks_texture = view ? view->marks_focused_inactive : NULL; |
@@ -651,14 +657,14 @@ static void render_container_tabbed(struct sway_output *output, | |||
651 | marks_texture = view ? view->marks_unfocused : NULL; | 657 | marks_texture = view ? view->marks_unfocused : NULL; |
652 | } | 658 | } |
653 | 659 | ||
654 | int x = cstate->swayc_x + tab_width * i; | 660 | int x = cstate->con_x + tab_width * i; |
655 | 661 | ||
656 | // Make last tab use the remaining width of the parent | 662 | // Make last tab use the remaining width of the parent |
657 | if (i == pstate->children->length - 1) { | 663 | if (i == parent->children->length - 1) { |
658 | tab_width = pstate->swayc_width - tab_width * i; | 664 | tab_width = parent->box.width - tab_width * i; |
659 | } | 665 | } |
660 | 666 | ||
661 | render_titlebar(output, damage, child, x, pstate->swayc_y, tab_width, | 667 | render_titlebar(output, damage, child, x, parent->box.y, tab_width, |
662 | colors, title_texture, marks_texture); | 668 | colors, title_texture, marks_texture); |
663 | 669 | ||
664 | if (child == current) { | 670 | if (child == current) { |
@@ -667,33 +673,30 @@ static void render_container_tabbed(struct sway_output *output, | |||
667 | } | 673 | } |
668 | 674 | ||
669 | // Render surface and left/right/bottom borders | 675 | // Render surface and left/right/bottom borders |
670 | if (current->type == C_VIEW) { | 676 | if (current->view) { |
671 | render_view(output, damage, current, current_colors); | 677 | render_view(output, damage, current, current_colors); |
672 | } else { | 678 | } else { |
673 | render_container(output, damage, current, | 679 | render_container(output, damage, current, |
674 | parent_focused || current->current.focused); | 680 | parent->focused || current->current.focused); |
675 | } | 681 | } |
676 | } | 682 | } |
677 | 683 | ||
678 | /** | 684 | /** |
679 | * Render a container's children using the L_STACKED layout. | 685 | * Render a container's children using the L_STACKED layout. |
680 | */ | 686 | */ |
681 | static void render_container_stacked(struct sway_output *output, | 687 | static void render_containers_stacked(struct sway_output *output, |
682 | pixman_region32_t *damage, struct sway_container *con, | 688 | pixman_region32_t *damage, struct parent_data *parent) { |
683 | bool parent_focused) { | 689 | if (!parent->children->length) { |
684 | if (!con->current.children->length) { | ||
685 | return; | 690 | return; |
686 | } | 691 | } |
687 | struct sway_container_state *pstate = &con->current; | 692 | struct sway_container *current = parent->active_child; |
688 | struct sway_container *current = pstate->focused_inactive_child; | ||
689 | struct border_colors *current_colors = &config->border_colors.unfocused; | 693 | struct border_colors *current_colors = &config->border_colors.unfocused; |
690 | |||
691 | size_t titlebar_height = container_titlebar_height(); | 694 | size_t titlebar_height = container_titlebar_height(); |
692 | 695 | ||
693 | // Render titles | 696 | // Render titles |
694 | for (int i = 0; i < pstate->children->length; ++i) { | 697 | for (int i = 0; i < parent->children->length; ++i) { |
695 | struct sway_container *child = pstate->children->items[i]; | 698 | struct sway_container *child = parent->children->items[i]; |
696 | struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; | 699 | struct sway_view *view = child->view; |
697 | struct sway_container_state *cstate = &child->current; | 700 | struct sway_container_state *cstate = &child->current; |
698 | struct border_colors *colors; | 701 | struct border_colors *colors; |
699 | struct wlr_texture *title_texture; | 702 | struct wlr_texture *title_texture; |
@@ -705,11 +708,11 @@ static void render_container_stacked(struct sway_output *output, | |||
705 | colors = &config->border_colors.urgent; | 708 | colors = &config->border_colors.urgent; |
706 | title_texture = child->title_urgent; | 709 | title_texture = child->title_urgent; |
707 | marks_texture = view ? view->marks_urgent : NULL; | 710 | marks_texture = view ? view->marks_urgent : NULL; |
708 | } else if (cstate->focused || parent_focused) { | 711 | } else if (cstate->focused || parent->focused) { |
709 | colors = &config->border_colors.focused; | 712 | colors = &config->border_colors.focused; |
710 | title_texture = child->title_focused; | 713 | title_texture = child->title_focused; |
711 | marks_texture = view ? view->marks_focused : NULL; | 714 | marks_texture = view ? view->marks_focused : NULL; |
712 | } else if (child == pstate->focused_inactive_child) { | 715 | } else if (child == parent->active_child) { |
713 | colors = &config->border_colors.focused_inactive; | 716 | colors = &config->border_colors.focused_inactive; |
714 | title_texture = child->title_focused_inactive; | 717 | title_texture = child->title_focused_inactive; |
715 | marks_texture = view ? view->marks_focused_inactive : NULL; | 718 | marks_texture = view ? view->marks_focused_inactive : NULL; |
@@ -719,9 +722,9 @@ static void render_container_stacked(struct sway_output *output, | |||
719 | marks_texture = view ? view->marks_unfocused : NULL; | 722 | marks_texture = view ? view->marks_unfocused : NULL; |
720 | } | 723 | } |
721 | 724 | ||
722 | int y = pstate->swayc_y + titlebar_height * i; | 725 | int y = parent->box.y + titlebar_height * i; |
723 | render_titlebar(output, damage, child, pstate->swayc_x, y, | 726 | render_titlebar(output, damage, child, parent->box.x, y, |
724 | pstate->swayc_width, colors, title_texture, marks_texture); | 727 | parent->box.width, colors, title_texture, marks_texture); |
725 | 728 | ||
726 | if (child == current) { | 729 | if (child == current) { |
727 | current_colors = colors; | 730 | current_colors = colors; |
@@ -729,36 +732,69 @@ static void render_container_stacked(struct sway_output *output, | |||
729 | } | 732 | } |
730 | 733 | ||
731 | // Render surface and left/right/bottom borders | 734 | // Render surface and left/right/bottom borders |
732 | if (current->type == C_VIEW) { | 735 | if (current->view) { |
733 | render_view(output, damage, current, current_colors); | 736 | render_view(output, damage, current, current_colors); |
734 | } else { | 737 | } else { |
735 | render_container(output, damage, current, | 738 | render_container(output, damage, current, |
736 | parent_focused || current->current.focused); | 739 | parent->focused || current->current.focused); |
737 | } | 740 | } |
738 | } | 741 | } |
739 | 742 | ||
740 | static void render_container(struct sway_output *output, | 743 | static void render_containers(struct sway_output *output, |
741 | pixman_region32_t *damage, struct sway_container *con, | 744 | pixman_region32_t *damage, struct parent_data *parent) { |
742 | bool parent_focused) { | 745 | switch (parent->layout) { |
743 | switch (con->current.layout) { | ||
744 | case L_NONE: | 746 | case L_NONE: |
745 | case L_HORIZ: | 747 | case L_HORIZ: |
746 | case L_VERT: | 748 | case L_VERT: |
747 | render_container_simple(output, damage, con, parent_focused); | 749 | render_containers_linear(output, damage, parent); |
748 | break; | 750 | break; |
749 | case L_STACKED: | 751 | case L_STACKED: |
750 | render_container_stacked(output, damage, con, parent_focused); | 752 | render_containers_stacked(output, damage, parent); |
751 | break; | 753 | break; |
752 | case L_TABBED: | 754 | case L_TABBED: |
753 | render_container_tabbed(output, damage, con, parent_focused); | 755 | render_containers_tabbed(output, damage, parent); |
754 | break; | 756 | break; |
755 | } | 757 | } |
756 | } | 758 | } |
757 | 759 | ||
760 | static void render_container(struct sway_output *output, | ||
761 | pixman_region32_t *damage, struct sway_container *con, bool focused) { | ||
762 | struct parent_data data = { | ||
763 | .layout = con->current.layout, | ||
764 | .box = { | ||
765 | .x = con->current.con_x, | ||
766 | .y = con->current.con_y, | ||
767 | .width = con->current.con_width, | ||
768 | .height = con->current.con_height, | ||
769 | }, | ||
770 | .children = con->current.children, | ||
771 | .focused = focused, | ||
772 | .active_child = con->current.focused_inactive_child, | ||
773 | }; | ||
774 | render_containers(output, damage, &data); | ||
775 | } | ||
776 | |||
777 | static void render_workspace(struct sway_output *output, | ||
778 | pixman_region32_t *damage, struct sway_workspace *ws, bool focused) { | ||
779 | struct parent_data data = { | ||
780 | .layout = ws->current.layout, | ||
781 | .box = { | ||
782 | .x = ws->current.x, | ||
783 | .y = ws->current.y, | ||
784 | .width = ws->current.width, | ||
785 | .height = ws->current.height, | ||
786 | }, | ||
787 | .children = ws->current.tiling, | ||
788 | .focused = focused, | ||
789 | .active_child = ws->current.focused_inactive_child, | ||
790 | }; | ||
791 | render_containers(output, damage, &data); | ||
792 | } | ||
793 | |||
758 | static void render_floating_container(struct sway_output *soutput, | 794 | static void render_floating_container(struct sway_output *soutput, |
759 | pixman_region32_t *damage, struct sway_container *con) { | 795 | pixman_region32_t *damage, struct sway_container *con) { |
760 | if (con->type == C_VIEW) { | 796 | if (con->view) { |
761 | struct sway_view *view = con->sway_view; | 797 | struct sway_view *view = con->view; |
762 | struct border_colors *colors; | 798 | struct border_colors *colors; |
763 | struct wlr_texture *title_texture; | 799 | struct wlr_texture *title_texture; |
764 | struct wlr_texture *marks_texture; | 800 | struct wlr_texture *marks_texture; |
@@ -777,10 +813,10 @@ static void render_floating_container(struct sway_output *soutput, | |||
777 | marks_texture = view->marks_unfocused; | 813 | marks_texture = view->marks_unfocused; |
778 | } | 814 | } |
779 | 815 | ||
780 | if (!view->swayc->current.using_csd) { | 816 | if (!view->container->current.using_csd) { |
781 | if (con->current.border == B_NORMAL) { | 817 | if (con->current.border == B_NORMAL) { |
782 | render_titlebar(soutput, damage, con, con->current.swayc_x, | 818 | render_titlebar(soutput, damage, con, con->current.con_x, |
783 | con->current.swayc_y, con->current.swayc_width, colors, | 819 | con->current.con_y, con->current.con_width, colors, |
784 | title_texture, marks_texture); | 820 | title_texture, marks_texture); |
785 | } else if (con->current.border != B_NONE) { | 821 | } else if (con->current.border != B_NONE) { |
786 | render_top_border(soutput, damage, con, colors); | 822 | render_top_border(soutput, damage, con, colors); |
@@ -794,17 +830,15 @@ static void render_floating_container(struct sway_output *soutput, | |||
794 | 830 | ||
795 | static void render_floating(struct sway_output *soutput, | 831 | static void render_floating(struct sway_output *soutput, |
796 | pixman_region32_t *damage) { | 832 | pixman_region32_t *damage) { |
797 | for (int i = 0; i < root_container.current.children->length; ++i) { | 833 | for (int i = 0; i < root->outputs->length; ++i) { |
798 | struct sway_container *output = | 834 | struct sway_output *output = root->outputs->items[i]; |
799 | root_container.current.children->items[i]; | 835 | for (int j = 0; j < output->current.workspaces->length; ++j) { |
800 | for (int j = 0; j < output->current.children->length; ++j) { | 836 | struct sway_workspace *ws = output->current.workspaces->items[j]; |
801 | struct sway_container *ws = output->current.children->items[j]; | ||
802 | if (!workspace_is_visible(ws)) { | 837 | if (!workspace_is_visible(ws)) { |
803 | continue; | 838 | continue; |
804 | } | 839 | } |
805 | list_t *floating = ws->current.ws_floating; | 840 | for (int k = 0; k < ws->current.floating->length; ++k) { |
806 | for (int k = 0; k < floating->length; ++k) { | 841 | struct sway_container *floater = ws->current.floating->items[k]; |
807 | struct sway_container *floater = floating->items[k]; | ||
808 | render_floating_container(soutput, damage, floater); | 842 | render_floating_container(soutput, damage, floater); |
809 | } | 843 | } |
810 | } | 844 | } |
@@ -837,8 +871,8 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
837 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | 871 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); |
838 | } | 872 | } |
839 | 873 | ||
840 | struct sway_container *workspace = output_get_active_workspace(output); | 874 | struct sway_workspace *workspace = output_get_active_workspace(output); |
841 | struct sway_container *fullscreen_con = workspace->current.ws_fullscreen; | 875 | struct sway_container *fullscreen_con = workspace->current.fullscreen; |
842 | 876 | ||
843 | if (output_has_opaque_overlay_layer_surface(output)) { | 877 | if (output_has_opaque_overlay_layer_surface(output)) { |
844 | goto render_overlay; | 878 | goto render_overlay; |
@@ -855,12 +889,11 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
855 | } | 889 | } |
856 | 890 | ||
857 | // TODO: handle views smaller than the output | 891 | // TODO: handle views smaller than the output |
858 | if (fullscreen_con->type == C_VIEW) { | 892 | if (fullscreen_con->view) { |
859 | if (fullscreen_con->sway_view->saved_buffer) { | 893 | if (fullscreen_con->view->saved_buffer) { |
860 | render_saved_view(fullscreen_con->sway_view, | 894 | render_saved_view(fullscreen_con->view, output, damage, 1.0f); |
861 | output, damage, 1.0f); | ||
862 | } else { | 895 | } else { |
863 | render_view_toplevels(fullscreen_con->sway_view, | 896 | render_view_toplevels(fullscreen_con->view, |
864 | output, damage, 1.0f); | 897 | output, damage, 1.0f); |
865 | } | 898 | } |
866 | } else { | 899 | } else { |
@@ -868,8 +901,7 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
868 | fullscreen_con->current.focused); | 901 | fullscreen_con->current.focused); |
869 | } | 902 | } |
870 | #ifdef HAVE_XWAYLAND | 903 | #ifdef HAVE_XWAYLAND |
871 | render_unmanaged(output, damage, | 904 | render_unmanaged(output, damage, &root->xwayland_unmanaged); |
872 | &root_container.sway_root->xwayland_unmanaged); | ||
873 | #endif | 905 | #endif |
874 | } else { | 906 | } else { |
875 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; | 907 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; |
@@ -886,31 +918,30 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
886 | render_layer(output, damage, | 918 | render_layer(output, damage, |
887 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); | 919 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); |
888 | 920 | ||
889 | render_container(output, damage, workspace, workspace->current.focused); | 921 | render_workspace(output, damage, workspace, workspace->current.focused); |
890 | render_floating(output, damage); | 922 | render_floating(output, damage); |
891 | #ifdef HAVE_XWAYLAND | 923 | #ifdef HAVE_XWAYLAND |
892 | render_unmanaged(output, damage, | 924 | render_unmanaged(output, damage, &root->xwayland_unmanaged); |
893 | &root_container.sway_root->xwayland_unmanaged); | ||
894 | #endif | 925 | #endif |
895 | render_layer(output, damage, | 926 | render_layer(output, damage, |
896 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | 927 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); |
897 | } | 928 | } |
898 | 929 | ||
899 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 930 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
900 | struct sway_container *focus = seat_get_focus(seat); | 931 | struct sway_container *focus = seat_get_focused_container(seat); |
901 | if (focus && focus->type == C_VIEW) { | 932 | if (focus && focus->view) { |
902 | render_view_popups(focus->sway_view, output, damage, focus->alpha); | 933 | render_view_popups(focus->view, output, damage, focus->alpha); |
903 | } | 934 | } |
904 | 935 | ||
905 | render_overlay: | 936 | render_overlay: |
906 | render_layer(output, damage, | 937 | render_layer(output, damage, |
907 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); | 938 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); |
908 | render_drag_icons(output, damage, &root_container.sway_root->drag_icons); | 939 | render_drag_icons(output, damage, &root->drag_icons); |
909 | 940 | ||
910 | renderer_end: | 941 | renderer_end: |
911 | if (debug.render_tree) { | 942 | if (debug.render_tree) { |
912 | wlr_renderer_scissor(renderer, NULL); | 943 | wlr_renderer_scissor(renderer, NULL); |
913 | wlr_render_texture(renderer, root_container.sway_root->debug_tree, | 944 | wlr_render_texture(renderer, root->debug_tree, |
914 | wlr_output->transform_matrix, 0, 40, 1); | 945 | wlr_output->transform_matrix, 0, 40, 1); |
915 | } | 946 | } |
916 | if (debug.damage == DAMAGE_HIGHLIGHT) { | 947 | if (debug.damage == DAMAGE_HIGHLIGHT) { |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 145c5f92..b4eec933 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "sway/desktop/transaction.h" | 12 | #include "sway/desktop/transaction.h" |
13 | #include "sway/output.h" | 13 | #include "sway/output.h" |
14 | #include "sway/tree/container.h" | 14 | #include "sway/tree/container.h" |
15 | #include "sway/tree/node.h" | ||
15 | #include "sway/tree/view.h" | 16 | #include "sway/tree/view.h" |
16 | #include "sway/tree/workspace.h" | 17 | #include "sway/tree/workspace.h" |
17 | #include "list.h" | 18 | #include "list.h" |
@@ -27,8 +28,12 @@ struct sway_transaction { | |||
27 | 28 | ||
28 | struct sway_transaction_instruction { | 29 | struct sway_transaction_instruction { |
29 | struct sway_transaction *transaction; | 30 | struct sway_transaction *transaction; |
30 | struct sway_container *container; | 31 | struct sway_node *node; |
31 | struct sway_container_state state; | 32 | union { |
33 | struct sway_output_state *output_state; | ||
34 | struct sway_workspace_state *workspace_state; | ||
35 | struct sway_container_state *container_state; | ||
36 | }; | ||
32 | uint32_t serial; | 37 | uint32_t serial; |
33 | }; | 38 | }; |
34 | 39 | ||
@@ -47,26 +52,24 @@ static void transaction_destroy(struct sway_transaction *transaction) { | |||
47 | for (int i = 0; i < transaction->instructions->length; ++i) { | 52 | for (int i = 0; i < transaction->instructions->length; ++i) { |
48 | struct sway_transaction_instruction *instruction = | 53 | struct sway_transaction_instruction *instruction = |
49 | transaction->instructions->items[i]; | 54 | transaction->instructions->items[i]; |
50 | struct sway_container *con = instruction->container; | 55 | struct sway_node *node = instruction->node; |
51 | con->ntxnrefs--; | 56 | node->ntxnrefs--; |
52 | if (con->instruction == instruction) { | 57 | if (node->instruction == instruction) { |
53 | con->instruction = NULL; | 58 | node->instruction = NULL; |
54 | } | 59 | } |
55 | if (con->destroying && con->ntxnrefs == 0) { | 60 | if (node->destroying && node->ntxnrefs == 0) { |
56 | switch (con->type) { | 61 | switch (node->type) { |
57 | case C_ROOT: | 62 | case N_ROOT: |
63 | sway_assert(false, "Never reached"); | ||
58 | break; | 64 | break; |
59 | case C_OUTPUT: | 65 | case N_OUTPUT: |
60 | output_destroy(con); | 66 | output_destroy(node->sway_output); |
61 | break; | 67 | break; |
62 | case C_WORKSPACE: | 68 | case N_WORKSPACE: |
63 | workspace_destroy(con); | 69 | workspace_destroy(node->sway_workspace); |
64 | break; | 70 | break; |
65 | case C_CONTAINER: | 71 | case N_CONTAINER: |
66 | case C_VIEW: | 72 | container_destroy(node->sway_container); |
67 | container_destroy(con); | ||
68 | break; | ||
69 | case C_TYPES: | ||
70 | break; | 73 | break; |
71 | } | 74 | } |
72 | } | 75 | } |
@@ -80,22 +83,79 @@ static void transaction_destroy(struct sway_transaction *transaction) { | |||
80 | free(transaction); | 83 | free(transaction); |
81 | } | 84 | } |
82 | 85 | ||
83 | static void copy_pending_state(struct sway_container *container, | 86 | static void copy_output_state(struct sway_output *output, |
84 | struct sway_container_state *state) { | 87 | struct sway_transaction_instruction *instruction) { |
88 | struct sway_output_state *state = | ||
89 | calloc(1, sizeof(struct sway_output_state)); | ||
90 | if (!state) { | ||
91 | wlr_log(WLR_ERROR, "Could not allocate output state"); | ||
92 | return; | ||
93 | } | ||
94 | instruction->output_state = state; | ||
95 | |||
96 | state->workspaces = create_list(); | ||
97 | list_cat(state->workspaces, output->workspaces); | ||
98 | |||
99 | state->active_workspace = output_get_active_workspace(output); | ||
100 | } | ||
101 | |||
102 | static void copy_workspace_state(struct sway_workspace *ws, | ||
103 | struct sway_transaction_instruction *instruction) { | ||
104 | struct sway_workspace_state *state = | ||
105 | calloc(1, sizeof(struct sway_workspace_state)); | ||
106 | if (!state) { | ||
107 | wlr_log(WLR_ERROR, "Could not allocate workspace state"); | ||
108 | return; | ||
109 | } | ||
110 | instruction->workspace_state = state; | ||
111 | |||
112 | state->fullscreen = ws->fullscreen; | ||
113 | state->x = ws->x; | ||
114 | state->y = ws->y; | ||
115 | state->width = ws->width; | ||
116 | state->height = ws->height; | ||
117 | state->layout = ws->layout; | ||
118 | |||
119 | state->output = ws->output; | ||
120 | state->floating = create_list(); | ||
121 | state->tiling = create_list(); | ||
122 | list_cat(state->floating, ws->floating); | ||
123 | list_cat(state->tiling, ws->tiling); | ||
124 | |||
125 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
126 | state->focused = seat_get_focus(seat) == &ws->node; | ||
127 | |||
128 | // Set focused_inactive_child to the direct tiling child | ||
129 | struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws); | ||
130 | if (focus) { | ||
131 | while (focus->parent) { | ||
132 | focus = focus->parent; | ||
133 | } | ||
134 | } | ||
135 | state->focused_inactive_child = focus; | ||
136 | } | ||
137 | |||
138 | static void copy_container_state(struct sway_container *container, | ||
139 | struct sway_transaction_instruction *instruction) { | ||
140 | struct sway_container_state *state = | ||
141 | calloc(1, sizeof(struct sway_container_state)); | ||
142 | if (!state) { | ||
143 | wlr_log(WLR_ERROR, "Could not allocate container state"); | ||
144 | return; | ||
145 | } | ||
146 | instruction->container_state = state; | ||
147 | |||
85 | state->layout = container->layout; | 148 | state->layout = container->layout; |
86 | state->swayc_x = container->x; | 149 | state->con_x = container->x; |
87 | state->swayc_y = container->y; | 150 | state->con_y = container->y; |
88 | state->swayc_width = container->width; | 151 | state->con_width = container->width; |
89 | state->swayc_height = container->height; | 152 | state->con_height = container->height; |
90 | state->is_fullscreen = container->is_fullscreen; | 153 | state->is_fullscreen = container->is_fullscreen; |
91 | state->has_gaps = container->has_gaps; | ||
92 | state->current_gaps = container->current_gaps; | ||
93 | state->gaps_inner = container->gaps_inner; | ||
94 | state->gaps_outer = container->gaps_outer; | ||
95 | state->parent = container->parent; | 154 | state->parent = container->parent; |
155 | state->workspace = container->workspace; | ||
96 | 156 | ||
97 | if (container->type == C_VIEW) { | 157 | if (container->view) { |
98 | struct sway_view *view = container->sway_view; | 158 | struct sway_view *view = container->view; |
99 | state->view_x = view->x; | 159 | state->view_x = view->x; |
100 | state->view_y = view->y; | 160 | state->view_y = view->y; |
101 | state->view_width = view->width; | 161 | state->view_width = view->width; |
@@ -107,50 +167,111 @@ static void copy_pending_state(struct sway_container *container, | |||
107 | state->border_right = view->border_right; | 167 | state->border_right = view->border_right; |
108 | state->border_bottom = view->border_bottom; | 168 | state->border_bottom = view->border_bottom; |
109 | state->using_csd = view->using_csd; | 169 | state->using_csd = view->using_csd; |
110 | } else if (container->type == C_WORKSPACE) { | ||
111 | state->ws_fullscreen = container->sway_workspace->fullscreen; | ||
112 | state->ws_floating = create_list(); | ||
113 | state->children = create_list(); | ||
114 | list_cat(state->ws_floating, container->sway_workspace->floating); | ||
115 | list_cat(state->children, container->children); | ||
116 | } else { | 170 | } else { |
117 | state->children = create_list(); | 171 | state->children = create_list(); |
118 | list_cat(state->children, container->children); | 172 | list_cat(state->children, container->children); |
119 | } | 173 | } |
120 | 174 | ||
121 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 175 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
122 | state->focused = seat_get_focus(seat) == container; | 176 | state->focused = seat_get_focus(seat) == &container->node; |
123 | 177 | ||
124 | if (container->type == C_WORKSPACE) { | 178 | if (!container->view) { |
125 | // Set focused_inactive_child to the direct tiling child | 179 | struct sway_node *focus = seat_get_active_child(seat, &container->node); |
126 | struct sway_container *focus = | 180 | state->focused_inactive_child = focus ? focus->sway_container : NULL; |
127 | seat_get_focus_inactive_tiling(seat, container); | ||
128 | if (focus && focus->type > C_WORKSPACE) { | ||
129 | while (focus->parent->type != C_WORKSPACE) { | ||
130 | focus = focus->parent; | ||
131 | } | ||
132 | } | ||
133 | state->focused_inactive_child = focus; | ||
134 | } else if (container->type != C_VIEW) { | ||
135 | state->focused_inactive_child = | ||
136 | seat_get_active_child(seat, container); | ||
137 | } | 181 | } |
138 | } | 182 | } |
139 | 183 | ||
140 | static void transaction_add_container(struct sway_transaction *transaction, | 184 | static void transaction_add_node(struct sway_transaction *transaction, |
141 | struct sway_container *container) { | 185 | struct sway_node *node) { |
142 | struct sway_transaction_instruction *instruction = | 186 | struct sway_transaction_instruction *instruction = |
143 | calloc(1, sizeof(struct sway_transaction_instruction)); | 187 | calloc(1, sizeof(struct sway_transaction_instruction)); |
144 | if (!sway_assert(instruction, "Unable to allocate instruction")) { | 188 | if (!sway_assert(instruction, "Unable to allocate instruction")) { |
145 | return; | 189 | return; |
146 | } | 190 | } |
147 | instruction->transaction = transaction; | 191 | instruction->transaction = transaction; |
148 | instruction->container = container; | 192 | instruction->node = node; |
149 | 193 | ||
150 | copy_pending_state(container, &instruction->state); | 194 | switch (node->type) { |
195 | case N_ROOT: | ||
196 | break; | ||
197 | case N_OUTPUT: | ||
198 | copy_output_state(node->sway_output, instruction); | ||
199 | break; | ||
200 | case N_WORKSPACE: | ||
201 | copy_workspace_state(node->sway_workspace, instruction); | ||
202 | break; | ||
203 | case N_CONTAINER: | ||
204 | copy_container_state(node->sway_container, instruction); | ||
205 | break; | ||
206 | } | ||
151 | 207 | ||
152 | list_add(transaction->instructions, instruction); | 208 | list_add(transaction->instructions, instruction); |
153 | container->ntxnrefs++; | 209 | node->ntxnrefs++; |
210 | } | ||
211 | |||
212 | static void apply_output_state(struct sway_output *output, | ||
213 | struct sway_output_state *state) { | ||
214 | output_damage_whole(output); | ||
215 | list_free(output->current.workspaces); | ||
216 | memcpy(&output->current, state, sizeof(struct sway_output_state)); | ||
217 | output_damage_whole(output); | ||
218 | } | ||
219 | |||
220 | static void apply_workspace_state(struct sway_workspace *ws, | ||
221 | struct sway_workspace_state *state) { | ||
222 | output_damage_whole(ws->current.output); | ||
223 | list_free(ws->current.floating); | ||
224 | list_free(ws->current.tiling); | ||
225 | memcpy(&ws->current, state, sizeof(struct sway_workspace_state)); | ||
226 | output_damage_whole(ws->current.output); | ||
227 | } | ||
228 | |||
229 | static void apply_container_state(struct sway_container *container, | ||
230 | struct sway_container_state *state) { | ||
231 | struct sway_view *view = container->view; | ||
232 | // Damage the old location | ||
233 | desktop_damage_whole_container(container); | ||
234 | if (view && view->saved_buffer) { | ||
235 | struct wlr_box box = { | ||
236 | .x = container->current.view_x - view->saved_geometry.x, | ||
237 | .y = container->current.view_y - view->saved_geometry.y, | ||
238 | .width = view->saved_buffer_width, | ||
239 | .height = view->saved_buffer_height, | ||
240 | }; | ||
241 | desktop_damage_box(&box); | ||
242 | } | ||
243 | |||
244 | // There are separate children lists for each instruction state, the | ||
245 | // container's current state and the container's pending state | ||
246 | // (ie. con->children). The list itself needs to be freed here. | ||
247 | // Any child containers which are being deleted will be cleaned up in | ||
248 | // transaction_destroy(). | ||
249 | list_free(container->current.children); | ||
250 | |||
251 | memcpy(&container->current, state, sizeof(struct sway_container_state)); | ||
252 | |||
253 | if (view && view->saved_buffer) { | ||
254 | if (!container->node.destroying || container->node.ntxnrefs == 1) { | ||
255 | view_remove_saved_buffer(view); | ||
256 | } | ||
257 | } | ||
258 | |||
259 | // Damage the new location | ||
260 | desktop_damage_whole_container(container); | ||
261 | if (view && view->surface) { | ||
262 | struct wlr_surface *surface = view->surface; | ||
263 | struct wlr_box box = { | ||
264 | .x = container->current.view_x - view->geometry.x, | ||
265 | .y = container->current.view_y - view->geometry.y, | ||
266 | .width = surface->current.width, | ||
267 | .height = surface->current.height, | ||
268 | }; | ||
269 | desktop_damage_box(&box); | ||
270 | } | ||
271 | |||
272 | if (!container->node.destroying) { | ||
273 | container_discover_outputs(container); | ||
274 | } | ||
154 | } | 275 | } |
155 | 276 | ||
156 | /** | 277 | /** |
@@ -168,67 +289,36 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
168 | "(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60)); | 289 | "(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60)); |
169 | } | 290 | } |
170 | 291 | ||
171 | // Apply the instruction state to the container's current state | 292 | // Apply the instruction state to the node's current state |
172 | for (int i = 0; i < transaction->instructions->length; ++i) { | 293 | for (int i = 0; i < transaction->instructions->length; ++i) { |
173 | struct sway_transaction_instruction *instruction = | 294 | struct sway_transaction_instruction *instruction = |
174 | transaction->instructions->items[i]; | 295 | transaction->instructions->items[i]; |
175 | struct sway_container *container = instruction->container; | 296 | struct sway_node *node = instruction->node; |
176 | |||
177 | // Damage the old location | ||
178 | desktop_damage_whole_container(container); | ||
179 | if (container->type == C_VIEW && container->sway_view->saved_buffer) { | ||
180 | struct sway_view *view = container->sway_view; | ||
181 | struct wlr_box box = { | ||
182 | .x = container->current.view_x - view->saved_geometry.x, | ||
183 | .y = container->current.view_y - view->saved_geometry.y, | ||
184 | .width = view->saved_buffer_width, | ||
185 | .height = view->saved_buffer_height, | ||
186 | }; | ||
187 | desktop_damage_box(&box); | ||
188 | } | ||
189 | |||
190 | // There are separate children lists for each instruction state, the | ||
191 | // container's current state and the container's pending state | ||
192 | // (ie. con->children). The list itself needs to be freed here. | ||
193 | // Any child containers which are being deleted will be cleaned up in | ||
194 | // transaction_destroy(). | ||
195 | list_free(container->current.children); | ||
196 | list_free(container->current.ws_floating); | ||
197 | |||
198 | memcpy(&container->current, &instruction->state, | ||
199 | sizeof(struct sway_container_state)); | ||
200 | |||
201 | if (container->type == C_VIEW && container->sway_view->saved_buffer) { | ||
202 | if (!container->destroying || container->ntxnrefs == 1) { | ||
203 | view_remove_saved_buffer(container->sway_view); | ||
204 | } | ||
205 | } | ||
206 | 297 | ||
207 | // Damage the new location | 298 | switch (node->type) { |
208 | desktop_damage_whole_container(container); | 299 | case N_ROOT: |
209 | if (container->type == C_VIEW && container->sway_view->surface) { | 300 | break; |
210 | struct sway_view *view = container->sway_view; | 301 | case N_OUTPUT: |
211 | struct wlr_surface *surface = view->surface; | 302 | apply_output_state(node->sway_output, instruction->output_state); |
212 | struct wlr_box box = { | 303 | break; |
213 | .x = container->current.view_x - view->geometry.x, | 304 | case N_WORKSPACE: |
214 | .y = container->current.view_y - view->geometry.y, | 305 | apply_workspace_state(node->sway_workspace, |
215 | .width = surface->current.width, | 306 | instruction->workspace_state); |
216 | .height = surface->current.height, | 307 | break; |
217 | }; | 308 | case N_CONTAINER: |
218 | desktop_damage_box(&box); | 309 | apply_container_state(node->sway_container, |
310 | instruction->container_state); | ||
311 | break; | ||
219 | } | 312 | } |
220 | 313 | ||
221 | container->instruction = NULL; | 314 | node->instruction = NULL; |
222 | if (container->type == C_CONTAINER || container->type == C_VIEW) { | ||
223 | container_discover_outputs(container); | ||
224 | } | ||
225 | } | 315 | } |
226 | } | 316 | } |
227 | 317 | ||
228 | static void transaction_commit(struct sway_transaction *transaction); | 318 | static void transaction_commit(struct sway_transaction *transaction); |
229 | 319 | ||
230 | // Return true if both transactions operate on the same containers | 320 | // Return true if both transactions operate on the same nodes |
231 | static bool transaction_same_containers(struct sway_transaction *a, | 321 | static bool transaction_same_nodes(struct sway_transaction *a, |
232 | struct sway_transaction *b) { | 322 | struct sway_transaction *b) { |
233 | if (a->instructions->length != b->instructions->length) { | 323 | if (a->instructions->length != b->instructions->length) { |
234 | return false; | 324 | return false; |
@@ -236,7 +326,7 @@ static bool transaction_same_containers(struct sway_transaction *a, | |||
236 | for (int i = 0; i < a->instructions->length; ++i) { | 326 | for (int i = 0; i < a->instructions->length; ++i) { |
237 | struct sway_transaction_instruction *a_inst = a->instructions->items[i]; | 327 | struct sway_transaction_instruction *a_inst = a->instructions->items[i]; |
238 | struct sway_transaction_instruction *b_inst = b->instructions->items[i]; | 328 | struct sway_transaction_instruction *b_inst = b->instructions->items[i]; |
239 | if (a_inst->container != b_inst->container) { | 329 | if (a_inst->node != b_inst->node) { |
240 | return false; | 330 | return false; |
241 | } | 331 | } |
242 | } | 332 | } |
@@ -267,7 +357,7 @@ static void transaction_progress_queue() { | |||
267 | while (server.transactions->length >= 2) { | 357 | while (server.transactions->length >= 2) { |
268 | struct sway_transaction *a = server.transactions->items[0]; | 358 | struct sway_transaction *a = server.transactions->items[0]; |
269 | struct sway_transaction *b = server.transactions->items[1]; | 359 | struct sway_transaction *b = server.transactions->items[1]; |
270 | if (transaction_same_containers(a, b)) { | 360 | if (transaction_same_nodes(a, b)) { |
271 | list_del(server.transactions, 0); | 361 | list_del(server.transactions, 0); |
272 | transaction_destroy(a); | 362 | transaction_destroy(a); |
273 | } else { | 363 | } else { |
@@ -289,16 +379,18 @@ static int handle_timeout(void *data) { | |||
289 | return 0; | 379 | return 0; |
290 | } | 380 | } |
291 | 381 | ||
292 | static bool should_configure(struct sway_container *con, | 382 | static bool should_configure(struct sway_node *node, |
293 | struct sway_transaction_instruction *instruction) { | 383 | struct sway_transaction_instruction *instruction) { |
294 | if (con->type != C_VIEW) { | 384 | if (!node_is_view(node)) { |
295 | return false; | 385 | return false; |
296 | } | 386 | } |
297 | if (con->destroying) { | 387 | if (node->destroying) { |
298 | return false; | 388 | return false; |
299 | } | 389 | } |
300 | if (con->current.view_width == instruction->state.view_width && | 390 | struct sway_container_state *cstate = &node->sway_container->current; |
301 | con->current.view_height == instruction->state.view_height) { | 391 | struct sway_container_state *istate = instruction->container_state; |
392 | if (cstate->view_width == istate->view_width && | ||
393 | cstate->view_height == istate->view_height) { | ||
302 | return false; | 394 | return false; |
303 | } | 395 | } |
304 | return true; | 396 | return true; |
@@ -311,13 +403,13 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
311 | for (int i = 0; i < transaction->instructions->length; ++i) { | 403 | for (int i = 0; i < transaction->instructions->length; ++i) { |
312 | struct sway_transaction_instruction *instruction = | 404 | struct sway_transaction_instruction *instruction = |
313 | transaction->instructions->items[i]; | 405 | transaction->instructions->items[i]; |
314 | struct sway_container *con = instruction->container; | 406 | struct sway_node *node = instruction->node; |
315 | if (should_configure(con, instruction)) { | 407 | if (should_configure(node, instruction)) { |
316 | instruction->serial = view_configure(con->sway_view, | 408 | instruction->serial = view_configure(node->sway_container->view, |
317 | instruction->state.view_x, | 409 | instruction->container_state->view_x, |
318 | instruction->state.view_y, | 410 | instruction->container_state->view_y, |
319 | instruction->state.view_width, | 411 | instruction->container_state->view_width, |
320 | instruction->state.view_height); | 412 | instruction->container_state->view_height); |
321 | ++transaction->num_waiting; | 413 | ++transaction->num_waiting; |
322 | 414 | ||
323 | // From here on we are rendering a saved buffer of the view, which | 415 | // From here on we are rendering a saved buffer of the view, which |
@@ -325,14 +417,16 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
325 | // as soon as possible. Additionally, this is required if a view is | 417 | // as soon as possible. Additionally, this is required if a view is |
326 | // mapping and its default geometry doesn't intersect an output. | 418 | // mapping and its default geometry doesn't intersect an output. |
327 | struct timespec when; | 419 | struct timespec when; |
328 | wlr_surface_send_frame_done(con->sway_view->surface, &when); | 420 | wlr_surface_send_frame_done( |
421 | node->sway_container->view->surface, &when); | ||
329 | } | 422 | } |
330 | if (con->type == C_VIEW && !con->sway_view->saved_buffer) { | 423 | if (node_is_view(node) && !node->sway_container->view->saved_buffer) { |
331 | view_save_buffer(con->sway_view); | 424 | view_save_buffer(node->sway_container->view); |
332 | memcpy(&con->sway_view->saved_geometry, &con->sway_view->geometry, | 425 | memcpy(&node->sway_container->view->saved_geometry, |
426 | &node->sway_container->view->geometry, | ||
333 | sizeof(struct wlr_box)); | 427 | sizeof(struct wlr_box)); |
334 | } | 428 | } |
335 | con->instruction = instruction; | 429 | node->instruction = instruction; |
336 | } | 430 | } |
337 | transaction->num_configures = transaction->num_waiting; | 431 | transaction->num_configures = transaction->num_waiting; |
338 | if (debug.txn_timings) { | 432 | if (debug.txn_timings) { |
@@ -381,7 +475,7 @@ static void set_instruction_ready( | |||
381 | transaction, | 475 | transaction, |
382 | transaction->num_configures - transaction->num_waiting + 1, | 476 | transaction->num_configures - transaction->num_waiting + 1, |
383 | transaction->num_configures, ms, | 477 | transaction->num_configures, ms, |
384 | instruction->container->name); | 478 | instruction->node->sway_container->title); |
385 | } | 479 | } |
386 | 480 | ||
387 | // If the transaction has timed out then its num_waiting will be 0 already. | 481 | // If the transaction has timed out then its num_waiting will be 0 already. |
@@ -390,41 +484,43 @@ static void set_instruction_ready( | |||
390 | wl_event_source_timer_update(transaction->timer, 0); | 484 | wl_event_source_timer_update(transaction->timer, 0); |
391 | } | 485 | } |
392 | 486 | ||
393 | instruction->container->instruction = NULL; | 487 | instruction->node->instruction = NULL; |
394 | transaction_progress_queue(); | 488 | transaction_progress_queue(); |
395 | } | 489 | } |
396 | 490 | ||
397 | void transaction_notify_view_ready_by_serial(struct sway_view *view, | 491 | void transaction_notify_view_ready_by_serial(struct sway_view *view, |
398 | uint32_t serial) { | 492 | uint32_t serial) { |
399 | struct sway_transaction_instruction *instruction = view->swayc->instruction; | 493 | struct sway_transaction_instruction *instruction = |
400 | if (view->swayc->instruction->serial == serial) { | 494 | view->container->node.instruction; |
495 | if (instruction->serial == serial) { | ||
401 | set_instruction_ready(instruction); | 496 | set_instruction_ready(instruction); |
402 | } | 497 | } |
403 | } | 498 | } |
404 | 499 | ||
405 | void transaction_notify_view_ready_by_size(struct sway_view *view, | 500 | void transaction_notify_view_ready_by_size(struct sway_view *view, |
406 | int width, int height) { | 501 | int width, int height) { |
407 | struct sway_transaction_instruction *instruction = view->swayc->instruction; | 502 | struct sway_transaction_instruction *instruction = |
408 | if (instruction->state.view_width == width && | 503 | view->container->node.instruction; |
409 | instruction->state.view_height == height) { | 504 | if (instruction->container_state->view_width == width && |
505 | instruction->container_state->view_height == height) { | ||
410 | set_instruction_ready(instruction); | 506 | set_instruction_ready(instruction); |
411 | } | 507 | } |
412 | } | 508 | } |
413 | 509 | ||
414 | void transaction_commit_dirty(void) { | 510 | void transaction_commit_dirty(void) { |
415 | if (!server.dirty_containers->length) { | 511 | if (!server.dirty_nodes->length) { |
416 | return; | 512 | return; |
417 | } | 513 | } |
418 | struct sway_transaction *transaction = transaction_create(); | 514 | struct sway_transaction *transaction = transaction_create(); |
419 | if (!transaction) { | 515 | if (!transaction) { |
420 | return; | 516 | return; |
421 | } | 517 | } |
422 | for (int i = 0; i < server.dirty_containers->length; ++i) { | 518 | for (int i = 0; i < server.dirty_nodes->length; ++i) { |
423 | struct sway_container *container = server.dirty_containers->items[i]; | 519 | struct sway_node *node = server.dirty_nodes->items[i]; |
424 | transaction_add_container(transaction, container); | 520 | transaction_add_node(transaction, node); |
425 | container->dirty = false; | 521 | node->dirty = false; |
426 | } | 522 | } |
427 | server.dirty_containers->length = 0; | 523 | server.dirty_nodes->length = 0; |
428 | 524 | ||
429 | list_add(server.transactions, transaction); | 525 | list_add(server.transactions, transaction); |
430 | 526 | ||
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 587deb0f..e19d8e18 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -11,10 +11,12 @@ | |||
11 | #include "sway/desktop/transaction.h" | 11 | #include "sway/desktop/transaction.h" |
12 | #include "sway/input/input-manager.h" | 12 | #include "sway/input/input-manager.h" |
13 | #include "sway/input/seat.h" | 13 | #include "sway/input/seat.h" |
14 | #include "sway/output.h" | ||
14 | #include "sway/server.h" | 15 | #include "sway/server.h" |
15 | #include "sway/tree/arrange.h" | 16 | #include "sway/tree/arrange.h" |
16 | #include "sway/tree/container.h" | 17 | #include "sway/tree/container.h" |
17 | #include "sway/tree/view.h" | 18 | #include "sway/tree/view.h" |
19 | #include "sway/tree/workspace.h" | ||
18 | 20 | ||
19 | static const struct sway_view_child_impl popup_impl; | 21 | static const struct sway_view_child_impl popup_impl; |
20 | 22 | ||
@@ -52,15 +54,15 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) { | |||
52 | struct sway_view *view = popup->child.view; | 54 | struct sway_view *view = popup->child.view; |
53 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; | 55 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; |
54 | 56 | ||
55 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 57 | struct sway_output *output = view->container->workspace->output; |
56 | 58 | ||
57 | // the output box expressed in the coordinate system of the toplevel parent | 59 | // the output box expressed in the coordinate system of the toplevel parent |
58 | // of the popup | 60 | // of the popup |
59 | struct wlr_box output_toplevel_sx_box = { | 61 | struct wlr_box output_toplevel_sx_box = { |
60 | .x = output->x - view->x, | 62 | .x = output->wlr_output->lx - view->x, |
61 | .y = output->y - view->y, | 63 | .y = output->wlr_output->ly - view->y, |
62 | .width = output->width, | 64 | .width = output->wlr_output->width, |
63 | .height = output->height, | 65 | .height = output->wlr_output->height, |
64 | }; | 66 | }; |
65 | 67 | ||
66 | wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); | 68 | wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); |
@@ -252,11 +254,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
252 | struct sway_view *view = &xdg_shell_view->view; | 254 | struct sway_view *view = &xdg_shell_view->view; |
253 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; | 255 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; |
254 | 256 | ||
255 | if (!view->swayc) { | 257 | if (view->container->node.instruction) { |
256 | return; | ||
257 | } | ||
258 | |||
259 | if (view->swayc->instruction) { | ||
260 | wlr_xdg_surface_get_geometry(xdg_surface, &view->geometry); | 258 | wlr_xdg_surface_get_geometry(xdg_surface, &view->geometry); |
261 | transaction_notify_view_ready_by_serial(view, | 259 | transaction_notify_view_ready_by_serial(view, |
262 | xdg_surface->configure_serial); | 260 | xdg_surface->configure_serial); |
@@ -265,7 +263,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
265 | wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); | 263 | wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); |
266 | 264 | ||
267 | if ((new_geo.width != view->width || new_geo.height != view->height) && | 265 | if ((new_geo.width != view->width || new_geo.height != view->height) && |
268 | container_is_floating(view->swayc)) { | 266 | container_is_floating(view->container)) { |
269 | // A floating view has unexpectedly sent a new size | 267 | // A floating view has unexpectedly sent a new size |
270 | desktop_damage_view(view); | 268 | desktop_damage_view(view); |
271 | view_update_size(view, new_geo.width, new_geo.height); | 269 | view_update_size(view, new_geo.width, new_geo.height); |
@@ -319,10 +317,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
319 | return; | 317 | return; |
320 | } | 318 | } |
321 | 319 | ||
322 | container_set_fullscreen(view->swayc, e->fullscreen); | 320 | container_set_fullscreen(view->container, e->fullscreen); |
323 | 321 | ||
324 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 322 | arrange_workspace(view->container->workspace); |
325 | arrange_windows(output); | ||
326 | transaction_commit_dirty(); | 323 | transaction_commit_dirty(); |
327 | } | 324 | } |
328 | 325 | ||
@@ -330,13 +327,13 @@ static void handle_request_move(struct wl_listener *listener, void *data) { | |||
330 | struct sway_xdg_shell_view *xdg_shell_view = | 327 | struct sway_xdg_shell_view *xdg_shell_view = |
331 | wl_container_of(listener, xdg_shell_view, request_move); | 328 | wl_container_of(listener, xdg_shell_view, request_move); |
332 | struct sway_view *view = &xdg_shell_view->view; | 329 | struct sway_view *view = &xdg_shell_view->view; |
333 | if (!container_is_floating(view->swayc)) { | 330 | if (!container_is_floating(view->container)) { |
334 | return; | 331 | return; |
335 | } | 332 | } |
336 | struct wlr_xdg_toplevel_move_event *e = data; | 333 | struct wlr_xdg_toplevel_move_event *e = data; |
337 | struct sway_seat *seat = e->seat->seat->data; | 334 | struct sway_seat *seat = e->seat->seat->data; |
338 | if (e->serial == seat->last_button_serial) { | 335 | if (e->serial == seat->last_button_serial) { |
339 | seat_begin_move(seat, view->swayc, seat->last_button); | 336 | seat_begin_move(seat, view->container, seat->last_button); |
340 | } | 337 | } |
341 | } | 338 | } |
342 | 339 | ||
@@ -344,13 +341,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { | |||
344 | struct sway_xdg_shell_view *xdg_shell_view = | 341 | struct sway_xdg_shell_view *xdg_shell_view = |
345 | wl_container_of(listener, xdg_shell_view, request_resize); | 342 | wl_container_of(listener, xdg_shell_view, request_resize); |
346 | struct sway_view *view = &xdg_shell_view->view; | 343 | struct sway_view *view = &xdg_shell_view->view; |
347 | if (!container_is_floating(view->swayc)) { | 344 | if (!container_is_floating(view->container)) { |
348 | return; | 345 | return; |
349 | } | 346 | } |
350 | struct wlr_xdg_toplevel_resize_event *e = data; | 347 | struct wlr_xdg_toplevel_resize_event *e = data; |
351 | struct sway_seat *seat = e->seat->seat->data; | 348 | struct sway_seat *seat = e->seat->seat->data; |
352 | if (e->serial == seat->last_button_serial) { | 349 | if (e->serial == seat->last_button_serial) { |
353 | seat_begin_resize_floating(seat, view->swayc, | 350 | seat_begin_resize_floating(seat, view->container, |
354 | seat->last_button, e->edges); | 351 | seat->last_button, e->edges); |
355 | } | 352 | } |
356 | } | 353 | } |
@@ -399,11 +396,14 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
399 | view_map(view, view->wlr_xdg_surface->surface); | 396 | view_map(view, view->wlr_xdg_surface->surface); |
400 | 397 | ||
401 | if (xdg_surface->toplevel->client_pending.fullscreen) { | 398 | if (xdg_surface->toplevel->client_pending.fullscreen) { |
402 | container_set_fullscreen(view->swayc, true); | 399 | container_set_fullscreen(view->container, true); |
403 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 400 | arrange_workspace(view->container->workspace); |
404 | arrange_windows(ws); | ||
405 | } else { | 401 | } else { |
406 | arrange_windows(view->swayc->parent); | 402 | if (view->container->parent) { |
403 | arrange_container(view->container->parent); | ||
404 | } else { | ||
405 | arrange_workspace(view->container->workspace); | ||
406 | } | ||
407 | } | 407 | } |
408 | transaction_commit_dirty(); | 408 | transaction_commit_dirty(); |
409 | 409 | ||
@@ -440,8 +440,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
440 | struct sway_xdg_shell_view *xdg_shell_view = | 440 | struct sway_xdg_shell_view *xdg_shell_view = |
441 | wl_container_of(listener, xdg_shell_view, destroy); | 441 | wl_container_of(listener, xdg_shell_view, destroy); |
442 | struct sway_view *view = &xdg_shell_view->view; | 442 | struct sway_view *view = &xdg_shell_view->view; |
443 | if (!sway_assert(view->swayc == NULL || view->swayc->destroying, | 443 | if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { |
444 | "Tried to destroy a mapped view")) { | ||
445 | return; | 444 | return; |
446 | } | 445 | } |
447 | wl_list_remove(&xdg_shell_view->destroy.link); | 446 | wl_list_remove(&xdg_shell_view->destroy.link); |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 175416f3..b23d4577 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -10,10 +10,12 @@ | |||
10 | #include "sway/desktop/transaction.h" | 10 | #include "sway/desktop/transaction.h" |
11 | #include "sway/input/input-manager.h" | 11 | #include "sway/input/input-manager.h" |
12 | #include "sway/input/seat.h" | 12 | #include "sway/input/seat.h" |
13 | #include "sway/output.h" | ||
13 | #include "sway/server.h" | 14 | #include "sway/server.h" |
14 | #include "sway/tree/arrange.h" | 15 | #include "sway/tree/arrange.h" |
15 | #include "sway/tree/container.h" | 16 | #include "sway/tree/container.h" |
16 | #include "sway/tree/view.h" | 17 | #include "sway/tree/view.h" |
18 | #include "sway/tree/workspace.h" | ||
17 | 19 | ||
18 | static const struct sway_view_child_impl popup_impl; | 20 | static const struct sway_view_child_impl popup_impl; |
19 | 21 | ||
@@ -51,15 +53,15 @@ static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { | |||
51 | struct sway_view *view = popup->child.view; | 53 | struct sway_view *view = popup->child.view; |
52 | struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; | 54 | struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; |
53 | 55 | ||
54 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 56 | struct sway_output *output = view->container->workspace->output; |
55 | 57 | ||
56 | // the output box expressed in the coordinate system of the toplevel parent | 58 | // the output box expressed in the coordinate system of the toplevel parent |
57 | // of the popup | 59 | // of the popup |
58 | struct wlr_box output_toplevel_sx_box = { | 60 | struct wlr_box output_toplevel_sx_box = { |
59 | .x = output->x - view->x, | 61 | .x = output->wlr_output->lx - view->x, |
60 | .y = output->y - view->y, | 62 | .y = output->wlr_output->ly - view->y, |
61 | .width = output->width, | 63 | .width = output->wlr_output->width, |
62 | .height = output->height, | 64 | .height = output->wlr_output->height, |
63 | }; | 65 | }; |
64 | 66 | ||
65 | wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); | 67 | wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); |
@@ -249,11 +251,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
249 | struct sway_view *view = &xdg_shell_v6_view->view; | 251 | struct sway_view *view = &xdg_shell_v6_view->view; |
250 | struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6; | 252 | struct wlr_xdg_surface_v6 *xdg_surface_v6 = view->wlr_xdg_surface_v6; |
251 | 253 | ||
252 | if (!view->swayc) { | 254 | if (view->container->node.instruction) { |
253 | return; | ||
254 | } | ||
255 | |||
256 | if (view->swayc->instruction) { | ||
257 | wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &view->geometry); | 255 | wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &view->geometry); |
258 | transaction_notify_view_ready_by_serial(view, | 256 | transaction_notify_view_ready_by_serial(view, |
259 | xdg_surface_v6->configure_serial); | 257 | xdg_surface_v6->configure_serial); |
@@ -262,7 +260,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
262 | wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &new_geo); | 260 | wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &new_geo); |
263 | 261 | ||
264 | if ((new_geo.width != view->width || new_geo.height != view->height) && | 262 | if ((new_geo.width != view->width || new_geo.height != view->height) && |
265 | container_is_floating(view->swayc)) { | 263 | container_is_floating(view->container)) { |
266 | // A floating view has unexpectedly sent a new size | 264 | // A floating view has unexpectedly sent a new size |
267 | desktop_damage_view(view); | 265 | desktop_damage_view(view); |
268 | view_update_size(view, new_geo.width, new_geo.height); | 266 | view_update_size(view, new_geo.width, new_geo.height); |
@@ -316,10 +314,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
316 | return; | 314 | return; |
317 | } | 315 | } |
318 | 316 | ||
319 | container_set_fullscreen(view->swayc, e->fullscreen); | 317 | container_set_fullscreen(view->container, e->fullscreen); |
320 | 318 | ||
321 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 319 | arrange_workspace(view->container->workspace); |
322 | arrange_windows(output); | ||
323 | transaction_commit_dirty(); | 320 | transaction_commit_dirty(); |
324 | } | 321 | } |
325 | 322 | ||
@@ -327,13 +324,13 @@ static void handle_request_move(struct wl_listener *listener, void *data) { | |||
327 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | 324 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = |
328 | wl_container_of(listener, xdg_shell_v6_view, request_move); | 325 | wl_container_of(listener, xdg_shell_v6_view, request_move); |
329 | struct sway_view *view = &xdg_shell_v6_view->view; | 326 | struct sway_view *view = &xdg_shell_v6_view->view; |
330 | if (!container_is_floating(view->swayc)) { | 327 | if (!container_is_floating(view->container)) { |
331 | return; | 328 | return; |
332 | } | 329 | } |
333 | struct wlr_xdg_toplevel_v6_move_event *e = data; | 330 | struct wlr_xdg_toplevel_v6_move_event *e = data; |
334 | struct sway_seat *seat = e->seat->seat->data; | 331 | struct sway_seat *seat = e->seat->seat->data; |
335 | if (e->serial == seat->last_button_serial) { | 332 | if (e->serial == seat->last_button_serial) { |
336 | seat_begin_move(seat, view->swayc, seat->last_button); | 333 | seat_begin_move(seat, view->container, seat->last_button); |
337 | } | 334 | } |
338 | } | 335 | } |
339 | 336 | ||
@@ -341,13 +338,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { | |||
341 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | 338 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = |
342 | wl_container_of(listener, xdg_shell_v6_view, request_resize); | 339 | wl_container_of(listener, xdg_shell_v6_view, request_resize); |
343 | struct sway_view *view = &xdg_shell_v6_view->view; | 340 | struct sway_view *view = &xdg_shell_v6_view->view; |
344 | if (!container_is_floating(view->swayc)) { | 341 | if (!container_is_floating(view->container)) { |
345 | return; | 342 | return; |
346 | } | 343 | } |
347 | struct wlr_xdg_toplevel_v6_resize_event *e = data; | 344 | struct wlr_xdg_toplevel_v6_resize_event *e = data; |
348 | struct sway_seat *seat = e->seat->seat->data; | 345 | struct sway_seat *seat = e->seat->seat->data; |
349 | if (e->serial == seat->last_button_serial) { | 346 | if (e->serial == seat->last_button_serial) { |
350 | seat_begin_resize_floating(seat, view->swayc, | 347 | seat_begin_resize_floating(seat, view->container, |
351 | seat->last_button, e->edges); | 348 | seat->last_button, e->edges); |
352 | } | 349 | } |
353 | } | 350 | } |
@@ -396,11 +393,14 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
396 | view_map(view, view->wlr_xdg_surface_v6->surface); | 393 | view_map(view, view->wlr_xdg_surface_v6->surface); |
397 | 394 | ||
398 | if (xdg_surface->toplevel->client_pending.fullscreen) { | 395 | if (xdg_surface->toplevel->client_pending.fullscreen) { |
399 | container_set_fullscreen(view->swayc, true); | 396 | container_set_fullscreen(view->container, true); |
400 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 397 | arrange_workspace(view->container->workspace); |
401 | arrange_windows(ws); | ||
402 | } else { | 398 | } else { |
403 | arrange_windows(view->swayc->parent); | 399 | if (view->container->parent) { |
400 | arrange_container(view->container->parent); | ||
401 | } else { | ||
402 | arrange_workspace(view->container->workspace); | ||
403 | } | ||
404 | } | 404 | } |
405 | transaction_commit_dirty(); | 405 | transaction_commit_dirty(); |
406 | 406 | ||
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 94a30239..0d192b76 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -59,8 +59,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) { | |||
59 | wl_container_of(listener, surface, map); | 59 | wl_container_of(listener, surface, map); |
60 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; | 60 | struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; |
61 | 61 | ||
62 | wl_list_insert(root_container.sway_root->xwayland_unmanaged.prev, | 62 | wl_list_insert(root->xwayland_unmanaged.prev, &surface->link); |
63 | &surface->link); | ||
64 | 63 | ||
65 | wl_signal_add(&xsurface->surface->events.commit, &surface->commit); | 64 | wl_signal_add(&xsurface->surface->events.commit, &surface->commit); |
66 | surface->commit.notify = unmanaged_handle_commit; | 65 | surface->commit.notify = unmanaged_handle_commit; |
@@ -90,11 +89,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
90 | if (seat->wlr_seat->keyboard_state.focused_surface == | 89 | if (seat->wlr_seat->keyboard_state.focused_surface == |
91 | xsurface->surface) { | 90 | xsurface->surface) { |
92 | // Restore focus | 91 | // Restore focus |
93 | struct sway_container *previous = | 92 | struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); |
94 | seat_get_focus_inactive(seat, &root_container); | ||
95 | if (previous) { | 93 | if (previous) { |
96 | // Hack to get seat to re-focus the return value of get_focus | 94 | // Hack to get seat to re-focus the return value of get_focus |
97 | seat_set_focus(seat, previous->parent); | 95 | seat_set_focus(seat, NULL); |
98 | seat_set_focus(seat, previous); | 96 | seat_set_focus(seat, previous); |
99 | } | 97 | } |
100 | } | 98 | } |
@@ -299,7 +297,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
299 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 297 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
300 | struct wlr_surface_state *state = &xsurface->surface->current; | 298 | struct wlr_surface_state *state = &xsurface->surface->current; |
301 | 299 | ||
302 | if (view->swayc->instruction) { | 300 | if (view->container->node.instruction) { |
303 | get_geometry(view, &view->geometry); | 301 | get_geometry(view, &view->geometry); |
304 | transaction_notify_view_ready_by_size(view, | 302 | transaction_notify_view_ready_by_size(view, |
305 | state->width, state->height); | 303 | state->width, state->height); |
@@ -308,7 +306,7 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
308 | get_geometry(view, &new_geo); | 306 | get_geometry(view, &new_geo); |
309 | 307 | ||
310 | if ((new_geo.width != view->width || new_geo.height != view->height) && | 308 | if ((new_geo.width != view->width || new_geo.height != view->height) && |
311 | container_is_floating(view->swayc)) { | 309 | container_is_floating(view->container)) { |
312 | // A floating view has unexpectedly sent a new size | 310 | // A floating view has unexpectedly sent a new size |
313 | // eg. The Firefox "Save As" dialog when downloading a file | 311 | // eg. The Firefox "Save As" dialog when downloading a file |
314 | desktop_damage_view(view); | 312 | desktop_damage_view(view); |
@@ -391,11 +389,14 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
391 | view_map(view, xsurface->surface); | 389 | view_map(view, xsurface->surface); |
392 | 390 | ||
393 | if (xsurface->fullscreen) { | 391 | if (xsurface->fullscreen) { |
394 | container_set_fullscreen(view->swayc, true); | 392 | container_set_fullscreen(view->container, true); |
395 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 393 | arrange_workspace(view->container->workspace); |
396 | arrange_windows(ws); | ||
397 | } else { | 394 | } else { |
398 | arrange_windows(view->swayc->parent); | 395 | if (view->container->parent) { |
396 | arrange_container(view->container->parent); | ||
397 | } else { | ||
398 | arrange_workspace(view->container->workspace); | ||
399 | } | ||
399 | } | 400 | } |
400 | transaction_commit_dirty(); | 401 | transaction_commit_dirty(); |
401 | } | 402 | } |
@@ -411,13 +412,14 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { | |||
411 | ev->width, ev->height); | 412 | ev->width, ev->height); |
412 | return; | 413 | return; |
413 | } | 414 | } |
414 | if (container_is_floating(view->swayc)) { | 415 | if (container_is_floating(view->container)) { |
415 | configure(view, view->swayc->current.view_x, | 416 | configure(view, view->container->current.view_x, |
416 | view->swayc->current.view_y, ev->width, ev->height); | 417 | view->container->current.view_y, ev->width, ev->height); |
417 | } else { | 418 | } else { |
418 | configure(view, view->swayc->current.view_x, | 419 | configure(view, view->container->current.view_x, |
419 | view->swayc->current.view_y, view->swayc->current.view_width, | 420 | view->container->current.view_y, |
420 | view->swayc->current.view_height); | 421 | view->container->current.view_width, |
422 | view->container->current.view_height); | ||
421 | } | 423 | } |
422 | } | 424 | } |
423 | 425 | ||
@@ -429,10 +431,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
429 | if (!xsurface->mapped) { | 431 | if (!xsurface->mapped) { |
430 | return; | 432 | return; |
431 | } | 433 | } |
432 | container_set_fullscreen(view->swayc, xsurface->fullscreen); | 434 | container_set_fullscreen(view->container, xsurface->fullscreen); |
433 | 435 | ||
434 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 436 | arrange_workspace(view->container->workspace); |
435 | arrange_windows(output); | ||
436 | transaction_commit_dirty(); | 437 | transaction_commit_dirty(); |
437 | } | 438 | } |
438 | 439 | ||
@@ -444,11 +445,11 @@ static void handle_request_move(struct wl_listener *listener, void *data) { | |||
444 | if (!xsurface->mapped) { | 445 | if (!xsurface->mapped) { |
445 | return; | 446 | return; |
446 | } | 447 | } |
447 | if (!container_is_floating(view->swayc)) { | 448 | if (!container_is_floating(view->container)) { |
448 | return; | 449 | return; |
449 | } | 450 | } |
450 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 451 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
451 | seat_begin_move(seat, view->swayc, seat->last_button); | 452 | seat_begin_move(seat, view->container, seat->last_button); |
452 | } | 453 | } |
453 | 454 | ||
454 | static void handle_request_resize(struct wl_listener *listener, void *data) { | 455 | static void handle_request_resize(struct wl_listener *listener, void *data) { |
@@ -459,12 +460,13 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { | |||
459 | if (!xsurface->mapped) { | 460 | if (!xsurface->mapped) { |
460 | return; | 461 | return; |
461 | } | 462 | } |
462 | if (!container_is_floating(view->swayc)) { | 463 | if (!container_is_floating(view->container)) { |
463 | return; | 464 | return; |
464 | } | 465 | } |
465 | struct wlr_xwayland_resize_event *e = data; | 466 | struct wlr_xwayland_resize_event *e = data; |
466 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 467 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
467 | seat_begin_resize_floating(seat, view->swayc, seat->last_button, e->edges); | 468 | seat_begin_resize_floating(seat, view->container, |
469 | seat->last_button, e->edges); | ||
468 | } | 470 | } |
469 | 471 | ||
470 | static void handle_request_activate(struct wl_listener *listener, void *data) { | 472 | static void handle_request_activate(struct wl_listener *listener, void *data) { |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 00240e84..15993265 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "sway/layers.h" | 20 | #include "sway/layers.h" |
21 | #include "sway/output.h" | 21 | #include "sway/output.h" |
22 | #include "sway/tree/arrange.h" | 22 | #include "sway/tree/arrange.h" |
23 | #include "sway/tree/container.h" | ||
23 | #include "sway/tree/root.h" | 24 | #include "sway/tree/root.h" |
24 | #include "sway/tree/view.h" | 25 | #include "sway/tree/view.h" |
25 | #include "sway/tree/workspace.h" | 26 | #include "sway/tree/workspace.h" |
@@ -50,15 +51,15 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output, | |||
50 | } | 51 | } |
51 | 52 | ||
52 | /** | 53 | /** |
53 | * Returns the container at the cursor's position. If there is a surface at that | 54 | * Returns the node at the cursor's position. If there is a surface at that |
54 | * location, it is stored in **surface (it may not be a view). | 55 | * location, it is stored in **surface (it may not be a view). |
55 | */ | 56 | */ |
56 | static struct sway_container *container_at_coords( | 57 | static struct sway_node *node_at_coords( |
57 | struct sway_seat *seat, double lx, double ly, | 58 | struct sway_seat *seat, double lx, double ly, |
58 | struct wlr_surface **surface, double *sx, double *sy) { | 59 | struct wlr_surface **surface, double *sx, double *sy) { |
59 | // check for unmanaged views first | 60 | // check for unmanaged views first |
60 | #ifdef HAVE_XWAYLAND | 61 | #ifdef HAVE_XWAYLAND |
61 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; | 62 | struct wl_list *unmanaged = &root->xwayland_unmanaged; |
62 | struct sway_xwayland_unmanaged *unmanaged_surface; | 63 | struct sway_xwayland_unmanaged *unmanaged_surface; |
63 | wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { | 64 | wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { |
64 | struct wlr_xwayland_surface *xsurface = | 65 | struct wlr_xwayland_surface *xsurface = |
@@ -75,67 +76,64 @@ static struct sway_container *container_at_coords( | |||
75 | } | 76 | } |
76 | #endif | 77 | #endif |
77 | // find the output the cursor is on | 78 | // find the output the cursor is on |
78 | struct wlr_output_layout *output_layout = | ||
79 | root_container.sway_root->output_layout; | ||
80 | struct wlr_output *wlr_output = wlr_output_layout_output_at( | 79 | struct wlr_output *wlr_output = wlr_output_layout_output_at( |
81 | output_layout, lx, ly); | 80 | root->output_layout, lx, ly); |
82 | if (wlr_output == NULL) { | 81 | if (wlr_output == NULL) { |
83 | return NULL; | 82 | return NULL; |
84 | } | 83 | } |
85 | struct sway_output *output = wlr_output->data; | 84 | struct sway_output *output = wlr_output->data; |
86 | double ox = lx, oy = ly; | 85 | double ox = lx, oy = ly; |
87 | wlr_output_layout_output_coords(output_layout, wlr_output, &ox, &oy); | 86 | wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy); |
88 | 87 | ||
89 | // find the focused workspace on the output for this seat | 88 | // find the focused workspace on the output for this seat |
90 | struct sway_container *ws = seat_get_focus_inactive(seat, output->swayc); | 89 | struct sway_workspace *ws = output_get_active_workspace(output); |
91 | if (ws && ws->type != C_WORKSPACE) { | ||
92 | ws = container_parent(ws, C_WORKSPACE); | ||
93 | } | ||
94 | if (!ws) { | ||
95 | return output->swayc; | ||
96 | } | ||
97 | 90 | ||
98 | if ((*surface = layer_surface_at(output, | 91 | if ((*surface = layer_surface_at(output, |
99 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], | 92 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], |
100 | ox, oy, sx, sy))) { | 93 | ox, oy, sx, sy))) { |
101 | return ws; | 94 | return &ws->node; |
102 | } | 95 | } |
103 | if (ws->sway_workspace->fullscreen) { | 96 | if (ws->fullscreen) { |
104 | return tiling_container_at(ws->sway_workspace->fullscreen, lx, ly, | 97 | struct sway_container *con = |
105 | surface, sx, sy); | 98 | tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); |
99 | if (con) { | ||
100 | return &con->node; | ||
101 | } | ||
102 | return NULL; | ||
106 | } | 103 | } |
107 | if ((*surface = layer_surface_at(output, | 104 | if ((*surface = layer_surface_at(output, |
108 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], | 105 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], |
109 | ox, oy, sx, sy))) { | 106 | ox, oy, sx, sy))) { |
110 | return ws; | 107 | return &ws->node; |
111 | } | 108 | } |
112 | 109 | ||
113 | struct sway_container *c; | 110 | struct sway_container *c; |
114 | if ((c = container_at(ws, lx, ly, surface, sx, sy))) { | 111 | if ((c = container_at(ws, lx, ly, surface, sx, sy))) { |
115 | return c; | 112 | return &c->node; |
116 | } | 113 | } |
117 | 114 | ||
118 | if ((*surface = layer_surface_at(output, | 115 | if ((*surface = layer_surface_at(output, |
119 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], | 116 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], |
120 | ox, oy, sx, sy))) { | 117 | ox, oy, sx, sy))) { |
121 | return ws; | 118 | return &ws->node; |
122 | } | 119 | } |
123 | if ((*surface = layer_surface_at(output, | 120 | if ((*surface = layer_surface_at(output, |
124 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], | 121 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], |
125 | ox, oy, sx, sy))) { | 122 | ox, oy, sx, sy))) { |
126 | return ws; | 123 | return &ws->node; |
127 | } | 124 | } |
128 | 125 | ||
129 | c = seat_get_active_child(seat, output->swayc); | 126 | return &ws->node; |
130 | if (c) { | 127 | } |
131 | return c; | ||
132 | } | ||
133 | if (!c && output->swayc->children->length) { | ||
134 | c = output->swayc->children->items[0]; | ||
135 | return c; | ||
136 | } | ||
137 | 128 | ||
138 | return output->swayc; | 129 | static struct sway_container *container_at_coords(struct sway_seat *seat, |
130 | double lx, double ly, | ||
131 | struct wlr_surface **surface, double *sx, double *sy) { | ||
132 | struct sway_node *node = node_at_coords(seat, lx, ly, surface, sx, sy); | ||
133 | if (node && node->type == N_CONTAINER) { | ||
134 | return node->sway_container; | ||
135 | } | ||
136 | return NULL; | ||
139 | } | 137 | } |
140 | 138 | ||
141 | /** | 139 | /** |
@@ -160,13 +158,14 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { | |||
160 | 158 | ||
161 | // Iterate the parents until we find one with the layout we want, | 159 | // Iterate the parents until we find one with the layout we want, |
162 | // then check if the child has siblings between it and the edge. | 160 | // then check if the child has siblings between it and the edge. |
163 | while (cont->type != C_OUTPUT) { | 161 | while (cont) { |
164 | if (cont->parent->layout == layout) { | 162 | if (container_parent_layout(cont) == layout) { |
165 | int index = list_find(cont->parent->children, cont); | 163 | list_t *siblings = container_get_siblings(cont); |
164 | int index = list_find(siblings, cont); | ||
166 | if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { | 165 | if (index > 0 && (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_TOP)) { |
167 | return false; | 166 | return false; |
168 | } | 167 | } |
169 | if (index < cont->parent->children->length - 1 && | 168 | if (index < siblings->length - 1 && |
170 | (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) { | 169 | (edge == WLR_EDGE_RIGHT || edge == WLR_EDGE_BOTTOM)) { |
171 | return false; | 170 | return false; |
172 | } | 171 | } |
@@ -178,10 +177,10 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { | |||
178 | 177 | ||
179 | static enum wlr_edges find_edge(struct sway_container *cont, | 178 | static enum wlr_edges find_edge(struct sway_container *cont, |
180 | struct sway_cursor *cursor) { | 179 | struct sway_cursor *cursor) { |
181 | if (cont->type != C_VIEW) { | 180 | if (!cont->view) { |
182 | return WLR_EDGE_NONE; | 181 | return WLR_EDGE_NONE; |
183 | } | 182 | } |
184 | struct sway_view *view = cont->sway_view; | 183 | struct sway_view *view = cont->view; |
185 | if (view->border == B_NONE || !view->border_thickness || view->using_csd) { | 184 | if (view->border == B_NONE || !view->border_thickness || view->using_csd) { |
186 | return WLR_EDGE_NONE; | 185 | return WLR_EDGE_NONE; |
187 | } | 186 | } |
@@ -219,7 +218,7 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont, | |||
219 | static void handle_down_motion(struct sway_seat *seat, | 218 | static void handle_down_motion(struct sway_seat *seat, |
220 | struct sway_cursor *cursor, uint32_t time_msec) { | 219 | struct sway_cursor *cursor, uint32_t time_msec) { |
221 | struct sway_container *con = seat->op_container; | 220 | struct sway_container *con = seat->op_container; |
222 | if (seat_is_input_allowed(seat, con->sway_view->surface)) { | 221 | if (seat_is_input_allowed(seat, con->view->surface)) { |
223 | double moved_x = cursor->cursor->x - seat->op_ref_lx; | 222 | double moved_x = cursor->cursor->x - seat->op_ref_lx; |
224 | double moved_y = cursor->cursor->y - seat->op_ref_ly; | 223 | double moved_y = cursor->cursor->y - seat->op_ref_ly; |
225 | double sx = seat->op_ref_con_lx + moved_x; | 224 | double sx = seat->op_ref_con_lx + moved_x; |
@@ -260,8 +259,7 @@ static void calculate_floating_constraints(struct sway_container *con, | |||
260 | if (config->floating_maximum_width == -1) { // no maximum | 259 | if (config->floating_maximum_width == -1) { // no maximum |
261 | *max_width = INT_MAX; | 260 | *max_width = INT_MAX; |
262 | } else if (config->floating_maximum_width == 0) { // automatic | 261 | } else if (config->floating_maximum_width == 0) { // automatic |
263 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 262 | *max_width = con->workspace->width; |
264 | *max_width = ws->width; | ||
265 | } else { | 263 | } else { |
266 | *max_width = config->floating_maximum_width; | 264 | *max_width = config->floating_maximum_width; |
267 | } | 265 | } |
@@ -269,8 +267,7 @@ static void calculate_floating_constraints(struct sway_container *con, | |||
269 | if (config->floating_maximum_height == -1) { // no maximum | 267 | if (config->floating_maximum_height == -1) { // no maximum |
270 | *max_height = INT_MAX; | 268 | *max_height = INT_MAX; |
271 | } else if (config->floating_maximum_height == 0) { // automatic | 269 | } else if (config->floating_maximum_height == 0) { // automatic |
272 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 270 | *max_height = con->workspace->height; |
273 | *max_height = ws->height; | ||
274 | } else { | 271 | } else { |
275 | *max_height = config->floating_maximum_height; | 272 | *max_height = config->floating_maximum_height; |
276 | } | 273 | } |
@@ -314,9 +311,9 @@ static void handle_resize_floating_motion(struct sway_seat *seat, | |||
314 | height = fmax(min_height, fmin(height, max_height)); | 311 | height = fmax(min_height, fmin(height, max_height)); |
315 | 312 | ||
316 | // Apply the view's min/max size | 313 | // Apply the view's min/max size |
317 | if (con->type == C_VIEW) { | 314 | if (con->view) { |
318 | double view_min_width, view_max_width, view_min_height, view_max_height; | 315 | double view_min_width, view_max_width, view_min_height, view_max_height; |
319 | view_get_constraints(con->sway_view, &view_min_width, &view_max_width, | 316 | view_get_constraints(con->view, &view_min_width, &view_max_width, |
320 | &view_min_height, &view_max_height); | 317 | &view_min_height, &view_max_height); |
321 | width = fmax(view_min_width, fmin(width, view_max_width)); | 318 | width = fmax(view_min_width, fmin(width, view_max_width)); |
322 | height = fmax(view_min_height, fmin(height, view_max_height)); | 319 | height = fmax(view_min_height, fmin(height, view_max_height)); |
@@ -357,15 +354,15 @@ static void handle_resize_floating_motion(struct sway_seat *seat, | |||
357 | con->width += relative_grow_width; | 354 | con->width += relative_grow_width; |
358 | con->height += relative_grow_height; | 355 | con->height += relative_grow_height; |
359 | 356 | ||
360 | if (con->type == C_VIEW) { | 357 | if (con->view) { |
361 | struct sway_view *view = con->sway_view; | 358 | struct sway_view *view = con->view; |
362 | view->x += relative_grow_x; | 359 | view->x += relative_grow_x; |
363 | view->y += relative_grow_y; | 360 | view->y += relative_grow_y; |
364 | view->width += relative_grow_width; | 361 | view->width += relative_grow_width; |
365 | view->height += relative_grow_height; | 362 | view->height += relative_grow_height; |
366 | } | 363 | } |
367 | 364 | ||
368 | arrange_windows(con); | 365 | arrange_container(con); |
369 | } | 366 | } |
370 | 367 | ||
371 | static void handle_resize_tiling_motion(struct sway_seat *seat, | 368 | static void handle_resize_tiling_motion(struct sway_seat *seat, |
@@ -435,44 +432,40 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
435 | struct wlr_surface *surface = NULL; | 432 | struct wlr_surface *surface = NULL; |
436 | double sx, sy; | 433 | double sx, sy; |
437 | 434 | ||
438 | // Find the container beneath the pointer's previous position | 435 | // Find the node beneath the pointer's previous position |
439 | struct sway_container *prev_c = container_at_coords(seat, | 436 | struct sway_node *prev_node = node_at_coords(seat, |
440 | cursor->previous.x, cursor->previous.y, &surface, &sx, &sy); | 437 | cursor->previous.x, cursor->previous.y, &surface, &sx, &sy); |
441 | // Update the stored previous position | 438 | // Update the stored previous position |
442 | cursor->previous.x = cursor->cursor->x; | 439 | cursor->previous.x = cursor->cursor->x; |
443 | cursor->previous.y = cursor->cursor->y; | 440 | cursor->previous.y = cursor->cursor->y; |
444 | 441 | ||
445 | struct sway_container *c = container_at_coords(seat, | 442 | struct sway_node *node = node_at_coords(seat, |
446 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | 443 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); |
447 | if (c && config->focus_follows_mouse && allow_refocusing) { | 444 | if (node && config->focus_follows_mouse && allow_refocusing) { |
448 | struct sway_container *focus = seat_get_focus(seat); | 445 | struct sway_node *focus = seat_get_focus(seat); |
449 | if (focus && c->type == C_WORKSPACE) { | 446 | if (focus && node->type == N_WORKSPACE) { |
450 | // Only follow the mouse if it would move to a new output | 447 | // Only follow the mouse if it would move to a new output |
451 | // Otherwise we'll focus the workspace, which is probably wrong | 448 | // Otherwise we'll focus the workspace, which is probably wrong |
452 | if (focus->type != C_OUTPUT) { | 449 | struct sway_output *focused_output = node_get_output(focus); |
453 | focus = container_parent(focus, C_OUTPUT); | 450 | struct sway_output *output = node_get_output(node); |
454 | } | 451 | if (output != focused_output) { |
455 | struct sway_container *output = c; | 452 | seat_set_focus_warp(seat, node, false, true); |
456 | if (output->type != C_OUTPUT) { | ||
457 | output = container_parent(c, C_OUTPUT); | ||
458 | } | ||
459 | if (output != focus) { | ||
460 | seat_set_focus_warp(seat, c, false, true); | ||
461 | } | 453 | } |
462 | } else if (c->type == C_VIEW) { | 454 | } else if (node->type == N_CONTAINER && node->sway_container->view) { |
463 | // Focus c if the following are true: | 455 | // Focus node if the following are true: |
464 | // - cursor is over a new view, i.e. entered a new window; and | 456 | // - cursor is over a new view, i.e. entered a new window; and |
465 | // - the new view is visible, i.e. not hidden in a stack or tab; and | 457 | // - the new view is visible, i.e. not hidden in a stack or tab; and |
466 | // - the seat does not have a keyboard grab | 458 | // - the seat does not have a keyboard grab |
467 | if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && | 459 | if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && |
468 | c != prev_c && | 460 | node != prev_node && |
469 | view_is_visible(c->sway_view)) { | 461 | view_is_visible(node->sway_container->view)) { |
470 | seat_set_focus_warp(seat, c, false, true); | 462 | seat_set_focus_warp(seat, node, false, true); |
471 | } else { | 463 | } else { |
472 | struct sway_container *next_focus = | 464 | struct sway_node *next_focus = |
473 | seat_get_focus_inactive(seat, &root_container); | 465 | seat_get_focus_inactive(seat, &root->node); |
474 | if (next_focus && next_focus->type == C_VIEW && | 466 | if (next_focus && next_focus->type == N_CONTAINER && |
475 | view_is_visible(next_focus->sway_view)) { | 467 | node->sway_container->view && |
468 | view_is_visible(next_focus->sway_container->view)) { | ||
476 | seat_set_focus_warp(seat, next_focus, false, true); | 469 | seat_set_focus_warp(seat, next_focus, false, true); |
477 | } | 470 | } |
478 | } | 471 | } |
@@ -486,12 +479,12 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
486 | if (client != cursor->image_client) { | 479 | if (client != cursor->image_client) { |
487 | cursor_set_image(cursor, "left_ptr", client); | 480 | cursor_set_image(cursor, "left_ptr", client); |
488 | } | 481 | } |
489 | } else if (c) { | 482 | } else if (node && node->type == N_CONTAINER) { |
490 | // Try a container's resize edge | 483 | // Try a node's resize edge |
491 | enum wlr_edges edge = find_resize_edge(c, cursor); | 484 | enum wlr_edges edge = find_resize_edge(node->sway_container, cursor); |
492 | if (edge == WLR_EDGE_NONE) { | 485 | if (edge == WLR_EDGE_NONE) { |
493 | cursor_set_image(cursor, "left_ptr", NULL); | 486 | cursor_set_image(cursor, "left_ptr", NULL); |
494 | } else if (container_is_floating(c)) { | 487 | } else if (container_is_floating(node->sway_container)) { |
495 | cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); | 488 | cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); |
496 | } else { | 489 | } else { |
497 | if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { | 490 | if (edge & (WLR_EDGE_LEFT | WLR_EDGE_RIGHT)) { |
@@ -684,7 +677,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
684 | // Handle tiling resize via border | 677 | // Handle tiling resize via border |
685 | if (resize_edge && button == BTN_LEFT && state == WLR_BUTTON_PRESSED && | 678 | if (resize_edge && button == BTN_LEFT && state == WLR_BUTTON_PRESSED && |
686 | !is_floating) { | 679 | !is_floating) { |
687 | seat_set_focus(seat, cont); | 680 | seat_set_focus(seat, &cont->node); |
688 | seat_begin_resize_tiling(seat, cont, button, edge); | 681 | seat_begin_resize_tiling(seat, cont, button, edge); |
689 | return; | 682 | return; |
690 | } | 683 | } |
@@ -713,7 +706,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
713 | image = "sw-resize"; | 706 | image = "sw-resize"; |
714 | } | 707 | } |
715 | cursor_set_image(seat->cursor, image, NULL); | 708 | cursor_set_image(seat->cursor, image, NULL); |
716 | seat_set_focus(seat, cont); | 709 | seat_set_focus(seat, &cont->node); |
717 | seat_begin_resize_tiling(seat, cont, button, edge); | 710 | seat_begin_resize_tiling(seat, cont, button, edge); |
718 | return; | 711 | return; |
719 | } | 712 | } |
@@ -725,7 +718,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
725 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; | 718 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; |
726 | if (button == btn_move && state == WLR_BUTTON_PRESSED && | 719 | if (button == btn_move && state == WLR_BUTTON_PRESSED && |
727 | (mod_pressed || on_titlebar)) { | 720 | (mod_pressed || on_titlebar)) { |
728 | while (cont->parent->type != C_WORKSPACE) { | 721 | while (cont->parent) { |
729 | cont = cont->parent; | 722 | cont = cont->parent; |
730 | } | 723 | } |
731 | seat_begin_move(seat, cont, button); | 724 | seat_begin_move(seat, cont, button); |
@@ -747,7 +740,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
747 | BTN_LEFT : BTN_RIGHT; | 740 | BTN_LEFT : BTN_RIGHT; |
748 | if (mod_pressed && button == btn_resize) { | 741 | if (mod_pressed && button == btn_resize) { |
749 | struct sway_container *floater = cont; | 742 | struct sway_container *floater = cont; |
750 | while (floater->parent->type != C_WORKSPACE) { | 743 | while (floater->parent) { |
751 | floater = floater->parent; | 744 | floater = floater->parent; |
752 | } | 745 | } |
753 | edge = 0; | 746 | edge = 0; |
@@ -762,7 +755,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
762 | 755 | ||
763 | // Handle mousedown on a container surface | 756 | // Handle mousedown on a container surface |
764 | if (surface && cont && state == WLR_BUTTON_PRESSED) { | 757 | if (surface && cont && state == WLR_BUTTON_PRESSED) { |
765 | seat_set_focus(seat, cont); | 758 | seat_set_focus(seat, &cont->node); |
766 | seat_pointer_notify_button(seat, time_msec, button, state); | 759 | seat_pointer_notify_button(seat, time_msec, button, state); |
767 | seat_begin_down(seat, cont, button, sx, sy); | 760 | seat_begin_down(seat, cont, button, sx, sy); |
768 | return; | 761 | return; |
@@ -770,7 +763,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
770 | 763 | ||
771 | // Handle clicking a container surface | 764 | // Handle clicking a container surface |
772 | if (cont) { | 765 | if (cont) { |
773 | seat_set_focus(seat, cont); | 766 | seat_set_focus(seat, &cont->node); |
774 | seat_pointer_notify_button(seat, time_msec, button, state); | 767 | seat_pointer_notify_button(seat, time_msec, button, state); |
775 | return; | 768 | return; |
776 | } | 769 | } |
@@ -1025,8 +1018,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { | |||
1025 | cursor->previous.y = wlr_cursor->y; | 1018 | cursor->previous.y = wlr_cursor->y; |
1026 | 1019 | ||
1027 | cursor->seat = seat; | 1020 | cursor->seat = seat; |
1028 | wlr_cursor_attach_output_layout(wlr_cursor, | 1021 | wlr_cursor_attach_output_layout(wlr_cursor, root->output_layout); |
1029 | root_container.sway_root->output_layout); | ||
1030 | 1022 | ||
1031 | // input events | 1023 | // input events |
1032 | wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); | 1024 | wl_signal_add(&wlr_cursor->events.motion, &cursor->motion); |
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index c820e032..b4352c6a 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c | |||
@@ -293,12 +293,10 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data) | |||
293 | struct sway_seat *seat; | 293 | struct sway_seat *seat; |
294 | wl_list_for_each(seat, &input_manager->seats, link) { | 294 | wl_list_for_each(seat, &input_manager->seats, link) { |
295 | seat_set_exclusive_client(seat, NULL); | 295 | seat_set_exclusive_client(seat, NULL); |
296 | struct sway_container *previous = seat_get_focus(seat); | 296 | struct sway_node *previous = seat_get_focus(seat); |
297 | if (previous) { | 297 | if (previous) { |
298 | wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, | ||
299 | container_type_to_str(previous->type), previous->name); | ||
300 | // Hack to get seat to re-focus the return value of get_focus | 298 | // Hack to get seat to re-focus the return value of get_focus |
301 | seat_set_focus(seat, previous->parent); | 299 | seat_set_focus(seat, NULL); |
302 | seat_set_focus(seat, previous); | 300 | seat_set_focus(seat, previous); |
303 | } | 301 | } |
304 | } | 302 | } |
@@ -369,10 +367,10 @@ struct sway_input_manager *input_manager_create( | |||
369 | } | 367 | } |
370 | 368 | ||
371 | bool input_manager_has_focus(struct sway_input_manager *input, | 369 | bool input_manager_has_focus(struct sway_input_manager *input, |
372 | struct sway_container *container) { | 370 | struct sway_node *node) { |
373 | struct sway_seat *seat = NULL; | 371 | struct sway_seat *seat = NULL; |
374 | wl_list_for_each(seat, &input->seats, link) { | 372 | wl_list_for_each(seat, &input->seats, link) { |
375 | if (seat_get_focus(seat) == container) { | 373 | if (seat_get_focus(seat) == node) { |
376 | return true; | 374 | return true; |
377 | } | 375 | } |
378 | } | 376 | } |
@@ -381,10 +379,10 @@ bool input_manager_has_focus(struct sway_input_manager *input, | |||
381 | } | 379 | } |
382 | 380 | ||
383 | void input_manager_set_focus(struct sway_input_manager *input, | 381 | void input_manager_set_focus(struct sway_input_manager *input, |
384 | struct sway_container *container) { | 382 | struct sway_node *node) { |
385 | struct sway_seat *seat; | 383 | struct sway_seat *seat; |
386 | wl_list_for_each(seat, &input->seats, link) { | 384 | wl_list_for_each(seat, &input->seats, link) { |
387 | seat_set_focus(seat, container); | 385 | seat_set_focus(seat, node); |
388 | } | 386 | } |
389 | } | 387 | } |
390 | 388 | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 4b7c7893..2f7a3318 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -47,48 +47,36 @@ void seat_destroy(struct sway_seat *seat) { | |||
47 | seat_device_destroy(seat_device); | 47 | seat_device_destroy(seat_device); |
48 | } | 48 | } |
49 | sway_cursor_destroy(seat->cursor); | 49 | sway_cursor_destroy(seat->cursor); |
50 | wl_list_remove(&seat->new_container.link); | 50 | wl_list_remove(&seat->new_node.link); |
51 | wl_list_remove(&seat->new_drag_icon.link); | 51 | wl_list_remove(&seat->new_drag_icon.link); |
52 | wl_list_remove(&seat->link); | 52 | wl_list_remove(&seat->link); |
53 | wlr_seat_destroy(seat->wlr_seat); | 53 | wlr_seat_destroy(seat->wlr_seat); |
54 | } | 54 | } |
55 | 55 | ||
56 | static struct sway_seat_container *seat_container_from_container( | 56 | static struct sway_seat_node *seat_node_from_node( |
57 | struct sway_seat *seat, struct sway_container *con); | 57 | struct sway_seat *seat, struct sway_node *node); |
58 | 58 | ||
59 | static void seat_container_destroy(struct sway_seat_container *seat_con) { | 59 | static void seat_node_destroy(struct sway_seat_node *seat_node) { |
60 | struct sway_container *con = seat_con->container; | 60 | wl_list_remove(&seat_node->destroy.link); |
61 | struct sway_container *child = NULL; | 61 | wl_list_remove(&seat_node->link); |
62 | 62 | free(seat_node); | |
63 | if (con->children != NULL) { | ||
64 | for (int i = 0; i < con->children->length; ++i) { | ||
65 | child = con->children->items[i]; | ||
66 | struct sway_seat_container *seat_child = | ||
67 | seat_container_from_container(seat_con->seat, child); | ||
68 | seat_container_destroy(seat_child); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | wl_list_remove(&seat_con->destroy.link); | ||
73 | wl_list_remove(&seat_con->link); | ||
74 | free(seat_con); | ||
75 | } | 63 | } |
76 | 64 | ||
77 | /** | 65 | /** |
78 | * Activate all views within this container recursively. | 66 | * Activate all views within this container recursively. |
79 | */ | 67 | */ |
80 | static void seat_send_activate(struct sway_container *con, | 68 | static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) { |
81 | struct sway_seat *seat) { | 69 | if (node_is_view(node)) { |
82 | if (con->type == C_VIEW) { | 70 | if (!seat_is_input_allowed(seat, node->sway_container->view->surface)) { |
83 | if (!seat_is_input_allowed(seat, con->sway_view->surface)) { | ||
84 | wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited"); | 71 | wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited"); |
85 | return; | 72 | return; |
86 | } | 73 | } |
87 | view_set_activated(con->sway_view, true); | 74 | view_set_activated(node->sway_container->view, true); |
88 | } else { | 75 | } else { |
89 | for (int i = 0; i < con->children->length; ++i) { | 76 | list_t *children = node_get_children(node); |
90 | struct sway_container *child = con->children->items[i]; | 77 | for (int i = 0; i < children->length; ++i) { |
91 | seat_send_activate(child, seat); | 78 | struct sway_container *child = children->items[i]; |
79 | seat_send_activate(&child->node, seat); | ||
92 | } | 80 | } |
93 | } | 81 | } |
94 | } | 82 | } |
@@ -98,14 +86,15 @@ static void seat_send_activate(struct sway_container *con, | |||
98 | * If con is a container, set all child views as active and don't enable | 86 | * If con is a container, set all child views as active and don't enable |
99 | * keyboard input on any. | 87 | * keyboard input on any. |
100 | */ | 88 | */ |
101 | static void seat_send_focus(struct sway_container *con, | 89 | static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) { |
102 | struct sway_seat *seat) { | 90 | seat_send_activate(node, seat); |
103 | seat_send_activate(con, seat); | ||
104 | 91 | ||
105 | if (con->type == C_VIEW | 92 | struct sway_view *view = node->type == N_CONTAINER ? |
106 | && seat_is_input_allowed(seat, con->sway_view->surface)) { | 93 | node->sway_container->view : NULL; |
94 | |||
95 | if (view && seat_is_input_allowed(seat, view->surface)) { | ||
107 | #ifdef HAVE_XWAYLAND | 96 | #ifdef HAVE_XWAYLAND |
108 | if (con->sway_view->type == SWAY_VIEW_XWAYLAND) { | 97 | if (view->type == SWAY_VIEW_XWAYLAND) { |
109 | struct wlr_xwayland *xwayland = | 98 | struct wlr_xwayland *xwayland = |
110 | seat->input->server->xwayland.wlr_xwayland; | 99 | seat->input->server->xwayland.wlr_xwayland; |
111 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 100 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
@@ -114,71 +103,67 @@ static void seat_send_focus(struct sway_container *con, | |||
114 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); | 103 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); |
115 | if (keyboard) { | 104 | if (keyboard) { |
116 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | 105 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, |
117 | con->sway_view->surface, keyboard->keycodes, | 106 | view->surface, keyboard->keycodes, |
118 | keyboard->num_keycodes, &keyboard->modifiers); | 107 | keyboard->num_keycodes, &keyboard->modifiers); |
119 | } else { | 108 | } else { |
120 | wlr_seat_keyboard_notify_enter( | 109 | wlr_seat_keyboard_notify_enter( |
121 | seat->wlr_seat, con->sway_view->surface, NULL, 0, NULL); | 110 | seat->wlr_seat, view->surface, NULL, 0, NULL); |
122 | } | 111 | } |
123 | } | 112 | } |
124 | } | 113 | } |
125 | 114 | ||
126 | void seat_focus_inactive_children_for_each(struct sway_seat *seat, | 115 | void seat_for_each_node(struct sway_seat *seat, |
127 | struct sway_container *container, | 116 | void (*f)(struct sway_node *node, void *data), void *data) { |
128 | void (*f)(struct sway_container *container, void *data), void *data) { | 117 | struct sway_seat_node *current = NULL; |
129 | struct sway_seat_container *current = NULL; | ||
130 | wl_list_for_each(current, &seat->focus_stack, link) { | 118 | wl_list_for_each(current, &seat->focus_stack, link) { |
131 | if (current->container->parent == NULL) { | 119 | f(current->node, data); |
132 | continue; | ||
133 | } | ||
134 | if (current->container->parent == container) { | ||
135 | f(current->container, data); | ||
136 | } | ||
137 | } | 120 | } |
138 | } | 121 | } |
139 | 122 | ||
140 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, | 123 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, |
141 | struct sway_container *ancestor) { | 124 | struct sway_node *ancestor) { |
142 | if (ancestor->type == C_VIEW) { | 125 | if (ancestor->type == N_CONTAINER && ancestor->sway_container->view) { |
143 | return ancestor; | 126 | return ancestor->sway_container; |
144 | } | 127 | } |
145 | struct sway_seat_container *current; | 128 | struct sway_seat_node *current; |
146 | wl_list_for_each(current, &seat->focus_stack, link) { | 129 | wl_list_for_each(current, &seat->focus_stack, link) { |
147 | struct sway_container *con = current->container; | 130 | struct sway_node *node = current->node; |
148 | if (con->type == C_VIEW && container_has_ancestor(con, ancestor)) { | 131 | if (node->type == N_CONTAINER && node->sway_container->view && |
149 | return con; | 132 | node_has_ancestor(node, ancestor)) { |
133 | return node->sway_container; | ||
150 | } | 134 | } |
151 | } | 135 | } |
152 | return NULL; | 136 | return NULL; |
153 | } | 137 | } |
154 | 138 | ||
155 | static void handle_seat_container_destroy(struct wl_listener *listener, | 139 | static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { |
156 | void *data) { | 140 | struct sway_seat_node *seat_node = |
157 | struct sway_seat_container *seat_con = | 141 | wl_container_of(listener, seat_node, destroy); |
158 | wl_container_of(listener, seat_con, destroy); | 142 | struct sway_seat *seat = seat_node->seat; |
159 | struct sway_seat *seat = seat_con->seat; | 143 | struct sway_node *node = seat_node->node; |
160 | struct sway_container *con = seat_con->container; | 144 | struct sway_node *parent = node_get_parent(node); |
161 | struct sway_container *parent = con->parent; | 145 | struct sway_node *focus = seat_get_focus(seat); |
162 | struct sway_container *focus = seat_get_focus(seat); | ||
163 | 146 | ||
164 | bool set_focus = | 147 | bool set_focus = |
165 | focus != NULL && | 148 | focus != NULL && |
166 | (focus == con || container_has_ancestor(focus, con)) && | 149 | (focus == node || node_has_ancestor(focus, node)) && |
167 | con->type != C_WORKSPACE; | 150 | node->type == N_CONTAINER; |
168 | 151 | ||
169 | seat_container_destroy(seat_con); | 152 | seat_node_destroy(seat_node); |
170 | 153 | ||
171 | if (set_focus) { | 154 | if (set_focus) { |
172 | struct sway_container *next_focus = NULL; | 155 | struct sway_node *next_focus = NULL; |
173 | while (next_focus == NULL) { | 156 | while (next_focus == NULL) { |
174 | next_focus = seat_get_focus_inactive_view(seat, parent); | 157 | struct sway_container *con = |
158 | seat_get_focus_inactive_view(seat, parent); | ||
159 | next_focus = con ? &con->node : NULL; | ||
175 | 160 | ||
176 | if (next_focus == NULL && parent->type == C_WORKSPACE) { | 161 | if (next_focus == NULL && parent->type == N_WORKSPACE) { |
177 | next_focus = parent; | 162 | next_focus = parent; |
178 | break; | 163 | break; |
179 | } | 164 | } |
180 | 165 | ||
181 | parent = parent->parent; | 166 | parent = node_get_parent(parent); |
182 | } | 167 | } |
183 | 168 | ||
184 | // the structure change might have caused it to move up to the top of | 169 | // the structure change might have caused it to move up to the top of |
@@ -191,39 +176,39 @@ static void handle_seat_container_destroy(struct wl_listener *listener, | |||
191 | } | 176 | } |
192 | } | 177 | } |
193 | 178 | ||
194 | static struct sway_seat_container *seat_container_from_container( | 179 | static struct sway_seat_node *seat_node_from_node( |
195 | struct sway_seat *seat, struct sway_container *con) { | 180 | struct sway_seat *seat, struct sway_node *node) { |
196 | if (con->type == C_ROOT || con->type == C_OUTPUT) { | 181 | if (node->type == N_ROOT || node->type == N_OUTPUT) { |
197 | // these don't get seat containers ever | 182 | // these don't get seat nodes ever |
198 | return NULL; | 183 | return NULL; |
199 | } | 184 | } |
200 | 185 | ||
201 | struct sway_seat_container *seat_con = NULL; | 186 | struct sway_seat_node *seat_node = NULL; |
202 | wl_list_for_each(seat_con, &seat->focus_stack, link) { | 187 | wl_list_for_each(seat_node, &seat->focus_stack, link) { |
203 | if (seat_con->container == con) { | 188 | if (seat_node->node == node) { |
204 | return seat_con; | 189 | return seat_node; |
205 | } | 190 | } |
206 | } | 191 | } |
207 | 192 | ||
208 | seat_con = calloc(1, sizeof(struct sway_seat_container)); | 193 | seat_node = calloc(1, sizeof(struct sway_seat_node)); |
209 | if (seat_con == NULL) { | 194 | if (seat_node == NULL) { |
210 | wlr_log(WLR_ERROR, "could not allocate seat container"); | 195 | wlr_log(WLR_ERROR, "could not allocate seat node"); |
211 | return NULL; | 196 | return NULL; |
212 | } | 197 | } |
213 | 198 | ||
214 | seat_con->container = con; | 199 | seat_node->node = node; |
215 | seat_con->seat = seat; | 200 | seat_node->seat = seat; |
216 | wl_list_insert(seat->focus_stack.prev, &seat_con->link); | 201 | wl_list_insert(seat->focus_stack.prev, &seat_node->link); |
217 | wl_signal_add(&con->events.destroy, &seat_con->destroy); | 202 | wl_signal_add(&node->events.destroy, &seat_node->destroy); |
218 | seat_con->destroy.notify = handle_seat_container_destroy; | 203 | seat_node->destroy.notify = handle_seat_node_destroy; |
219 | 204 | ||
220 | return seat_con; | 205 | return seat_node; |
221 | } | 206 | } |
222 | 207 | ||
223 | static void handle_new_container(struct wl_listener *listener, void *data) { | 208 | static void handle_new_node(struct wl_listener *listener, void *data) { |
224 | struct sway_seat *seat = wl_container_of(listener, seat, new_container); | 209 | struct sway_seat *seat = wl_container_of(listener, seat, new_node); |
225 | struct sway_container *con = data; | 210 | struct sway_node *node = data; |
226 | seat_container_from_container(seat, con); | 211 | seat_node_from_node(seat, node); |
227 | } | 212 | } |
228 | 213 | ||
229 | static void drag_icon_damage_whole(struct sway_drag_icon *icon) { | 214 | static void drag_icon_damage_whole(struct sway_drag_icon *icon) { |
@@ -272,8 +257,7 @@ static void drag_icon_handle_unmap(struct wl_listener *listener, void *data) { | |||
272 | drag_icon_damage_whole(icon); | 257 | drag_icon_damage_whole(icon); |
273 | } | 258 | } |
274 | 259 | ||
275 | static void drag_icon_handle_destroy(struct wl_listener *listener, | 260 | static void drag_icon_handle_destroy(struct wl_listener *listener, void *data) { |
276 | void *data) { | ||
277 | struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy); | 261 | struct sway_drag_icon *icon = wl_container_of(listener, icon, destroy); |
278 | icon->wlr_drag_icon->data = NULL; | 262 | icon->wlr_drag_icon->data = NULL; |
279 | wl_list_remove(&icon->link); | 263 | wl_list_remove(&icon->link); |
@@ -305,20 +289,29 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) { | |||
305 | icon->destroy.notify = drag_icon_handle_destroy; | 289 | icon->destroy.notify = drag_icon_handle_destroy; |
306 | wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); | 290 | wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); |
307 | 291 | ||
308 | wl_list_insert(&root_container.sway_root->drag_icons, &icon->link); | 292 | wl_list_insert(&root->drag_icons, &icon->link); |
309 | 293 | ||
310 | drag_icon_update_position(icon); | 294 | drag_icon_update_position(icon); |
311 | } | 295 | } |
312 | 296 | ||
313 | static void collect_focus_iter(struct sway_container *con, void *data) { | 297 | static void collect_focus_iter(struct sway_node *node, void *data) { |
314 | struct sway_seat *seat = data; | 298 | struct sway_seat *seat = data; |
315 | struct sway_seat_container *seat_con = | 299 | struct sway_seat_node *seat_node = seat_node_from_node(seat, node); |
316 | seat_container_from_container(seat, con); | 300 | if (!seat_node) { |
317 | if (!seat_con) { | ||
318 | return; | 301 | return; |
319 | } | 302 | } |
320 | wl_list_remove(&seat_con->link); | 303 | wl_list_remove(&seat_node->link); |
321 | wl_list_insert(&seat->focus_stack, &seat_con->link); | 304 | wl_list_insert(&seat->focus_stack, &seat_node->link); |
305 | } | ||
306 | |||
307 | static void collect_focus_workspace_iter(struct sway_workspace *workspace, | ||
308 | void *data) { | ||
309 | collect_focus_iter(&workspace->node, data); | ||
310 | } | ||
311 | |||
312 | static void collect_focus_container_iter(struct sway_container *container, | ||
313 | void *data) { | ||
314 | collect_focus_iter(&container->node, data); | ||
322 | } | 315 | } |
323 | 316 | ||
324 | struct sway_seat *seat_create(struct sway_input_manager *input, | 317 | struct sway_seat *seat_create(struct sway_input_manager *input, |
@@ -345,12 +338,11 @@ struct sway_seat *seat_create(struct sway_input_manager *input, | |||
345 | // init the focus stack | 338 | // init the focus stack |
346 | wl_list_init(&seat->focus_stack); | 339 | wl_list_init(&seat->focus_stack); |
347 | 340 | ||
348 | root_for_each_workspace(collect_focus_iter, seat); | 341 | root_for_each_workspace(collect_focus_workspace_iter, seat); |
349 | root_for_each_container(collect_focus_iter, seat); | 342 | root_for_each_container(collect_focus_container_iter, seat); |
350 | 343 | ||
351 | wl_signal_add(&root_container.sway_root->events.new_container, | 344 | wl_signal_add(&root->events.new_node, &seat->new_node); |
352 | &seat->new_container); | 345 | seat->new_node.notify = handle_new_node; |
353 | seat->new_container.notify = handle_new_container; | ||
354 | 346 | ||
355 | wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon); | 347 | wl_signal_add(&seat->wlr_seat->events.new_drag_icon, &seat->new_drag_icon); |
356 | seat->new_drag_icon.notify = handle_new_drag_icon; | 348 | seat->new_drag_icon.notify = handle_new_drag_icon; |
@@ -388,19 +380,11 @@ static void seat_apply_input_config(struct sway_seat *seat, | |||
388 | if (mapped_to_output != NULL) { | 380 | if (mapped_to_output != NULL) { |
389 | wlr_log(WLR_DEBUG, "Mapping input device %s to output %s", | 381 | wlr_log(WLR_DEBUG, "Mapping input device %s to output %s", |
390 | sway_device->input_device->identifier, mapped_to_output); | 382 | sway_device->input_device->identifier, mapped_to_output); |
391 | struct sway_container *output = NULL; | 383 | struct sway_output *output = output_by_name(mapped_to_output); |
392 | for (int i = 0; i < root_container.children->length; ++i) { | ||
393 | struct sway_container *_output = root_container.children->items[i]; | ||
394 | if (strcasecmp(_output->name, mapped_to_output) == 0) { | ||
395 | output = _output; | ||
396 | break; | ||
397 | } | ||
398 | } | ||
399 | if (output) { | 384 | if (output) { |
400 | wlr_cursor_map_input_to_output(seat->cursor->cursor, | 385 | wlr_cursor_map_input_to_output(seat->cursor->cursor, |
401 | sway_device->input_device->wlr_device, | 386 | sway_device->input_device->wlr_device, output->wlr_output); |
402 | output->sway_output->wlr_output); | 387 | wlr_log(WLR_DEBUG, "Mapped to output %s", output->wlr_output->name); |
403 | wlr_log(WLR_DEBUG, "Mapped to output %s", output->name); | ||
404 | } | 388 | } |
405 | } | 389 | } |
406 | } | 390 | } |
@@ -423,12 +407,12 @@ static void seat_configure_keyboard(struct sway_seat *seat, | |||
423 | sway_keyboard_configure(seat_device->keyboard); | 407 | sway_keyboard_configure(seat_device->keyboard); |
424 | wlr_seat_set_keyboard(seat->wlr_seat, | 408 | wlr_seat_set_keyboard(seat->wlr_seat, |
425 | seat_device->input_device->wlr_device); | 409 | seat_device->input_device->wlr_device); |
426 | struct sway_container *focus = seat_get_focus(seat); | 410 | struct sway_node *focus = seat_get_focus(seat); |
427 | if (focus && focus->type == C_VIEW) { | 411 | if (focus && node_is_view(focus)) { |
428 | // force notify reenter to pick up the new configuration | 412 | // force notify reenter to pick up the new configuration |
429 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); | 413 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); |
430 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, | 414 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, |
431 | focus->sway_view->surface, wlr_keyboard->keycodes, | 415 | focus->sway_container->view->surface, wlr_keyboard->keycodes, |
432 | wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); | 416 | wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers); |
433 | } | 417 | } |
434 | } | 418 | } |
@@ -461,8 +445,7 @@ static struct sway_seat_device *seat_get_device(struct sway_seat *seat, | |||
461 | 445 | ||
462 | void seat_configure_device(struct sway_seat *seat, | 446 | void seat_configure_device(struct sway_seat *seat, |
463 | struct sway_input_device *input_device) { | 447 | struct sway_input_device *input_device) { |
464 | struct sway_seat_device *seat_device = | 448 | struct sway_seat_device *seat_device = seat_get_device(seat, input_device); |
465 | seat_get_device(seat, input_device); | ||
466 | if (!seat_device) { | 449 | if (!seat_device) { |
467 | return; | 450 | return; |
468 | } | 451 | } |
@@ -512,8 +495,7 @@ void seat_add_device(struct sway_seat *seat, | |||
512 | 495 | ||
513 | void seat_remove_device(struct sway_seat *seat, | 496 | void seat_remove_device(struct sway_seat *seat, |
514 | struct sway_input_device *input_device) { | 497 | struct sway_input_device *input_device) { |
515 | struct sway_seat_device *seat_device = | 498 | struct sway_seat_device *seat_device = seat_get_device(seat, input_device); |
516 | seat_get_device(seat, input_device); | ||
517 | 499 | ||
518 | if (!seat_device) { | 500 | if (!seat_device) { |
519 | return; | 501 | return; |
@@ -539,11 +521,9 @@ void seat_configure_xcursor(struct sway_seat *seat) { | |||
539 | } | 521 | } |
540 | } | 522 | } |
541 | 523 | ||
542 | for (int i = 0; i < root_container.children->length; ++i) { | 524 | for (int i = 0; i < root->outputs->length; ++i) { |
543 | struct sway_container *output_container = | 525 | struct sway_output *sway_output = root->outputs->items[i]; |
544 | root_container.children->items[i]; | 526 | struct wlr_output *output = sway_output->wlr_output; |
545 | struct wlr_output *output = | ||
546 | output_container->sway_output->wlr_output; | ||
547 | bool result = | 527 | bool result = |
548 | wlr_xcursor_manager_load(seat->cursor->xcursor_manager, | 528 | wlr_xcursor_manager_load(seat->cursor->xcursor_manager, |
549 | output->scale); | 529 | output->scale); |
@@ -566,17 +546,20 @@ bool seat_is_input_allowed(struct sway_seat *seat, | |||
566 | return !seat->exclusive_client || seat->exclusive_client == client; | 546 | return !seat->exclusive_client || seat->exclusive_client == client; |
567 | } | 547 | } |
568 | 548 | ||
549 | static void send_unfocus(struct sway_container *con, void *data) { | ||
550 | if (con->view) { | ||
551 | view_set_activated(con->view, false); | ||
552 | } | ||
553 | } | ||
554 | |||
569 | // Unfocus the container and any children (eg. when leaving `focus parent`) | 555 | // Unfocus the container and any children (eg. when leaving `focus parent`) |
570 | static void seat_send_unfocus(struct sway_container *container, | 556 | static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) { |
571 | struct sway_seat *seat) { | 557 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); |
572 | if (container->type == C_VIEW) { | 558 | if (node->type == N_WORKSPACE) { |
573 | wlr_seat_keyboard_clear_focus(seat->wlr_seat); | 559 | workspace_for_each_container(node->sway_workspace, send_unfocus, seat); |
574 | view_set_activated(container->sway_view, false); | ||
575 | } else { | 560 | } else { |
576 | for (int i = 0; i < container->children->length; ++i) { | 561 | send_unfocus(node->sway_container, seat); |
577 | struct sway_container *child = container->children->items[i]; | 562 | container_for_each_child(node->sway_container, send_unfocus, seat); |
578 | seat_send_unfocus(child, seat); | ||
579 | } | ||
580 | } | 563 | } |
581 | } | 564 | } |
582 | 565 | ||
@@ -586,26 +569,23 @@ static int handle_urgent_timeout(void *data) { | |||
586 | return 0; | 569 | return 0; |
587 | } | 570 | } |
588 | 571 | ||
589 | void seat_set_focus_warp(struct sway_seat *seat, | 572 | void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, |
590 | struct sway_container *container, bool warp, bool notify) { | 573 | bool warp, bool notify) { |
591 | if (seat->focused_layer) { | 574 | if (seat->focused_layer) { |
592 | return; | 575 | return; |
593 | } | 576 | } |
594 | 577 | ||
595 | struct sway_container *last_focus = seat_get_focus(seat); | 578 | struct sway_node *last_focus = seat_get_focus(seat); |
596 | if (last_focus == container) { | 579 | if (last_focus == node) { |
597 | return; | 580 | return; |
598 | } | 581 | } |
599 | 582 | ||
600 | struct sway_container *last_workspace = last_focus; | 583 | struct sway_workspace *last_workspace = seat_get_focused_workspace(seat); |
601 | if (last_workspace && last_workspace->type != C_WORKSPACE) { | ||
602 | last_workspace = container_parent(last_workspace, C_WORKSPACE); | ||
603 | } | ||
604 | 584 | ||
605 | if (container == NULL) { | 585 | if (node == NULL) { |
606 | // Close any popups on the old focus | 586 | // Close any popups on the old focus |
607 | if (last_focus->type == C_VIEW) { | 587 | if (node_is_view(last_focus)) { |
608 | view_close_popups(last_focus->sway_view); | 588 | view_close_popups(last_focus->sway_container->view); |
609 | } | 589 | } |
610 | seat_send_unfocus(last_focus, seat); | 590 | seat_send_unfocus(last_focus, seat); |
611 | seat->has_focus = false; | 591 | seat->has_focus = false; |
@@ -613,69 +593,70 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
613 | return; | 593 | return; |
614 | } | 594 | } |
615 | 595 | ||
616 | struct sway_container *new_workspace = container; | 596 | struct sway_workspace *new_workspace = node->type == N_WORKSPACE ? |
617 | if (new_workspace->type != C_WORKSPACE) { | 597 | node->sway_workspace : node->sway_container->workspace; |
618 | new_workspace = container_parent(new_workspace, C_WORKSPACE); | 598 | struct sway_container *container = node->type == N_CONTAINER ? |
619 | } | 599 | node->sway_container : NULL; |
620 | 600 | ||
621 | if (last_workspace == new_workspace | 601 | // Deny setting focus to a view which is hidden by a fullscreen container |
622 | && last_workspace->sway_workspace->fullscreen | 602 | if (new_workspace && new_workspace->fullscreen && container && |
623 | && !container_is_fullscreen_or_child(container)) { | 603 | !container_is_fullscreen_or_child(container)) { |
624 | return; | 604 | return; |
625 | } | 605 | } |
626 | 606 | ||
627 | struct sway_container *last_output = last_focus; | 607 | struct sway_output *last_output = last_workspace ? |
628 | if (last_output && last_output->type != C_OUTPUT) { | 608 | last_workspace->output : NULL; |
629 | last_output = container_parent(last_output, C_OUTPUT); | 609 | struct sway_output *new_output = new_workspace->output; |
630 | } | ||
631 | struct sway_container *new_output = container; | ||
632 | if (new_output->type != C_OUTPUT) { | ||
633 | new_output = container_parent(new_output, C_OUTPUT); | ||
634 | } | ||
635 | 610 | ||
636 | // find new output's old workspace, which might have to be removed if empty | 611 | // find new output's old workspace, which might have to be removed if empty |
637 | struct sway_container *new_output_last_ws = NULL; | 612 | struct sway_workspace *new_output_last_ws = NULL; |
638 | if (new_output && last_output != new_output) { | 613 | if (new_output && last_output != new_output) { |
639 | new_output_last_ws = seat_get_active_child(seat, new_output); | 614 | new_output_last_ws = output_get_active_workspace(new_output); |
640 | } | 615 | } |
641 | 616 | ||
642 | if (container->parent) { | 617 | // Put the container parents on the focus stack, then the workspace, then |
643 | struct sway_seat_container *seat_con = | 618 | // the focused container. |
644 | seat_container_from_container(seat, container); | 619 | if (container) { |
645 | if (seat_con == NULL) { | 620 | struct sway_container *parent = container->parent; |
646 | return; | ||
647 | } | ||
648 | |||
649 | // put all the ancestors of this container on top of the focus stack | ||
650 | struct sway_seat_container *parent = | ||
651 | seat_container_from_container(seat, container->parent); | ||
652 | while (parent) { | 621 | while (parent) { |
653 | wl_list_remove(&parent->link); | 622 | struct sway_seat_node *seat_node = |
654 | wl_list_insert(&seat->focus_stack, &parent->link); | 623 | seat_node_from_node(seat, &parent->node); |
655 | container_set_dirty(parent->container); | 624 | wl_list_remove(&seat_node->link); |
656 | 625 | wl_list_insert(&seat->focus_stack, &seat_node->link); | |
657 | parent = seat_container_from_container(seat, | 626 | node_set_dirty(&parent->node); |
658 | parent->container->parent); | 627 | parent = parent->parent; |
659 | } | 628 | } |
660 | 629 | } | |
661 | wl_list_remove(&seat_con->link); | 630 | if (new_workspace) { |
662 | wl_list_insert(&seat->focus_stack, &seat_con->link); | 631 | struct sway_seat_node *seat_node = |
632 | seat_node_from_node(seat, &new_workspace->node); | ||
633 | wl_list_remove(&seat_node->link); | ||
634 | wl_list_insert(&seat->focus_stack, &seat_node->link); | ||
635 | node_set_dirty(&new_workspace->node); | ||
636 | } | ||
637 | if (container) { | ||
638 | struct sway_seat_node *seat_node = | ||
639 | seat_node_from_node(seat, &container->node); | ||
640 | wl_list_remove(&seat_node->link); | ||
641 | wl_list_insert(&seat->focus_stack, &seat_node->link); | ||
642 | node_set_dirty(&container->node); | ||
663 | 643 | ||
664 | if (last_focus) { | 644 | if (last_focus) { |
665 | seat_send_unfocus(last_focus, seat); | 645 | seat_send_unfocus(last_focus, seat); |
666 | container_set_dirty(last_focus); | 646 | node_set_dirty(last_focus); |
647 | struct sway_node *last_parent = node_get_parent(last_focus); | ||
648 | if (last_parent) { | ||
649 | node_set_dirty(last_parent); | ||
650 | } | ||
667 | } | 651 | } |
668 | seat_send_focus(container, seat); | 652 | seat_send_focus(&container->node, seat); |
669 | |||
670 | container_set_dirty(container); | ||
671 | container_set_dirty(container->parent); // for focused_inactive_child | ||
672 | } | 653 | } |
673 | 654 | ||
674 | // emit ipc events | 655 | // emit ipc events |
675 | if (notify && new_workspace && last_workspace != new_workspace) { | 656 | if (notify && new_workspace && last_workspace != new_workspace) { |
676 | ipc_event_workspace(last_workspace, new_workspace, "focus"); | 657 | ipc_event_workspace(last_workspace, new_workspace, "focus"); |
677 | } | 658 | } |
678 | if (container->type == C_VIEW) { | 659 | if (container && container->view) { |
679 | ipc_event_window(container, "focus"); | 660 | ipc_event_window(container, "focus"); |
680 | } | 661 | } |
681 | 662 | ||
@@ -684,14 +665,14 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
684 | } | 665 | } |
685 | 666 | ||
686 | // Close any popups on the old focus | 667 | // Close any popups on the old focus |
687 | if (last_focus && last_focus->type == C_VIEW) { | 668 | if (last_focus && node_is_view(last_focus)) { |
688 | view_close_popups(last_focus->sway_view); | 669 | view_close_popups(last_focus->sway_container->view); |
689 | } | 670 | } |
690 | 671 | ||
691 | // If urgent, either unset the urgency or start a timer to unset it | 672 | // If urgent, either unset the urgency or start a timer to unset it |
692 | if (container->type == C_VIEW && view_is_urgent(container->sway_view) && | 673 | if (container && container->view && view_is_urgent(container->view) && |
693 | !container->sway_view->urgent_timer) { | 674 | !container->view->urgent_timer) { |
694 | struct sway_view *view = container->sway_view; | 675 | struct sway_view *view = container->view; |
695 | if (last_workspace && last_workspace != new_workspace && | 676 | if (last_workspace && last_workspace != new_workspace && |
696 | config->urgent_timeout > 0) { | 677 | config->urgent_timeout > 0) { |
697 | view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, | 678 | view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, |
@@ -711,12 +692,15 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
711 | 692 | ||
712 | // If we've focused a floating container, bring it to the front. | 693 | // If we've focused a floating container, bring it to the front. |
713 | // We do this by putting it at the end of the floating list. | 694 | // We do this by putting it at the end of the floating list. |
714 | struct sway_container *floater = container; | 695 | if (container) { |
715 | while (floater->parent && floater->parent->type != C_WORKSPACE) { | 696 | struct sway_container *floater = container; |
716 | floater = floater->parent; | 697 | while (floater->parent) { |
717 | } | 698 | floater = floater->parent; |
718 | if (container_is_floating(floater)) { | 699 | } |
719 | list_move_to_end(floater->parent->sway_workspace->floating, floater); | 700 | if (container_is_floating(floater)) { |
701 | list_move_to_end(floater->workspace->floating, floater); | ||
702 | node_set_dirty(&floater->workspace->node); | ||
703 | } | ||
720 | } | 704 | } |
721 | 705 | ||
722 | if (last_focus) { | 706 | if (last_focus) { |
@@ -727,11 +711,8 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
727 | if (config->mouse_warping && warp && new_output != last_output) { | 711 | if (config->mouse_warping && warp && new_output != last_output) { |
728 | double x = container->x + container->width / 2.0; | 712 | double x = container->x + container->width / 2.0; |
729 | double y = container->y + container->height / 2.0; | 713 | double y = container->y + container->height / 2.0; |
730 | struct wlr_output *wlr_output = | 714 | if (!wlr_output_layout_contains_point(root->output_layout, |
731 | new_output->sway_output->wlr_output; | 715 | new_output->wlr_output, seat->cursor->cursor->x, |
732 | if (!wlr_output_layout_contains_point( | ||
733 | root_container.sway_root->output_layout, | ||
734 | wlr_output, seat->cursor->cursor->x, | ||
735 | seat->cursor->cursor->y)) { | 716 | seat->cursor->cursor->y)) { |
736 | wlr_cursor_warp(seat->cursor->cursor, NULL, x, y); | 717 | wlr_cursor_warp(seat->cursor->cursor, NULL, x, y); |
737 | cursor_send_pointer_motion(seat->cursor, 0, true); | 718 | cursor_send_pointer_motion(seat->cursor, 0, true); |
@@ -744,9 +725,8 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
744 | update_debug_tree(); | 725 | update_debug_tree(); |
745 | } | 726 | } |
746 | 727 | ||
747 | void seat_set_focus(struct sway_seat *seat, | 728 | void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { |
748 | struct sway_container *container) { | 729 | seat_set_focus_warp(seat, node, true, true); |
749 | seat_set_focus_warp(seat, container, true, true); | ||
750 | } | 730 | } |
751 | 731 | ||
752 | void seat_set_focus_surface(struct sway_seat *seat, | 732 | void seat_set_focus_surface(struct sway_seat *seat, |
@@ -755,12 +735,11 @@ void seat_set_focus_surface(struct sway_seat *seat, | |||
755 | return; | 735 | return; |
756 | } | 736 | } |
757 | if (seat->has_focus && unfocus) { | 737 | if (seat->has_focus && unfocus) { |
758 | struct sway_container *focus = seat_get_focus(seat); | 738 | struct sway_node *focus = seat_get_focus(seat); |
759 | seat_send_unfocus(focus, seat); | 739 | seat_send_unfocus(focus, seat); |
760 | seat->has_focus = false; | 740 | seat->has_focus = false; |
761 | } | 741 | } |
762 | struct wlr_keyboard *keyboard = | 742 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat); |
763 | wlr_seat_get_keyboard(seat->wlr_seat); | ||
764 | if (keyboard) { | 743 | if (keyboard) { |
765 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, | 744 | wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, |
766 | keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); | 745 | keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); |
@@ -773,11 +752,8 @@ void seat_set_focus_layer(struct sway_seat *seat, | |||
773 | struct wlr_layer_surface *layer) { | 752 | struct wlr_layer_surface *layer) { |
774 | if (!layer && seat->focused_layer) { | 753 | if (!layer && seat->focused_layer) { |
775 | seat->focused_layer = NULL; | 754 | seat->focused_layer = NULL; |
776 | struct sway_container *previous = | 755 | struct sway_node *previous = seat_get_focus_inactive(seat, &root->node); |
777 | seat_get_focus_inactive(seat, &root_container); | ||
778 | if (previous) { | 756 | if (previous) { |
779 | wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, | ||
780 | container_type_to_str(previous->type), previous->name); | ||
781 | // Hack to get seat to re-focus the return value of get_focus | 757 | // Hack to get seat to re-focus the return value of get_focus |
782 | seat_set_focus(seat, NULL); | 758 | seat_set_focus(seat, NULL); |
783 | seat_set_focus(seat, previous); | 759 | seat_set_focus(seat, previous); |
@@ -798,13 +774,9 @@ void seat_set_exclusive_client(struct sway_seat *seat, | |||
798 | seat->exclusive_client = client; | 774 | seat->exclusive_client = client; |
799 | // Triggers a refocus of the topmost surface layer if necessary | 775 | // Triggers a refocus of the topmost surface layer if necessary |
800 | // TODO: Make layer surface focus per-output based on cursor position | 776 | // TODO: Make layer surface focus per-output based on cursor position |
801 | for (int i = 0; i < root_container.children->length; ++i) { | 777 | for (int i = 0; i < root->outputs->length; ++i) { |
802 | struct sway_container *output = root_container.children->items[i]; | 778 | struct sway_output *output = root->outputs->items[i]; |
803 | if (!sway_assert(output->type == C_OUTPUT, | 779 | arrange_layers(output); |
804 | "root container has non-output child")) { | ||
805 | continue; | ||
806 | } | ||
807 | arrange_layers(output->sway_output); | ||
808 | } | 780 | } |
809 | return; | 781 | return; |
810 | } | 782 | } |
@@ -814,9 +786,9 @@ void seat_set_exclusive_client(struct sway_seat *seat, | |||
814 | } | 786 | } |
815 | } | 787 | } |
816 | if (seat->has_focus) { | 788 | if (seat->has_focus) { |
817 | struct sway_container *focus = seat_get_focus(seat); | 789 | struct sway_node *focus = seat_get_focus(seat); |
818 | if (focus->type == C_VIEW && wl_resource_get_client( | 790 | if (node_is_view(focus) && wl_resource_get_client( |
819 | focus->sway_view->surface->resource) != client) { | 791 | focus->sway_container->view->surface->resource) != client) { |
820 | seat_set_focus(seat, NULL); | 792 | seat_set_focus(seat, NULL); |
821 | } | 793 | } |
822 | } | 794 | } |
@@ -837,79 +809,101 @@ void seat_set_exclusive_client(struct sway_seat *seat, | |||
837 | seat->exclusive_client = client; | 809 | seat->exclusive_client = client; |
838 | } | 810 | } |
839 | 811 | ||
840 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | 812 | struct sway_node *seat_get_focus_inactive(struct sway_seat *seat, |
841 | struct sway_container *con) { | 813 | struct sway_node *node) { |
842 | if (con->type == C_WORKSPACE && !con->children->length && | 814 | if (node_is_view(node)) { |
843 | !con->sway_workspace->floating->length) { | 815 | return node; |
844 | return con; | ||
845 | } | ||
846 | if (con->type == C_VIEW) { | ||
847 | return con; | ||
848 | } | 816 | } |
849 | struct sway_seat_container *current; | 817 | struct sway_seat_node *current; |
850 | wl_list_for_each(current, &seat->focus_stack, link) { | 818 | wl_list_for_each(current, &seat->focus_stack, link) { |
851 | if (container_has_ancestor(current->container, con)) { | 819 | if (node_has_ancestor(current->node, node)) { |
852 | return current->container; | 820 | return current->node; |
853 | } | 821 | } |
854 | } | 822 | } |
823 | if (node->type == N_WORKSPACE) { | ||
824 | return node; | ||
825 | } | ||
855 | return NULL; | 826 | return NULL; |
856 | } | 827 | } |
857 | 828 | ||
858 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, | 829 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, |
859 | struct sway_container *ancestor) { | 830 | struct sway_workspace *workspace) { |
860 | if (ancestor->type == C_WORKSPACE && !ancestor->children->length) { | 831 | if (!workspace->tiling->length) { |
861 | return ancestor; | 832 | return NULL; |
862 | } | 833 | } |
863 | struct sway_seat_container *current; | 834 | struct sway_seat_node *current; |
864 | wl_list_for_each(current, &seat->focus_stack, link) { | 835 | wl_list_for_each(current, &seat->focus_stack, link) { |
865 | struct sway_container *con = current->container; | 836 | struct sway_node *node = current->node; |
866 | if (!container_is_floating_or_child(con) && | 837 | if (node->type == N_CONTAINER && |
867 | container_has_ancestor(current->container, ancestor)) { | 838 | !container_is_floating_or_child(node->sway_container) && |
868 | return con; | 839 | node->sway_container->workspace == workspace) { |
840 | return node->sway_container; | ||
869 | } | 841 | } |
870 | } | 842 | } |
871 | return NULL; | 843 | return NULL; |
872 | } | 844 | } |
873 | 845 | ||
874 | struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, | 846 | struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, |
875 | struct sway_container *ancestor) { | 847 | struct sway_workspace *workspace) { |
876 | if (ancestor->type == C_WORKSPACE && | 848 | if (!workspace->floating->length) { |
877 | !ancestor->sway_workspace->floating->length) { | ||
878 | return NULL; | 849 | return NULL; |
879 | } | 850 | } |
880 | struct sway_seat_container *current; | 851 | struct sway_seat_node *current; |
881 | wl_list_for_each(current, &seat->focus_stack, link) { | 852 | wl_list_for_each(current, &seat->focus_stack, link) { |
882 | struct sway_container *con = current->container; | 853 | struct sway_node *node = current->node; |
883 | if (container_is_floating_or_child(con) && | 854 | if (node->type == N_CONTAINER && |
884 | container_has_ancestor(current->container, ancestor)) { | 855 | container_is_floating_or_child(node->sway_container) && |
885 | return con; | 856 | node->sway_container->workspace == workspace) { |
857 | return node->sway_container; | ||
886 | } | 858 | } |
887 | } | 859 | } |
888 | return NULL; | 860 | return NULL; |
889 | } | 861 | } |
890 | 862 | ||
891 | struct sway_container *seat_get_active_child(struct sway_seat *seat, | 863 | struct sway_node *seat_get_active_child(struct sway_seat *seat, |
892 | struct sway_container *parent) { | 864 | struct sway_node *parent) { |
893 | if (parent->type == C_VIEW) { | 865 | if (node_is_view(parent)) { |
894 | return parent; | 866 | return parent; |
895 | } | 867 | } |
896 | struct sway_seat_container *current; | 868 | struct sway_seat_node *current; |
897 | wl_list_for_each(current, &seat->focus_stack, link) { | 869 | wl_list_for_each(current, &seat->focus_stack, link) { |
898 | struct sway_container *con = current->container; | 870 | struct sway_node *node = current->node; |
899 | if (con->parent == parent) { | 871 | if (node_get_parent(node) == parent) { |
900 | return con; | 872 | return node; |
901 | } | 873 | } |
902 | } | 874 | } |
903 | return NULL; | 875 | return NULL; |
904 | } | 876 | } |
905 | 877 | ||
906 | struct sway_container *seat_get_focus(struct sway_seat *seat) { | 878 | struct sway_node *seat_get_focus(struct sway_seat *seat) { |
907 | if (!seat->has_focus) { | 879 | if (!seat->has_focus) { |
908 | return NULL; | 880 | return NULL; |
909 | } | 881 | } |
910 | struct sway_seat_container *current = | 882 | struct sway_seat_node *current = |
911 | wl_container_of(seat->focus_stack.next, current, link); | 883 | wl_container_of(seat->focus_stack.next, current, link); |
912 | return current->container; | 884 | return current->node; |
885 | } | ||
886 | |||
887 | struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) { | ||
888 | struct sway_node *focus = seat_get_focus(seat); | ||
889 | if (!focus) { | ||
890 | return NULL; | ||
891 | } | ||
892 | if (focus->type == N_CONTAINER) { | ||
893 | return focus->sway_container->workspace; | ||
894 | } | ||
895 | if (focus->type == N_WORKSPACE) { | ||
896 | return focus->sway_workspace; | ||
897 | } | ||
898 | return NULL; // unreachable | ||
899 | } | ||
900 | |||
901 | struct sway_container *seat_get_focused_container(struct sway_seat *seat) { | ||
902 | struct sway_node *focus = seat_get_focus(seat); | ||
903 | if (focus && focus->type == N_CONTAINER) { | ||
904 | return focus->sway_container; | ||
905 | } | ||
906 | return NULL; | ||
913 | } | 907 | } |
914 | 908 | ||
915 | void seat_apply_config(struct sway_seat *seat, | 909 | void seat_apply_config(struct sway_seat *seat, |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 06cb7e11..9a955991 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -46,18 +46,18 @@ json_object *ipc_json_get_version() { | |||
46 | return version; | 46 | return version; |
47 | } | 47 | } |
48 | 48 | ||
49 | static json_object *ipc_json_create_rect(struct sway_container *c) { | 49 | static json_object *ipc_json_create_rect(struct wlr_box *box) { |
50 | json_object *rect = json_object_new_object(); | 50 | json_object *rect = json_object_new_object(); |
51 | 51 | ||
52 | json_object_object_add(rect, "x", json_object_new_int((int32_t)c->x)); | 52 | json_object_object_add(rect, "x", json_object_new_int(box->x)); |
53 | json_object_object_add(rect, "y", json_object_new_int((int32_t)c->y)); | 53 | json_object_object_add(rect, "y", json_object_new_int(box->y)); |
54 | json_object_object_add(rect, "width", json_object_new_int((int32_t)c->width)); | 54 | json_object_object_add(rect, "width", json_object_new_int(box->width)); |
55 | json_object_object_add(rect, "height", json_object_new_int((int32_t)c->height)); | 55 | json_object_object_add(rect, "height", json_object_new_int(box->height)); |
56 | 56 | ||
57 | return rect; | 57 | return rect; |
58 | } | 58 | } |
59 | 59 | ||
60 | static void ipc_json_describe_root(struct sway_container *root, json_object *object) { | 60 | static void ipc_json_describe_root(struct sway_root *root, json_object *object) { |
61 | json_object_object_add(object, "type", json_object_new_string("root")); | 61 | json_object_object_add(object, "type", json_object_new_string("root")); |
62 | json_object_object_add(object, "layout", json_object_new_string("splith")); | 62 | json_object_object_add(object, "layout", json_object_new_string("splith")); |
63 | } | 63 | } |
@@ -84,17 +84,13 @@ static const char *ipc_json_get_output_transform(enum wl_output_transform transf | |||
84 | return NULL; | 84 | return NULL; |
85 | } | 85 | } |
86 | 86 | ||
87 | static void ipc_json_describe_output(struct sway_container *container, | 87 | static void ipc_json_describe_output(struct sway_output *output, |
88 | json_object *object) { | 88 | json_object *object) { |
89 | struct wlr_output *wlr_output = container->sway_output->wlr_output; | 89 | struct wlr_output *wlr_output = output->wlr_output; |
90 | json_object_object_add(object, "type", | 90 | json_object_object_add(object, "type", json_object_new_string("output")); |
91 | json_object_new_string("output")); | 91 | json_object_object_add(object, "active", json_object_new_boolean(true)); |
92 | json_object_object_add(object, "active", | 92 | json_object_object_add(object, "primary", json_object_new_boolean(false)); |
93 | json_object_new_boolean(true)); | 93 | json_object_object_add(object, "layout", json_object_new_string("output")); |
94 | json_object_object_add(object, "primary", | ||
95 | json_object_new_boolean(false)); | ||
96 | json_object_object_add(object, "layout", | ||
97 | json_object_new_string("output")); | ||
98 | json_object_object_add(object, "make", | 94 | json_object_object_add(object, "make", |
99 | json_object_new_string(wlr_output->make)); | 95 | json_object_new_string(wlr_output->make)); |
100 | json_object_object_add(object, "model", | 96 | json_object_object_add(object, "model", |
@@ -109,20 +105,9 @@ static void ipc_json_describe_output(struct sway_container *container, | |||
109 | json_object_new_string( | 105 | json_object_new_string( |
110 | ipc_json_get_output_transform(wlr_output->transform))); | 106 | ipc_json_get_output_transform(wlr_output->transform))); |
111 | 107 | ||
112 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | 108 | struct sway_workspace *ws = output_get_active_workspace(output); |
113 | const char *ws = NULL; | ||
114 | if (seat) { | ||
115 | struct sway_container *focus = | ||
116 | seat_get_focus_inactive(seat, container); | ||
117 | if (focus && focus->type != C_WORKSPACE) { | ||
118 | focus = container_parent(focus, C_WORKSPACE); | ||
119 | } | ||
120 | if (focus) { | ||
121 | ws = focus->name; | ||
122 | } | ||
123 | } | ||
124 | json_object_object_add(object, "current_workspace", | 109 | json_object_object_add(object, "current_workspace", |
125 | json_object_new_string(ws)); | 110 | json_object_new_string(ws->name)); |
126 | 111 | ||
127 | json_object *modes_array = json_object_new_array(); | 112 | json_object *modes_array = json_object_new_array(); |
128 | struct wlr_output_mode *mode; | 113 | struct wlr_output_mode *mode; |
@@ -161,60 +146,57 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) { | |||
161 | return object; | 146 | return object; |
162 | } | 147 | } |
163 | 148 | ||
164 | static void ipc_json_describe_workspace(struct sway_container *workspace, | 149 | static void ipc_json_describe_workspace(struct sway_workspace *workspace, |
165 | json_object *object) { | 150 | json_object *object) { |
166 | int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1; | 151 | int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1; |
167 | 152 | ||
168 | json_object_object_add(object, "num", json_object_new_int(num)); | 153 | json_object_object_add(object, "num", json_object_new_int(num)); |
169 | json_object_object_add(object, "output", workspace->parent ? | 154 | json_object_object_add(object, "output", workspace->output ? |
170 | json_object_new_string(workspace->parent->name) : NULL); | 155 | json_object_new_string(workspace->output->wlr_output->name) : NULL); |
171 | json_object_object_add(object, "type", json_object_new_string("workspace")); | 156 | json_object_object_add(object, "type", json_object_new_string("workspace")); |
172 | json_object_object_add(object, "urgent", | 157 | json_object_object_add(object, "urgent", |
173 | json_object_new_boolean(workspace->sway_workspace->urgent)); | 158 | json_object_new_boolean(workspace->urgent)); |
174 | json_object_object_add(object, "representation", workspace->formatted_title ? | 159 | json_object_object_add(object, "representation", workspace->representation ? |
175 | json_object_new_string(workspace->formatted_title) : NULL); | 160 | json_object_new_string(workspace->representation) : NULL); |
176 | 161 | ||
177 | const char *layout = ipc_json_layout_description(workspace->layout); | 162 | const char *layout = ipc_json_layout_description(workspace->layout); |
178 | json_object_object_add(object, "layout", json_object_new_string(layout)); | 163 | json_object_object_add(object, "layout", json_object_new_string(layout)); |
179 | 164 | ||
180 | // Floating | 165 | // Floating |
181 | json_object *floating_array = json_object_new_array(); | 166 | json_object *floating_array = json_object_new_array(); |
182 | list_t *floating = workspace->sway_workspace->floating; | 167 | for (int i = 0; i < workspace->floating->length; ++i) { |
183 | for (int i = 0; i < floating->length; ++i) { | 168 | struct sway_container *floater = workspace->floating->items[i]; |
184 | struct sway_container *floater = floating->items[i]; | ||
185 | json_object_array_add(floating_array, | 169 | json_object_array_add(floating_array, |
186 | ipc_json_describe_container_recursive(floater)); | 170 | ipc_json_describe_node_recursive(&floater->node)); |
187 | } | 171 | } |
188 | json_object_object_add(object, "floating_nodes", floating_array); | 172 | json_object_object_add(object, "floating_nodes", floating_array); |
189 | } | 173 | } |
190 | 174 | ||
191 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { | 175 | static void ipc_json_describe_view(struct sway_container *c, json_object *object) { |
192 | json_object_object_add(object, "name", | 176 | json_object_object_add(object, "name", |
193 | c->name ? json_object_new_string(c->name) : NULL); | 177 | c->title ? json_object_new_string(c->title) : NULL); |
194 | json_object_object_add(object, "type", json_object_new_string("con")); | 178 | json_object_object_add(object, "type", json_object_new_string("con")); |
195 | 179 | ||
196 | if (c->type == C_VIEW) { | 180 | if (c->view) { |
197 | const char *app_id = view_get_app_id(c->sway_view); | 181 | const char *app_id = view_get_app_id(c->view); |
198 | json_object_object_add(object, "app_id", | 182 | json_object_object_add(object, "app_id", |
199 | app_id ? json_object_new_string(app_id) : NULL); | 183 | app_id ? json_object_new_string(app_id) : NULL); |
200 | 184 | ||
201 | const char *class = view_get_class(c->sway_view); | 185 | const char *class = view_get_class(c->view); |
202 | json_object_object_add(object, "class", | 186 | json_object_object_add(object, "class", |
203 | class ? json_object_new_string(class) : NULL); | 187 | class ? json_object_new_string(class) : NULL); |
204 | } | 188 | } |
205 | 189 | ||
206 | if (c->parent) { | 190 | json_object_object_add(object, "layout", |
207 | json_object_object_add(object, "layout", | 191 | json_object_new_string(ipc_json_layout_description(c->layout))); |
208 | json_object_new_string(ipc_json_layout_description(c->layout))); | ||
209 | } | ||
210 | 192 | ||
211 | bool urgent = c->type == C_VIEW ? | 193 | bool urgent = c->view ? |
212 | view_is_urgent(c->sway_view) : container_has_urgent_child(c); | 194 | view_is_urgent(c->view) : container_has_urgent_child(c); |
213 | json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); | 195 | json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); |
214 | 196 | ||
215 | if (c->type == C_VIEW) { | 197 | if (c->view) { |
216 | json_object *marks = json_object_new_array(); | 198 | json_object *marks = json_object_new_array(); |
217 | list_t *view_marks = c->sway_view->marks; | 199 | list_t *view_marks = c->view->marks; |
218 | for (int i = 0; i < view_marks->length; ++i) { | 200 | for (int i = 0; i < view_marks->length; ++i) { |
219 | json_object_array_add(marks, json_object_new_string(view_marks->items[i])); | 201 | json_object_array_add(marks, json_object_new_string(view_marks->items[i])); |
220 | } | 202 | } |
@@ -222,64 +204,97 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
222 | } | 204 | } |
223 | } | 205 | } |
224 | 206 | ||
225 | static void focus_inactive_children_iterator(struct sway_container *c, void *data) { | 207 | struct focus_inactive_data { |
226 | json_object *focus = data; | 208 | struct sway_node *node; |
227 | json_object_array_add(focus, json_object_new_int(c->id)); | 209 | json_object *object; |
228 | } | 210 | }; |
229 | 211 | ||
230 | json_object *ipc_json_describe_container(struct sway_container *c) { | 212 | static void focus_inactive_children_iterator(struct sway_node *node, |
231 | if (!(sway_assert(c, "Container must not be null."))) { | 213 | void *_data) { |
232 | return NULL; | 214 | struct focus_inactive_data *data = _data; |
215 | if (node_get_parent(node) == data->node) { | ||
216 | json_object_array_add(data->object, json_object_new_int(node->id)); | ||
233 | } | 217 | } |
218 | } | ||
234 | 219 | ||
220 | json_object *ipc_json_describe_node(struct sway_node *node) { | ||
235 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | 221 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
236 | bool focused = seat_get_focus(seat) == c; | 222 | bool focused = seat_get_focus(seat) == node; |
237 | 223 | ||
238 | json_object *object = json_object_new_object(); | 224 | json_object *object = json_object_new_object(); |
225 | char *name = node_get_name(node); | ||
239 | 226 | ||
240 | json_object_object_add(object, "id", json_object_new_int((int)c->id)); | 227 | struct wlr_box box; |
228 | node_get_box(node, &box); | ||
229 | json_object_object_add(object, "id", json_object_new_int((int)node->id)); | ||
241 | json_object_object_add(object, "name", | 230 | json_object_object_add(object, "name", |
242 | c->name ? json_object_new_string(c->name) : NULL); | 231 | name ? json_object_new_string(name) : NULL); |
243 | json_object_object_add(object, "rect", ipc_json_create_rect(c)); | 232 | json_object_object_add(object, "rect", ipc_json_create_rect(&box)); |
244 | json_object_object_add(object, "focused", | 233 | json_object_object_add(object, "focused", json_object_new_boolean(focused)); |
245 | json_object_new_boolean(focused)); | ||
246 | 234 | ||
247 | json_object *focus = json_object_new_array(); | 235 | json_object *focus = json_object_new_array(); |
248 | seat_focus_inactive_children_for_each(seat, c, | 236 | struct focus_inactive_data data = { |
249 | focus_inactive_children_iterator, focus); | 237 | .node = node, |
238 | .object = focus, | ||
239 | }; | ||
240 | seat_for_each_node(seat, focus_inactive_children_iterator, &data); | ||
250 | json_object_object_add(object, "focus", focus); | 241 | json_object_object_add(object, "focus", focus); |
251 | 242 | ||
252 | switch (c->type) { | 243 | switch (node->type) { |
253 | case C_ROOT: | 244 | case N_ROOT: |
254 | ipc_json_describe_root(c, object); | 245 | ipc_json_describe_root(root, object); |
255 | break; | 246 | break; |
256 | case C_OUTPUT: | 247 | case N_OUTPUT: |
257 | ipc_json_describe_output(c, object); | 248 | ipc_json_describe_output(node->sway_output, object); |
258 | break; | 249 | break; |
259 | case C_CONTAINER: | 250 | case N_CONTAINER: |
260 | case C_VIEW: | 251 | ipc_json_describe_view(node->sway_container, object); |
261 | ipc_json_describe_view(c, object); | ||
262 | break; | 252 | break; |
263 | case C_WORKSPACE: | 253 | case N_WORKSPACE: |
264 | ipc_json_describe_workspace(c, object); | 254 | ipc_json_describe_workspace(node->sway_workspace, object); |
265 | break; | ||
266 | case C_TYPES: | ||
267 | default: | ||
268 | break; | 255 | break; |
269 | } | 256 | } |
270 | 257 | ||
271 | return object; | 258 | return object; |
272 | } | 259 | } |
273 | 260 | ||
274 | json_object *ipc_json_describe_container_recursive(struct sway_container *c) { | 261 | json_object *ipc_json_describe_node_recursive(struct sway_node *node) { |
275 | json_object *object = ipc_json_describe_container(c); | 262 | json_object *object = ipc_json_describe_node(node); |
276 | int i; | 263 | int i; |
277 | 264 | ||
278 | json_object *children = json_object_new_array(); | 265 | json_object *children = json_object_new_array(); |
279 | if (c->type != C_VIEW && c->children) { | 266 | switch (node->type) { |
280 | for (i = 0; i < c->children->length; ++i) { | 267 | case N_ROOT: |
281 | json_object_array_add(children, ipc_json_describe_container_recursive(c->children->items[i])); | 268 | for (i = 0; i < root->outputs->length; ++i) { |
269 | struct sway_output *output = root->outputs->items[i]; | ||
270 | json_object_array_add(children, | ||
271 | ipc_json_describe_node_recursive(&output->node)); | ||
272 | } | ||
273 | break; | ||
274 | case N_OUTPUT: | ||
275 | for (i = 0; i < node->sway_output->workspaces->length; ++i) { | ||
276 | struct sway_workspace *ws = node->sway_output->workspaces->items[i]; | ||
277 | json_object_array_add(children, | ||
278 | ipc_json_describe_node_recursive(&ws->node)); | ||
282 | } | 279 | } |
280 | break; | ||
281 | case N_WORKSPACE: | ||
282 | for (i = 0; i < node->sway_workspace->tiling->length; ++i) { | ||
283 | struct sway_container *con = node->sway_workspace->tiling->items[i]; | ||
284 | json_object_array_add(children, | ||
285 | ipc_json_describe_node_recursive(&con->node)); | ||
286 | } | ||
287 | break; | ||
288 | case N_CONTAINER: | ||
289 | if (node->sway_container->children) { | ||
290 | for (i = 0; i < node->sway_container->children->length; ++i) { | ||
291 | struct sway_container *child = | ||
292 | node->sway_container->children->items[i]; | ||
293 | json_object_array_add(children, | ||
294 | ipc_json_describe_node_recursive(&child->node)); | ||
295 | } | ||
296 | } | ||
297 | break; | ||
283 | } | 298 | } |
284 | json_object_object_add(object, "nodes", children); | 299 | json_object_object_add(object, "nodes", children); |
285 | 300 | ||
@@ -329,7 +344,7 @@ json_object *ipc_json_describe_seat(struct sway_seat *seat) { | |||
329 | } | 344 | } |
330 | 345 | ||
331 | json_object *object = json_object_new_object(); | 346 | json_object *object = json_object_new_object(); |
332 | struct sway_container *focus = seat_get_focus(seat); | 347 | struct sway_node *focus = seat_get_focus(seat); |
333 | 348 | ||
334 | json_object_object_add(object, "name", | 349 | json_object_object_add(object, "name", |
335 | json_object_new_string(seat->wlr_seat->name)); | 350 | json_object_new_string(seat->wlr_seat->name)); |
@@ -470,13 +485,13 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { | |||
470 | json_object_object_add(json, "colors", colors); | 485 | json_object_object_add(json, "colors", colors); |
471 | 486 | ||
472 | // Add outputs if defined | 487 | // Add outputs if defined |
488 | json_object *outputs = json_object_new_array(); | ||
473 | if (bar->outputs && bar->outputs->length > 0) { | 489 | if (bar->outputs && bar->outputs->length > 0) { |
474 | json_object *outputs = json_object_new_array(); | ||
475 | for (int i = 0; i < bar->outputs->length; ++i) { | 490 | for (int i = 0; i < bar->outputs->length; ++i) { |
476 | const char *name = bar->outputs->items[i]; | 491 | const char *name = bar->outputs->items[i]; |
477 | json_object_array_add(outputs, json_object_new_string(name)); | 492 | json_object_array_add(outputs, json_object_new_string(name)); |
478 | } | 493 | } |
479 | json_object_object_add(json, "outputs", outputs); | ||
480 | } | 494 | } |
495 | json_object_object_add(json, "outputs", outputs); | ||
481 | return json; | 496 | return json; |
482 | } | 497 | } |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index fb5be27b..8ae265f6 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include "sway/input/seat.h" | 33 | #include "sway/input/seat.h" |
34 | #include "sway/tree/root.h" | 34 | #include "sway/tree/root.h" |
35 | #include "sway/tree/view.h" | 35 | #include "sway/tree/view.h" |
36 | #include "sway/tree/workspace.h" | ||
36 | #include "list.h" | 37 | #include "list.h" |
37 | #include "log.h" | 38 | #include "log.h" |
38 | #include "util.h" | 39 | #include "util.h" |
@@ -291,8 +292,8 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event) | |||
291 | } | 292 | } |
292 | } | 293 | } |
293 | 294 | ||
294 | void ipc_event_workspace(struct sway_container *old, | 295 | void ipc_event_workspace(struct sway_workspace *old, |
295 | struct sway_container *new, const char *change) { | 296 | struct sway_workspace *new, const char *change) { |
296 | if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) { | 297 | if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) { |
297 | return; | 298 | return; |
298 | } | 299 | } |
@@ -301,14 +302,14 @@ void ipc_event_workspace(struct sway_container *old, | |||
301 | json_object_object_add(obj, "change", json_object_new_string(change)); | 302 | json_object_object_add(obj, "change", json_object_new_string(change)); |
302 | if (old) { | 303 | if (old) { |
303 | json_object_object_add(obj, "old", | 304 | json_object_object_add(obj, "old", |
304 | ipc_json_describe_container_recursive(old)); | 305 | ipc_json_describe_node_recursive(&old->node)); |
305 | } else { | 306 | } else { |
306 | json_object_object_add(obj, "old", NULL); | 307 | json_object_object_add(obj, "old", NULL); |
307 | } | 308 | } |
308 | 309 | ||
309 | if (new) { | 310 | if (new) { |
310 | json_object_object_add(obj, "current", | 311 | json_object_object_add(obj, "current", |
311 | ipc_json_describe_container_recursive(new)); | 312 | ipc_json_describe_node_recursive(&new->node)); |
312 | } else { | 313 | } else { |
313 | json_object_object_add(obj, "current", NULL); | 314 | json_object_object_add(obj, "current", NULL); |
314 | } | 315 | } |
@@ -325,7 +326,8 @@ void ipc_event_window(struct sway_container *window, const char *change) { | |||
325 | wlr_log(WLR_DEBUG, "Sending window::%s event", change); | 326 | wlr_log(WLR_DEBUG, "Sending window::%s event", change); |
326 | json_object *obj = json_object_new_object(); | 327 | json_object *obj = json_object_new_object(); |
327 | json_object_object_add(obj, "change", json_object_new_string(change)); | 328 | json_object_object_add(obj, "change", json_object_new_string(change)); |
328 | json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); | 329 | json_object_object_add(obj, "container", |
330 | ipc_json_describe_node_recursive(&window->node)); | ||
329 | 331 | ||
330 | const char *json_string = json_object_to_json_string(obj); | 332 | const char *json_string = json_object_to_json_string(obj); |
331 | ipc_send_event(json_string, IPC_EVENT_WINDOW); | 333 | ipc_send_event(json_string, IPC_EVENT_WINDOW); |
@@ -521,30 +523,20 @@ void ipc_client_disconnect(struct ipc_client *client) { | |||
521 | free(client); | 523 | free(client); |
522 | } | 524 | } |
523 | 525 | ||
524 | static void ipc_get_workspaces_callback(struct sway_container *workspace, | 526 | static void ipc_get_workspaces_callback(struct sway_workspace *workspace, |
525 | void *data) { | 527 | void *data) { |
526 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 528 | json_object *workspace_json = ipc_json_describe_node(&workspace->node); |
527 | return; | ||
528 | } | ||
529 | json_object *workspace_json = ipc_json_describe_container(workspace); | ||
530 | // override the default focused indicator because | 529 | // override the default focused indicator because |
531 | // it's set differently for the get_workspaces reply | 530 | // it's set differently for the get_workspaces reply |
532 | struct sway_seat *seat = | 531 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
533 | input_manager_get_default_seat(input_manager); | 532 | struct sway_workspace *focused_ws = seat_get_focused_workspace(seat); |
534 | struct sway_container *focused_ws = seat_get_focus(seat); | ||
535 | if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) { | ||
536 | focused_ws = container_parent(focused_ws, C_WORKSPACE); | ||
537 | } | ||
538 | bool focused = workspace == focused_ws; | 533 | bool focused = workspace == focused_ws; |
539 | json_object_object_del(workspace_json, "focused"); | 534 | json_object_object_del(workspace_json, "focused"); |
540 | json_object_object_add(workspace_json, "focused", | 535 | json_object_object_add(workspace_json, "focused", |
541 | json_object_new_boolean(focused)); | 536 | json_object_new_boolean(focused)); |
542 | json_object_array_add((json_object *)data, workspace_json); | 537 | json_object_array_add((json_object *)data, workspace_json); |
543 | 538 | ||
544 | focused_ws = seat_get_focus_inactive(seat, workspace->parent); | 539 | focused_ws = output_get_active_workspace(workspace->output); |
545 | if (focused_ws->type != C_WORKSPACE) { | ||
546 | focused_ws = container_parent(focused_ws, C_WORKSPACE); | ||
547 | } | ||
548 | bool visible = workspace == focused_ws; | 540 | bool visible = workspace == focused_ws; |
549 | json_object_object_add(workspace_json, "visible", | 541 | json_object_object_add(workspace_json, "visible", |
550 | json_object_new_boolean(visible)); | 542 | json_object_new_boolean(visible)); |
@@ -552,9 +544,9 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace, | |||
552 | 544 | ||
553 | static void ipc_get_marks_callback(struct sway_container *con, void *data) { | 545 | static void ipc_get_marks_callback(struct sway_container *con, void *data) { |
554 | json_object *marks = (json_object *)data; | 546 | json_object *marks = (json_object *)data; |
555 | if (con->type == C_VIEW && con->sway_view->marks) { | 547 | if (con->view && con->view->marks) { |
556 | for (int i = 0; i < con->sway_view->marks->length; ++i) { | 548 | for (int i = 0; i < con->view->marks->length; ++i) { |
557 | char *mark = (char *)con->sway_view->marks->items[i]; | 549 | char *mark = (char *)con->view->marks->items[i]; |
558 | json_object_array_add(marks, json_object_new_string(mark)); | 550 | json_object_array_add(marks, json_object_new_string(mark)); |
559 | } | 551 | } |
560 | } | 552 | } |
@@ -608,16 +600,14 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
608 | case IPC_GET_OUTPUTS: | 600 | case IPC_GET_OUTPUTS: |
609 | { | 601 | { |
610 | json_object *outputs = json_object_new_array(); | 602 | json_object *outputs = json_object_new_array(); |
611 | for (int i = 0; i < root_container.children->length; ++i) { | 603 | for (int i = 0; i < root->outputs->length; ++i) { |
612 | struct sway_container *container = root_container.children->items[i]; | 604 | struct sway_output *output = root->outputs->items[i]; |
613 | if (container->type == C_OUTPUT) { | 605 | json_object_array_add(outputs, |
614 | json_object_array_add(outputs, | 606 | ipc_json_describe_node(&output->node)); |
615 | ipc_json_describe_container(container)); | ||
616 | } | ||
617 | } | 607 | } |
618 | struct sway_output *output; | 608 | struct sway_output *output; |
619 | wl_list_for_each(output, &root_container.sway_root->all_outputs, link) { | 609 | wl_list_for_each(output, &root->all_outputs, link) { |
620 | if (!output->swayc) { | 610 | if (!output->enabled) { |
621 | json_object_array_add(outputs, | 611 | json_object_array_add(outputs, |
622 | ipc_json_describe_disabled_output(output)); | 612 | ipc_json_describe_disabled_output(output)); |
623 | } | 613 | } |
@@ -717,8 +707,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
717 | 707 | ||
718 | case IPC_GET_TREE: | 708 | case IPC_GET_TREE: |
719 | { | 709 | { |
720 | json_object *tree = | 710 | json_object *tree = ipc_json_describe_node_recursive(&root->node); |
721 | ipc_json_describe_container_recursive(&root_container); | ||
722 | const char *json_string = json_object_to_json_string(tree); | 711 | const char *json_string = json_object_to_json_string(tree); |
723 | client_valid = | 712 | client_valid = |
724 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | 713 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); |
diff --git a/sway/main.c b/sway/main.c index 2f05dc38..fb4f0d8c 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -42,7 +42,6 @@ void sway_terminate(int exit_code) { | |||
42 | } | 42 | } |
43 | 43 | ||
44 | void sig_handler(int signal) { | 44 | void sig_handler(int signal) { |
45 | //close_views(&root_container); | ||
46 | sway_terminate(EXIT_SUCCESS); | 45 | sway_terminate(EXIT_SUCCESS); |
47 | } | 46 | } |
48 | 47 | ||
@@ -395,7 +394,7 @@ int main(int argc, char **argv) { | |||
395 | 394 | ||
396 | wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION); | 395 | wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION); |
397 | 396 | ||
398 | root_create(); | 397 | root = root_create(); |
399 | 398 | ||
400 | if (!server_init(&server)) { | 399 | if (!server_init(&server)) { |
401 | return 1; | 400 | return 1; |
@@ -450,7 +449,8 @@ int main(int argc, char **argv) { | |||
450 | wlr_log(WLR_INFO, "Shutting down sway"); | 449 | wlr_log(WLR_INFO, "Shutting down sway"); |
451 | 450 | ||
452 | server_fini(&server); | 451 | server_fini(&server); |
453 | root_destroy(); | 452 | root_destroy(root); |
453 | root = NULL; | ||
454 | 454 | ||
455 | if (config) { | 455 | if (config) { |
456 | free_config(config); | 456 | free_config(config); |
diff --git a/sway/meson.build b/sway/meson.build index c14e58dd..8891ebc0 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -151,6 +151,7 @@ sway_sources = files( | |||
151 | 151 | ||
152 | 'tree/arrange.c', | 152 | 'tree/arrange.c', |
153 | 'tree/container.c', | 153 | 'tree/container.c', |
154 | 'tree/node.c', | ||
154 | 'tree/root.c', | 155 | 'tree/root.c', |
155 | 'tree/view.c', | 156 | 'tree/view.c', |
156 | 'tree/workspace.c', | 157 | 'tree/workspace.c', |
diff --git a/sway/server.c b/sway/server.c index 749365cb..09ebe83f 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -61,8 +61,7 @@ bool server_init(struct sway_server *server) { | |||
61 | server->new_output.notify = handle_new_output; | 61 | server->new_output.notify = handle_new_output; |
62 | wl_signal_add(&server->backend->events.new_output, &server->new_output); | 62 | wl_signal_add(&server->backend->events.new_output, &server->new_output); |
63 | 63 | ||
64 | wlr_xdg_output_manager_create(server->wl_display, | 64 | wlr_xdg_output_manager_create(server->wl_display, root->output_layout); |
65 | root_container.sway_root->output_layout); | ||
66 | 65 | ||
67 | server->idle = wlr_idle_create(server->wl_display); | 66 | server->idle = wlr_idle_create(server->wl_display); |
68 | server->idle_inhibit_manager_v1 = | 67 | server->idle_inhibit_manager_v1 = |
@@ -131,7 +130,7 @@ bool server_init(struct sway_server *server) { | |||
131 | server->txn_timeout_ms = 200; | 130 | server->txn_timeout_ms = 200; |
132 | } | 131 | } |
133 | 132 | ||
134 | server->dirty_containers = create_list(); | 133 | server->dirty_nodes = create_list(); |
135 | server->transactions = create_list(); | 134 | server->transactions = create_list(); |
136 | 135 | ||
137 | input_manager = input_manager_create(server); | 136 | input_manager = input_manager_create(server); |
@@ -145,7 +144,7 @@ void server_fini(struct sway_server *server) { | |||
145 | #endif | 144 | #endif |
146 | wl_display_destroy_clients(server->wl_display); | 145 | wl_display_destroy_clients(server->wl_display); |
147 | wl_display_destroy(server->wl_display); | 146 | wl_display_destroy(server->wl_display); |
148 | list_free(server->dirty_containers); | 147 | list_free(server->dirty_nodes); |
149 | list_free(server->transactions); | 148 | list_free(server->transactions); |
150 | } | 149 | } |
151 | 150 | ||
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 92f20fcc..f86d4a74 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -166,29 +166,23 @@ void arrange_container(struct sway_container *container) { | |||
166 | if (config->reloading) { | 166 | if (config->reloading) { |
167 | return; | 167 | return; |
168 | } | 168 | } |
169 | if (container->type == C_VIEW) { | 169 | if (container->view) { |
170 | view_autoconfigure(container->sway_view); | 170 | view_autoconfigure(container->view); |
171 | container_set_dirty(container); | 171 | node_set_dirty(&container->node); |
172 | return; | ||
173 | } | ||
174 | if (!sway_assert(container->type == C_CONTAINER, "Expected a container")) { | ||
175 | return; | 172 | return; |
176 | } | 173 | } |
177 | struct wlr_box box; | 174 | struct wlr_box box; |
178 | container_get_box(container, &box); | 175 | container_get_box(container, &box); |
179 | arrange_children(container->children, container->layout, &box); | 176 | arrange_children(container->children, container->layout, &box); |
180 | container_set_dirty(container); | 177 | node_set_dirty(&container->node); |
181 | } | 178 | } |
182 | 179 | ||
183 | void arrange_workspace(struct sway_container *workspace) { | 180 | void arrange_workspace(struct sway_workspace *workspace) { |
184 | if (config->reloading) { | 181 | if (config->reloading) { |
185 | return; | 182 | return; |
186 | } | 183 | } |
187 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 184 | struct sway_output *output = workspace->output; |
188 | return; | 185 | struct wlr_box *area = &output->usable_area; |
189 | } | ||
190 | struct sway_container *output = workspace->parent; | ||
191 | struct wlr_box *area = &output->sway_output->usable_area; | ||
192 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", | 186 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", |
193 | area->width, area->height, area->x, area->y); | 187 | area->width, area->height, area->x, area->y); |
194 | workspace_remove_gaps(workspace); | 188 | workspace_remove_gaps(workspace); |
@@ -197,21 +191,20 @@ void arrange_workspace(struct sway_container *workspace) { | |||
197 | double prev_y = workspace->y; | 191 | double prev_y = workspace->y; |
198 | workspace->width = area->width; | 192 | workspace->width = area->width; |
199 | workspace->height = area->height; | 193 | workspace->height = area->height; |
200 | workspace->x = output->x + area->x; | 194 | workspace->x = output->wlr_output->lx + area->x; |
201 | workspace->y = output->y + area->y; | 195 | workspace->y = output->wlr_output->ly + area->y; |
202 | 196 | ||
203 | // Adjust any floating containers | 197 | // Adjust any floating containers |
204 | double diff_x = workspace->x - prev_x; | 198 | double diff_x = workspace->x - prev_x; |
205 | double diff_y = workspace->y - prev_y; | 199 | double diff_y = workspace->y - prev_y; |
206 | if (diff_x != 0 || diff_y != 0) { | 200 | if (diff_x != 0 || diff_y != 0) { |
207 | for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) { | 201 | for (int i = 0; i < workspace->floating->length; ++i) { |
208 | struct sway_container *floater = | 202 | struct sway_container *floater = workspace->floating->items[i]; |
209 | workspace->sway_workspace->floating->items[i]; | ||
210 | container_floating_translate(floater, diff_x, diff_y); | 203 | container_floating_translate(floater, diff_x, diff_y); |
211 | double center_x = floater->x + floater->width / 2; | 204 | double center_x = floater->x + floater->width / 2; |
212 | double center_y = floater->y + floater->height / 2; | 205 | double center_y = floater->y + floater->height / 2; |
213 | struct wlr_box workspace_box; | 206 | struct wlr_box workspace_box; |
214 | container_get_box(workspace, &workspace_box); | 207 | workspace_get_box(workspace, &workspace_box); |
215 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { | 208 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { |
216 | container_floating_move_to_center(floater); | 209 | container_floating_move_to_center(floater); |
217 | } | 210 | } |
@@ -219,43 +212,32 @@ void arrange_workspace(struct sway_container *workspace) { | |||
219 | } | 212 | } |
220 | 213 | ||
221 | workspace_add_gaps(workspace); | 214 | workspace_add_gaps(workspace); |
222 | container_set_dirty(workspace); | 215 | node_set_dirty(&workspace->node); |
223 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, | 216 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, |
224 | workspace->x, workspace->y); | 217 | workspace->x, workspace->y); |
225 | if (workspace->sway_workspace->fullscreen) { | 218 | if (workspace->fullscreen) { |
226 | struct sway_container *fs = workspace->sway_workspace->fullscreen; | 219 | struct sway_container *fs = workspace->fullscreen; |
227 | fs->x = workspace->parent->x; | 220 | fs->x = output->wlr_output->lx; |
228 | fs->y = workspace->parent->y; | 221 | fs->y = output->wlr_output->ly; |
229 | fs->width = workspace->parent->width; | 222 | fs->width = output->wlr_output->width; |
230 | fs->height = workspace->parent->height; | 223 | fs->height = output->wlr_output->height; |
231 | arrange_container(fs); | 224 | arrange_container(fs); |
232 | } else { | 225 | } else { |
233 | struct wlr_box box; | 226 | struct wlr_box box; |
234 | container_get_box(workspace, &box); | 227 | workspace_get_box(workspace, &box); |
235 | arrange_children(workspace->children, workspace->layout, &box); | 228 | arrange_children(workspace->tiling, workspace->layout, &box); |
236 | arrange_floating(workspace->sway_workspace->floating); | 229 | arrange_floating(workspace->floating); |
237 | } | 230 | } |
238 | } | 231 | } |
239 | 232 | ||
240 | void arrange_output(struct sway_container *output) { | 233 | void arrange_output(struct sway_output *output) { |
241 | if (config->reloading) { | 234 | if (config->reloading) { |
242 | return; | 235 | return; |
243 | } | 236 | } |
244 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 237 | // Outputs have no pending x/y/width/height, |
245 | return; | 238 | // so all we do here is arrange the workspaces. |
246 | } | 239 | for (int i = 0; i < output->workspaces->length; ++i) { |
247 | const struct wlr_box *output_box = wlr_output_layout_get_box( | 240 | struct sway_workspace *workspace = output->workspaces->items[i]; |
248 | root_container.sway_root->output_layout, | ||
249 | output->sway_output->wlr_output); | ||
250 | output->x = output_box->x; | ||
251 | output->y = output_box->y; | ||
252 | output->width = output_box->width; | ||
253 | output->height = output_box->height; | ||
254 | container_set_dirty(output); | ||
255 | wlr_log(WLR_DEBUG, "Arranging output '%s' at %f,%f", | ||
256 | output->name, output->x, output->y); | ||
257 | for (int i = 0; i < output->children->length; ++i) { | ||
258 | struct sway_container *workspace = output->children->items[i]; | ||
259 | arrange_workspace(workspace); | 241 | arrange_workspace(workspace); |
260 | } | 242 | } |
261 | } | 243 | } |
@@ -264,37 +246,31 @@ void arrange_root(void) { | |||
264 | if (config->reloading) { | 246 | if (config->reloading) { |
265 | return; | 247 | return; |
266 | } | 248 | } |
267 | struct wlr_output_layout *output_layout = | ||
268 | root_container.sway_root->output_layout; | ||
269 | const struct wlr_box *layout_box = | 249 | const struct wlr_box *layout_box = |
270 | wlr_output_layout_get_box(output_layout, NULL); | 250 | wlr_output_layout_get_box(root->output_layout, NULL); |
271 | root_container.x = layout_box->x; | 251 | root->x = layout_box->x; |
272 | root_container.y = layout_box->y; | 252 | root->y = layout_box->y; |
273 | root_container.width = layout_box->width; | 253 | root->width = layout_box->width; |
274 | root_container.height = layout_box->height; | 254 | root->height = layout_box->height; |
275 | container_set_dirty(&root_container); | 255 | for (int i = 0; i < root->outputs->length; ++i) { |
276 | for (int i = 0; i < root_container.children->length; ++i) { | 256 | struct sway_output *output = root->outputs->items[i]; |
277 | struct sway_container *output = root_container.children->items[i]; | ||
278 | arrange_output(output); | 257 | arrange_output(output); |
279 | } | 258 | } |
280 | } | 259 | } |
281 | 260 | ||
282 | void arrange_windows(struct sway_container *container) { | 261 | void arrange_node(struct sway_node *node) { |
283 | switch (container->type) { | 262 | switch (node->type) { |
284 | case C_ROOT: | 263 | case N_ROOT: |
285 | arrange_root(); | 264 | arrange_root(); |
286 | break; | 265 | break; |
287 | case C_OUTPUT: | 266 | case N_OUTPUT: |
288 | arrange_output(container); | 267 | arrange_output(node->sway_output); |
289 | break; | ||
290 | case C_WORKSPACE: | ||
291 | arrange_workspace(container); | ||
292 | break; | 268 | break; |
293 | case C_CONTAINER: | 269 | case N_WORKSPACE: |
294 | case C_VIEW: | 270 | arrange_workspace(node->sway_workspace); |
295 | arrange_container(container); | ||
296 | break; | 271 | break; |
297 | case C_TYPES: | 272 | case N_CONTAINER: |
273 | arrange_container(node->sway_container); | ||
298 | break; | 274 | break; |
299 | } | 275 | } |
300 | } | 276 | } |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 520b4566..0cb8d0a5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -24,97 +24,39 @@ | |||
24 | #include "log.h" | 24 | #include "log.h" |
25 | #include "stringop.h" | 25 | #include "stringop.h" |
26 | 26 | ||
27 | const char *container_type_to_str(enum sway_container_type type) { | 27 | struct sway_container *container_create(struct sway_view *view) { |
28 | switch (type) { | ||
29 | case C_ROOT: | ||
30 | return "C_ROOT"; | ||
31 | case C_OUTPUT: | ||
32 | return "C_OUTPUT"; | ||
33 | case C_WORKSPACE: | ||
34 | return "C_WORKSPACE"; | ||
35 | case C_CONTAINER: | ||
36 | return "C_CONTAINER"; | ||
37 | case C_VIEW: | ||
38 | return "C_VIEW"; | ||
39 | default: | ||
40 | return "C_UNKNOWN"; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | void container_create_notify(struct sway_container *container) { | ||
45 | if (container->type == C_VIEW) { | ||
46 | ipc_event_window(container, "new"); | ||
47 | } else if (container->type == C_WORKSPACE) { | ||
48 | ipc_event_workspace(NULL, container, "init"); | ||
49 | } | ||
50 | wl_signal_emit(&root_container.sway_root->events.new_container, container); | ||
51 | } | ||
52 | |||
53 | void container_update_textures_recursive(struct sway_container *con) { | ||
54 | if (con->type == C_CONTAINER || con->type == C_VIEW) { | ||
55 | container_update_title_textures(con); | ||
56 | } | ||
57 | |||
58 | if (con->type == C_VIEW) { | ||
59 | view_update_marks_textures(con->sway_view); | ||
60 | } else { | ||
61 | for (int i = 0; i < con->children->length; ++i) { | ||
62 | struct sway_container *child = con->children->items[i]; | ||
63 | container_update_textures_recursive(child); | ||
64 | } | ||
65 | |||
66 | if (con->type == C_WORKSPACE) { | ||
67 | for (int i = 0; i < con->sway_workspace->floating->length; ++i) { | ||
68 | struct sway_container *floater = | ||
69 | con->sway_workspace->floating->items[i]; | ||
70 | container_update_textures_recursive(floater); | ||
71 | } | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | |||
76 | struct sway_container *container_create(enum sway_container_type type) { | ||
77 | // next id starts at 1 because 0 is assigned to root_container in layout.c | ||
78 | static size_t next_id = 1; | ||
79 | struct sway_container *c = calloc(1, sizeof(struct sway_container)); | 28 | struct sway_container *c = calloc(1, sizeof(struct sway_container)); |
80 | if (!c) { | 29 | if (!c) { |
30 | wlr_log(WLR_ERROR, "Unable to allocate sway_container"); | ||
81 | return NULL; | 31 | return NULL; |
82 | } | 32 | } |
83 | c->id = next_id++; | 33 | node_init(&c->node, N_CONTAINER, c); |
84 | c->layout = L_NONE; | 34 | c->layout = L_NONE; |
85 | c->type = type; | 35 | c->view = view; |
86 | c->alpha = 1.0f; | 36 | c->alpha = 1.0f; |
87 | 37 | ||
88 | if (type != C_VIEW) { | 38 | if (!view) { |
89 | c->children = create_list(); | 39 | c->children = create_list(); |
90 | c->current.children = create_list(); | 40 | c->current.children = create_list(); |
91 | } | 41 | } |
92 | c->outputs = create_list(); | 42 | c->outputs = create_list(); |
93 | 43 | ||
94 | wl_signal_init(&c->events.destroy); | 44 | wl_signal_init(&c->events.destroy); |
95 | 45 | wl_signal_emit(&root->events.new_node, &c->node); | |
96 | c->has_gaps = false; | ||
97 | c->gaps_inner = 0; | ||
98 | c->gaps_outer = 0; | ||
99 | c->current_gaps = 0; | ||
100 | 46 | ||
101 | return c; | 47 | return c; |
102 | } | 48 | } |
103 | 49 | ||
104 | void container_destroy(struct sway_container *con) { | 50 | void container_destroy(struct sway_container *con) { |
105 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, | 51 | if (!sway_assert(con->node.destroying, |
106 | "Expected a container or view")) { | ||
107 | return; | ||
108 | } | ||
109 | if (!sway_assert(con->destroying, | ||
110 | "Tried to free container which wasn't marked as destroying")) { | 52 | "Tried to free container which wasn't marked as destroying")) { |
111 | return; | 53 | return; |
112 | } | 54 | } |
113 | if (!sway_assert(con->ntxnrefs == 0, "Tried to free container " | 55 | if (!sway_assert(con->node.ntxnrefs == 0, "Tried to free container " |
114 | "which is still referenced by transactions")) { | 56 | "which is still referenced by transactions")) { |
115 | return; | 57 | return; |
116 | } | 58 | } |
117 | free(con->name); | 59 | free(con->title); |
118 | free(con->formatted_title); | 60 | free(con->formatted_title); |
119 | wlr_texture_destroy(con->title_focused); | 61 | wlr_texture_destroy(con->title_focused); |
120 | wlr_texture_destroy(con->title_focused_inactive); | 62 | wlr_texture_destroy(con->title_focused_inactive); |
@@ -124,14 +66,14 @@ void container_destroy(struct sway_container *con) { | |||
124 | list_free(con->current.children); | 66 | list_free(con->current.children); |
125 | list_free(con->outputs); | 67 | list_free(con->outputs); |
126 | 68 | ||
127 | if (con->type == C_VIEW) { | 69 | if (con->view) { |
128 | struct sway_view *view = con->sway_view; | 70 | struct sway_view *view = con->view; |
129 | view->swayc = NULL; | 71 | view->container = NULL; |
130 | free(view->title_format); | 72 | free(view->title_format); |
131 | view->title_format = NULL; | 73 | view->title_format = NULL; |
132 | 74 | ||
133 | if (view->destroying) { | 75 | if (view->destroying) { |
134 | view_destroy(view); | 76 | view_destroy(con->view); |
135 | } | 77 | } |
136 | } | 78 | } |
137 | 79 | ||
@@ -139,115 +81,57 @@ void container_destroy(struct sway_container *con) { | |||
139 | } | 81 | } |
140 | 82 | ||
141 | void container_begin_destroy(struct sway_container *con) { | 83 | void container_begin_destroy(struct sway_container *con) { |
142 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, | 84 | if (con->view) { |
143 | "Expected a container or view")) { | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | if (con->type == C_VIEW) { | ||
148 | ipc_event_window(con, "close"); | 85 | ipc_event_window(con, "close"); |
149 | } | 86 | } |
150 | wl_signal_emit(&con->events.destroy, con); | 87 | wl_signal_emit(&con->node.events.destroy, &con->node); |
151 | 88 | ||
152 | container_end_mouse_operation(con); | 89 | container_end_mouse_operation(con); |
153 | 90 | ||
154 | con->destroying = true; | 91 | con->node.destroying = true; |
155 | container_set_dirty(con); | 92 | node_set_dirty(&con->node); |
156 | 93 | ||
157 | if (con->scratchpad) { | 94 | if (con->scratchpad) { |
158 | root_scratchpad_remove_container(con); | 95 | root_scratchpad_remove_container(con); |
159 | } | 96 | } |
160 | 97 | ||
161 | if (con->parent) { | 98 | if (con->parent || con->workspace) { |
162 | container_remove_child(con); | 99 | container_detach(con); |
163 | } | 100 | } |
164 | } | 101 | } |
165 | 102 | ||
166 | struct sway_container *container_reap_empty(struct sway_container *con) { | 103 | void container_reap_empty(struct sway_container *con) { |
167 | while (con && con->type == C_CONTAINER) { | 104 | if (con->view) { |
168 | struct sway_container *next = con->parent; | 105 | return; |
169 | if (con->children->length == 0) { | ||
170 | container_begin_destroy(con); | ||
171 | } | ||
172 | con = next; | ||
173 | } | 106 | } |
174 | if (con && con->type == C_WORKSPACE) { | 107 | struct sway_workspace *ws = con->workspace; |
175 | workspace_consider_destroy(con); | 108 | while (con) { |
176 | if (con->destroying) { | 109 | if (con->children->length) { |
177 | con = con->parent; | 110 | return; |
178 | } | 111 | } |
112 | struct sway_container *parent = con->parent; | ||
113 | container_begin_destroy(con); | ||
114 | con = parent; | ||
179 | } | 115 | } |
180 | return con; | 116 | workspace_consider_destroy(ws); |
181 | } | 117 | } |
182 | 118 | ||
183 | struct sway_container *container_flatten(struct sway_container *container) { | 119 | struct sway_container *container_flatten(struct sway_container *container) { |
184 | while (container->type == C_CONTAINER && container->children->length == 1) { | 120 | if (container->view) { |
121 | return NULL; | ||
122 | } | ||
123 | while (container && container->children->length == 1) { | ||
185 | struct sway_container *child = container->children->items[0]; | 124 | struct sway_container *child = container->children->items[0]; |
186 | struct sway_container *parent = container->parent; | 125 | struct sway_container *parent = container->parent; |
187 | container_replace_child(container, child); | 126 | container_replace(container, child); |
188 | container_begin_destroy(container); | 127 | container_begin_destroy(container); |
189 | container = parent; | 128 | container = parent; |
190 | } | 129 | } |
191 | return container; | 130 | return container; |
192 | } | 131 | } |
193 | 132 | ||
194 | static void container_close_func(struct sway_container *container, void *data) { | ||
195 | if (container->type == C_VIEW) { | ||
196 | view_close(container->sway_view); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | struct sway_container *container_close(struct sway_container *con) { | ||
201 | if (!sway_assert(con != NULL, | ||
202 | "container_close called with a NULL container")) { | ||
203 | return NULL; | ||
204 | } | ||
205 | |||
206 | struct sway_container *parent = con->parent; | ||
207 | |||
208 | if (con->type == C_VIEW) { | ||
209 | view_close(con->sway_view); | ||
210 | } else if (con->type == C_CONTAINER) { | ||
211 | container_for_each_child(con, container_close_func, NULL); | ||
212 | } else if (con->type == C_WORKSPACE) { | ||
213 | workspace_for_each_container(con, container_close_func, NULL); | ||
214 | } | ||
215 | |||
216 | return parent; | ||
217 | } | ||
218 | |||
219 | struct sway_container *container_view_create(struct sway_container *sibling, | ||
220 | struct sway_view *sway_view) { | ||
221 | if (!sway_assert(sibling, | ||
222 | "container_view_create called with NULL sibling/parent")) { | ||
223 | return NULL; | ||
224 | } | ||
225 | const char *title = view_get_title(sway_view); | ||
226 | struct sway_container *swayc = container_create(C_VIEW); | ||
227 | wlr_log(WLR_DEBUG, "Adding new view %p:%s to container %p %d %s", | ||
228 | swayc, title, sibling, sibling ? sibling->type : 0, sibling->name); | ||
229 | // Setup values | ||
230 | swayc->sway_view = sway_view; | ||
231 | swayc->width = 0; | ||
232 | swayc->height = 0; | ||
233 | |||
234 | if (sibling->type == C_WORKSPACE) { | ||
235 | // Case of focused workspace, just create as child of it | ||
236 | container_add_child(sibling, swayc); | ||
237 | } else { | ||
238 | // Regular case, create as sibling of current container | ||
239 | container_add_sibling(sibling, swayc); | ||
240 | } | ||
241 | container_create_notify(swayc); | ||
242 | return swayc; | ||
243 | } | ||
244 | |||
245 | struct sway_container *container_find_child(struct sway_container *container, | 133 | struct sway_container *container_find_child(struct sway_container *container, |
246 | bool (*test)(struct sway_container *view, void *data), void *data) { | 134 | bool (*test)(struct sway_container *con, void *data), void *data) { |
247 | if (!sway_assert(container->type == C_CONTAINER || | ||
248 | container->type == C_VIEW, "Expected a container or view")) { | ||
249 | return NULL; | ||
250 | } | ||
251 | if (!container->children) { | 135 | if (!container->children) { |
252 | return NULL; | 136 | return NULL; |
253 | } | 137 | } |
@@ -264,46 +148,32 @@ struct sway_container *container_find_child(struct sway_container *container, | |||
264 | return NULL; | 148 | return NULL; |
265 | } | 149 | } |
266 | 150 | ||
267 | struct sway_container *container_parent(struct sway_container *container, | 151 | static void surface_at_view(struct sway_container *con, double lx, double ly, |
268 | enum sway_container_type type) { | ||
269 | if (!sway_assert(container, "container is NULL")) { | ||
270 | return NULL; | ||
271 | } | ||
272 | if (!sway_assert(type < C_TYPES && type >= C_ROOT, "invalid type")) { | ||
273 | return NULL; | ||
274 | } | ||
275 | do { | ||
276 | container = container->parent; | ||
277 | } while (container && container->type != type); | ||
278 | return container; | ||
279 | } | ||
280 | |||
281 | static void surface_at_view(struct sway_container *swayc, double lx, double ly, | ||
282 | struct wlr_surface **surface, double *sx, double *sy) { | 152 | struct wlr_surface **surface, double *sx, double *sy) { |
283 | if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { | 153 | if (!sway_assert(con->view, "Expected a view")) { |
284 | return; | 154 | return; |
285 | } | 155 | } |
286 | struct sway_view *sview = swayc->sway_view; | 156 | struct sway_view *view = con->view; |
287 | double view_sx = lx - sview->x + sview->geometry.x; | 157 | double view_sx = lx - view->x + view->geometry.x; |
288 | double view_sy = ly - sview->y + sview->geometry.y; | 158 | double view_sy = ly - view->y + view->geometry.y; |
289 | 159 | ||
290 | double _sx, _sy; | 160 | double _sx, _sy; |
291 | struct wlr_surface *_surface = NULL; | 161 | struct wlr_surface *_surface = NULL; |
292 | switch (sview->type) { | 162 | switch (view->type) { |
293 | #ifdef HAVE_XWAYLAND | 163 | #ifdef HAVE_XWAYLAND |
294 | case SWAY_VIEW_XWAYLAND: | 164 | case SWAY_VIEW_XWAYLAND: |
295 | _surface = wlr_surface_surface_at(sview->surface, | 165 | _surface = wlr_surface_surface_at(view->surface, |
296 | view_sx, view_sy, &_sx, &_sy); | 166 | view_sx, view_sy, &_sx, &_sy); |
297 | break; | 167 | break; |
298 | #endif | 168 | #endif |
299 | case SWAY_VIEW_XDG_SHELL_V6: | 169 | case SWAY_VIEW_XDG_SHELL_V6: |
300 | _surface = wlr_xdg_surface_v6_surface_at( | 170 | _surface = wlr_xdg_surface_v6_surface_at( |
301 | sview->wlr_xdg_surface_v6, | 171 | view->wlr_xdg_surface_v6, |
302 | view_sx, view_sy, &_sx, &_sy); | 172 | view_sx, view_sy, &_sx, &_sy); |
303 | break; | 173 | break; |
304 | case SWAY_VIEW_XDG_SHELL: | 174 | case SWAY_VIEW_XDG_SHELL: |
305 | _surface = wlr_xdg_surface_surface_at( | 175 | _surface = wlr_xdg_surface_surface_at( |
306 | sview->wlr_xdg_surface, | 176 | view->wlr_xdg_surface, |
307 | view_sx, view_sy, &_sx, &_sy); | 177 | view_sx, view_sy, &_sx, &_sy); |
308 | break; | 178 | break; |
309 | } | 179 | } |
@@ -317,65 +187,72 @@ static void surface_at_view(struct sway_container *swayc, double lx, double ly, | |||
317 | /** | 187 | /** |
318 | * container_at for a container with layout L_TABBED. | 188 | * container_at for a container with layout L_TABBED. |
319 | */ | 189 | */ |
320 | static struct sway_container *container_at_tabbed(struct sway_container *parent, | 190 | static struct sway_container *container_at_tabbed(struct sway_node *parent, |
321 | double lx, double ly, | 191 | double lx, double ly, |
322 | struct wlr_surface **surface, double *sx, double *sy) { | 192 | struct wlr_surface **surface, double *sx, double *sy) { |
323 | if (ly < parent->y || ly > parent->y + parent->height) { | 193 | struct wlr_box box; |
194 | node_get_box(parent, &box); | ||
195 | if (ly < box.y || ly > box.y + box.height) { | ||
324 | return NULL; | 196 | return NULL; |
325 | } | 197 | } |
326 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 198 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
199 | list_t *children = node_get_children(parent); | ||
327 | 200 | ||
328 | // Tab titles | 201 | // Tab titles |
329 | int title_height = container_titlebar_height(); | 202 | int title_height = container_titlebar_height(); |
330 | if (ly < parent->y + title_height) { | 203 | if (ly < box.y + title_height) { |
331 | int tab_width = parent->width / parent->children->length; | 204 | int tab_width = box.width / children->length; |
332 | int child_index = (lx - parent->x) / tab_width; | 205 | int child_index = (lx - box.x) / tab_width; |
333 | if (child_index >= parent->children->length) { | 206 | if (child_index >= children->length) { |
334 | child_index = parent->children->length - 1; | 207 | child_index = children->length - 1; |
335 | } | 208 | } |
336 | struct sway_container *child = parent->children->items[child_index]; | 209 | struct sway_container *child = children->items[child_index]; |
337 | return seat_get_focus_inactive(seat, child); | 210 | struct sway_node *node = seat_get_focus_inactive(seat, &child->node); |
211 | return node->sway_container; | ||
338 | } | 212 | } |
339 | 213 | ||
340 | // Surfaces | 214 | // Surfaces |
341 | struct sway_container *current = seat_get_active_child(seat, parent); | 215 | struct sway_node *current = seat_get_active_child(seat, parent); |
342 | |||
343 | return tiling_container_at(current, lx, ly, surface, sx, sy); | 216 | return tiling_container_at(current, lx, ly, surface, sx, sy); |
344 | } | 217 | } |
345 | 218 | ||
346 | /** | 219 | /** |
347 | * container_at for a container with layout L_STACKED. | 220 | * container_at for a container with layout L_STACKED. |
348 | */ | 221 | */ |
349 | static struct sway_container *container_at_stacked( | 222 | static struct sway_container *container_at_stacked(struct sway_node *parent, |
350 | struct sway_container *parent, double lx, double ly, | 223 | double lx, double ly, |
351 | struct wlr_surface **surface, double *sx, double *sy) { | 224 | struct wlr_surface **surface, double *sx, double *sy) { |
352 | if (ly < parent->y || ly > parent->y + parent->height) { | 225 | struct wlr_box box; |
226 | node_get_box(parent, &box); | ||
227 | if (ly < box.y || ly > box.y + box.height) { | ||
353 | return NULL; | 228 | return NULL; |
354 | } | 229 | } |
355 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 230 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
231 | list_t *children = node_get_children(parent); | ||
356 | 232 | ||
357 | // Title bars | 233 | // Title bars |
358 | int title_height = container_titlebar_height(); | 234 | int title_height = container_titlebar_height(); |
359 | int child_index = (ly - parent->y) / title_height; | 235 | int child_index = (ly - box.y) / title_height; |
360 | if (child_index < parent->children->length) { | 236 | if (child_index < children->length) { |
361 | struct sway_container *child = parent->children->items[child_index]; | 237 | struct sway_container *child = children->items[child_index]; |
362 | return seat_get_focus_inactive(seat, child); | 238 | struct sway_node *node = seat_get_focus_inactive(seat, &child->node); |
239 | return node->sway_container; | ||
363 | } | 240 | } |
364 | 241 | ||
365 | // Surfaces | 242 | // Surfaces |
366 | struct sway_container *current = seat_get_active_child(seat, parent); | 243 | struct sway_node *current = seat_get_active_child(seat, parent); |
367 | |||
368 | return tiling_container_at(current, lx, ly, surface, sx, sy); | 244 | return tiling_container_at(current, lx, ly, surface, sx, sy); |
369 | } | 245 | } |
370 | 246 | ||
371 | /** | 247 | /** |
372 | * container_at for a container with layout L_HORIZ or L_VERT. | 248 | * container_at for a container with layout L_HORIZ or L_VERT. |
373 | */ | 249 | */ |
374 | static struct sway_container *container_at_linear(struct sway_container *parent, | 250 | static struct sway_container *container_at_linear(struct sway_node *parent, |
375 | double lx, double ly, | 251 | double lx, double ly, |
376 | struct wlr_surface **surface, double *sx, double *sy) { | 252 | struct wlr_surface **surface, double *sx, double *sy) { |
377 | for (int i = 0; i < parent->children->length; ++i) { | 253 | list_t *children = node_get_children(parent); |
378 | struct sway_container *child = parent->children->items[i]; | 254 | for (int i = 0; i < children->length; ++i) { |
255 | struct sway_container *child = children->items[i]; | ||
379 | struct wlr_box box = { | 256 | struct wlr_box box = { |
380 | .x = child->x, | 257 | .x = child->x, |
381 | .y = child->y, | 258 | .y = child->y, |
@@ -383,7 +260,7 @@ static struct sway_container *container_at_linear(struct sway_container *parent, | |||
383 | .height = child->height, | 260 | .height = child->height, |
384 | }; | 261 | }; |
385 | if (wlr_box_contains_point(&box, lx, ly)) { | 262 | if (wlr_box_contains_point(&box, lx, ly)) { |
386 | return tiling_container_at(child, lx, ly, surface, sx, sy); | 263 | return tiling_container_at(&child->node, lx, ly, surface, sx, sy); |
387 | } | 264 | } |
388 | } | 265 | } |
389 | return NULL; | 266 | return NULL; |
@@ -391,12 +268,11 @@ static struct sway_container *container_at_linear(struct sway_container *parent, | |||
391 | 268 | ||
392 | static struct sway_container *floating_container_at(double lx, double ly, | 269 | static struct sway_container *floating_container_at(double lx, double ly, |
393 | struct wlr_surface **surface, double *sx, double *sy) { | 270 | struct wlr_surface **surface, double *sx, double *sy) { |
394 | for (int i = 0; i < root_container.children->length; ++i) { | 271 | for (int i = 0; i < root->outputs->length; ++i) { |
395 | struct sway_container *output = root_container.children->items[i]; | 272 | struct sway_output *output = root->outputs->items[i]; |
396 | for (int j = 0; j < output->children->length; ++j) { | 273 | for (int j = 0; j < output->workspaces->length; ++j) { |
397 | struct sway_container *workspace = output->children->items[j]; | 274 | struct sway_workspace *ws = output->workspaces->items[j]; |
398 | struct sway_workspace *ws = workspace->sway_workspace; | 275 | if (!workspace_is_visible(ws)) { |
399 | if (!workspace_is_visible(workspace)) { | ||
400 | continue; | 276 | continue; |
401 | } | 277 | } |
402 | // Items at the end of the list are on top, so iterate the list in | 278 | // Items at the end of the list are on top, so iterate the list in |
@@ -410,7 +286,7 @@ static struct sway_container *floating_container_at(double lx, double ly, | |||
410 | .height = floater->height, | 286 | .height = floater->height, |
411 | }; | 287 | }; |
412 | if (wlr_box_contains_point(&box, lx, ly)) { | 288 | if (wlr_box_contains_point(&box, lx, ly)) { |
413 | return tiling_container_at(floater, lx, ly, | 289 | return tiling_container_at(&floater->node, lx, ly, |
414 | surface, sx, sy); | 290 | surface, sx, sy); |
415 | } | 291 | } |
416 | } | 292 | } |
@@ -419,25 +295,24 @@ static struct sway_container *floating_container_at(double lx, double ly, | |||
419 | return NULL; | 295 | return NULL; |
420 | } | 296 | } |
421 | 297 | ||
422 | struct sway_container *tiling_container_at( | 298 | struct sway_container *tiling_container_at(struct sway_node *parent, |
423 | struct sway_container *con, double lx, double ly, | 299 | double lx, double ly, |
424 | struct wlr_surface **surface, double *sx, double *sy) { | 300 | struct wlr_surface **surface, double *sx, double *sy) { |
425 | if (con->type == C_VIEW) { | 301 | if (node_is_view(parent)) { |
426 | surface_at_view(con, lx, ly, surface, sx, sy); | 302 | surface_at_view(parent->sway_container, lx, ly, surface, sx, sy); |
427 | return con; | 303 | return parent->sway_container; |
428 | } | 304 | } |
429 | if (!con->children->length) { | 305 | if (!node_get_children(parent)) { |
430 | return NULL; | 306 | return NULL; |
431 | } | 307 | } |
432 | 308 | switch (node_get_layout(parent)) { | |
433 | switch (con->layout) { | ||
434 | case L_HORIZ: | 309 | case L_HORIZ: |
435 | case L_VERT: | 310 | case L_VERT: |
436 | return container_at_linear(con, lx, ly, surface, sx, sy); | 311 | return container_at_linear(parent, lx, ly, surface, sx, sy); |
437 | case L_TABBED: | 312 | case L_TABBED: |
438 | return container_at_tabbed(con, lx, ly, surface, sx, sy); | 313 | return container_at_tabbed(parent, lx, ly, surface, sx, sy); |
439 | case L_STACKED: | 314 | case L_STACKED: |
440 | return container_at_stacked(con, lx, ly, surface, sx, sy); | 315 | return container_at_stacked(parent, lx, ly, surface, sx, sy); |
441 | case L_NONE: | 316 | case L_NONE: |
442 | return NULL; | 317 | return NULL; |
443 | } | 318 | } |
@@ -472,19 +347,16 @@ static bool surface_is_popup(struct wlr_surface *surface) { | |||
472 | return false; | 347 | return false; |
473 | } | 348 | } |
474 | 349 | ||
475 | struct sway_container *container_at(struct sway_container *workspace, | 350 | struct sway_container *container_at(struct sway_workspace *workspace, |
476 | double lx, double ly, | 351 | double lx, double ly, |
477 | struct wlr_surface **surface, double *sx, double *sy) { | 352 | struct wlr_surface **surface, double *sx, double *sy) { |
478 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | ||
479 | return NULL; | ||
480 | } | ||
481 | struct sway_container *c; | 353 | struct sway_container *c; |
354 | // Focused view's popups | ||
482 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 355 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
483 | struct sway_container *focus = | 356 | struct sway_container *focus = seat_get_focused_container(seat); |
484 | seat_get_focus_inactive(seat, &root_container); | ||
485 | bool is_floating = focus && container_is_floating_or_child(focus); | 357 | bool is_floating = focus && container_is_floating_or_child(focus); |
486 | // Focused view's popups | 358 | // Focused view's popups |
487 | if (focus && focus->type == C_VIEW) { | 359 | if (focus && focus->view) { |
488 | surface_at_view(focus, lx, ly, surface, sx, sy); | 360 | surface_at_view(focus, lx, ly, surface, sx, sy); |
489 | if (*surface && surface_is_popup(*surface)) { | 361 | if (*surface && surface_is_popup(*surface)) { |
490 | return focus; | 362 | return focus; |
@@ -492,7 +364,7 @@ struct sway_container *container_at(struct sway_container *workspace, | |||
492 | *surface = NULL; | 364 | *surface = NULL; |
493 | } | 365 | } |
494 | // If focused is floating, focused view's non-popups | 366 | // If focused is floating, focused view's non-popups |
495 | if (focus && focus->type == C_VIEW && is_floating) { | 367 | if (focus && focus->view && is_floating) { |
496 | surface_at_view(focus, lx, ly, surface, sx, sy); | 368 | surface_at_view(focus, lx, ly, surface, sx, sy); |
497 | if (*surface) { | 369 | if (*surface) { |
498 | return focus; | 370 | return focus; |
@@ -504,7 +376,7 @@ struct sway_container *container_at(struct sway_container *workspace, | |||
504 | return c; | 376 | return c; |
505 | } | 377 | } |
506 | // If focused is tiling, focused view's non-popups | 378 | // If focused is tiling, focused view's non-popups |
507 | if (focus && focus->type == C_VIEW && !is_floating) { | 379 | if (focus && focus->view && !is_floating) { |
508 | surface_at_view(focus, lx, ly, surface, sx, sy); | 380 | surface_at_view(focus, lx, ly, surface, sx, sy); |
509 | if (*surface) { | 381 | if (*surface) { |
510 | return focus; | 382 | return focus; |
@@ -512,7 +384,7 @@ struct sway_container *container_at(struct sway_container *workspace, | |||
512 | *surface = NULL; | 384 | *surface = NULL; |
513 | } | 385 | } |
514 | // Tiling (non-focused) | 386 | // Tiling (non-focused) |
515 | if ((c = tiling_container_at(workspace, lx, ly, surface, sx, sy))) { | 387 | if ((c = tiling_container_at(&workspace->node, lx, ly, surface, sx, sy))) { |
516 | return c; | 388 | return c; |
517 | } | 389 | } |
518 | return NULL; | 390 | return NULL; |
@@ -521,10 +393,6 @@ struct sway_container *container_at(struct sway_container *workspace, | |||
521 | void container_for_each_child(struct sway_container *container, | 393 | void container_for_each_child(struct sway_container *container, |
522 | void (*f)(struct sway_container *container, void *data), | 394 | void (*f)(struct sway_container *container, void *data), |
523 | void *data) { | 395 | void *data) { |
524 | if (!sway_assert(container->type == C_CONTAINER || | ||
525 | container->type == C_VIEW, "Expected a container or view")) { | ||
526 | return; | ||
527 | } | ||
528 | if (container->children) { | 396 | if (container->children) { |
529 | for (int i = 0; i < container->children->length; ++i) { | 397 | for (int i = 0; i < container->children->length; ++i) { |
530 | struct sway_container *child = container->children->items[i]; | 398 | struct sway_container *child = container->children->items[i]; |
@@ -536,7 +404,7 @@ void container_for_each_child(struct sway_container *container, | |||
536 | 404 | ||
537 | bool container_has_ancestor(struct sway_container *descendant, | 405 | bool container_has_ancestor(struct sway_container *descendant, |
538 | struct sway_container *ancestor) { | 406 | struct sway_container *ancestor) { |
539 | while (descendant && descendant->type != C_ROOT) { | 407 | while (descendant) { |
540 | descendant = descendant->parent; | 408 | descendant = descendant->parent; |
541 | if (descendant == ancestor) { | 409 | if (descendant == ancestor) { |
542 | return true; | 410 | return true; |
@@ -545,27 +413,10 @@ bool container_has_ancestor(struct sway_container *descendant, | |||
545 | return false; | 413 | return false; |
546 | } | 414 | } |
547 | 415 | ||
548 | int container_count_descendants_of_type(struct sway_container *con, | ||
549 | enum sway_container_type type) { | ||
550 | int children = 0; | ||
551 | if (con->type == type) { | ||
552 | children++; | ||
553 | } | ||
554 | if (con->children) { | ||
555 | for (int i = 0; i < con->children->length; i++) { | ||
556 | struct sway_container *child = con->children->items[i]; | ||
557 | children += container_count_descendants_of_type(child, type); | ||
558 | } | ||
559 | } | ||
560 | return children; | ||
561 | } | ||
562 | |||
563 | void container_damage_whole(struct sway_container *container) { | 416 | void container_damage_whole(struct sway_container *container) { |
564 | for (int i = 0; i < root_container.children->length; ++i) { | 417 | for (int i = 0; i < root->outputs->length; ++i) { |
565 | struct sway_container *cont = root_container.children->items[i]; | 418 | struct sway_output *output = root->outputs->items[i]; |
566 | if (cont->type == C_OUTPUT) { | 419 | output_damage_whole_container(output, container); |
567 | output_damage_whole_container(cont->sway_output, container); | ||
568 | } | ||
569 | } | 420 | } |
570 | } | 421 | } |
571 | 422 | ||
@@ -582,10 +433,6 @@ struct sway_output *container_get_effective_output(struct sway_container *con) { | |||
582 | 433 | ||
583 | static void update_title_texture(struct sway_container *con, | 434 | static void update_title_texture(struct sway_container *con, |
584 | struct wlr_texture **texture, struct border_colors *class) { | 435 | struct wlr_texture **texture, struct border_colors *class) { |
585 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, | ||
586 | "Unexpected type %s", container_type_to_str(con->type))) { | ||
587 | return; | ||
588 | } | ||
589 | struct sway_output *output = container_get_effective_output(con); | 436 | struct sway_output *output = container_get_effective_output(con); |
590 | if (!output) { | 437 | if (!output) { |
591 | return; | 438 | return; |
@@ -664,9 +511,10 @@ void container_calculate_title_height(struct sway_container *container) { | |||
664 | * An example tree representation is: V[Terminal, Firefox] | 511 | * An example tree representation is: V[Terminal, Firefox] |
665 | * If buffer is not NULL, also populate the buffer with the representation. | 512 | * If buffer is not NULL, also populate the buffer with the representation. |
666 | */ | 513 | */ |
667 | static size_t get_tree_representation(struct sway_container *parent, char *buffer) { | 514 | size_t container_build_representation(enum sway_container_layout layout, |
515 | list_t *children, char *buffer) { | ||
668 | size_t len = 2; | 516 | size_t len = 2; |
669 | switch (parent->layout) { | 517 | switch (layout) { |
670 | case L_VERT: | 518 | case L_VERT: |
671 | lenient_strcat(buffer, "V["); | 519 | lenient_strcat(buffer, "V["); |
672 | break; | 520 | break; |
@@ -683,17 +531,17 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe | |||
683 | lenient_strcat(buffer, "D["); | 531 | lenient_strcat(buffer, "D["); |
684 | break; | 532 | break; |
685 | } | 533 | } |
686 | for (int i = 0; i < parent->children->length; ++i) { | 534 | for (int i = 0; i < children->length; ++i) { |
687 | if (i != 0) { | 535 | if (i != 0) { |
688 | ++len; | 536 | ++len; |
689 | lenient_strcat(buffer, " "); | 537 | lenient_strcat(buffer, " "); |
690 | } | 538 | } |
691 | struct sway_container *child = parent->children->items[i]; | 539 | struct sway_container *child = children->items[i]; |
692 | const char *identifier = NULL; | 540 | const char *identifier = NULL; |
693 | if (child->type == C_VIEW) { | 541 | if (child->view) { |
694 | identifier = view_get_class(child->sway_view); | 542 | identifier = view_get_class(child->view); |
695 | if (!identifier) { | 543 | if (!identifier) { |
696 | identifier = view_get_app_id(child->sway_view); | 544 | identifier = view_get_app_id(child->view); |
697 | } | 545 | } |
698 | } else { | 546 | } else { |
699 | identifier = child->formatted_title; | 547 | identifier = child->formatted_title; |
@@ -711,25 +559,25 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe | |||
711 | return len; | 559 | return len; |
712 | } | 560 | } |
713 | 561 | ||
714 | void container_notify_subtree_changed(struct sway_container *container) { | 562 | void container_update_representation(struct sway_container *con) { |
715 | if (!container || container->type < C_WORKSPACE) { | 563 | if (!con->view) { |
716 | return; | 564 | size_t len = container_build_representation(con->layout, |
717 | } | 565 | con->children, NULL); |
718 | free(container->formatted_title); | 566 | free(con->formatted_title); |
719 | container->formatted_title = NULL; | 567 | con->formatted_title = calloc(len + 1, sizeof(char)); |
720 | 568 | if (!sway_assert(con->formatted_title, | |
721 | size_t len = get_tree_representation(container, NULL); | 569 | "Unable to allocate title string")) { |
722 | char *buffer = calloc(len + 1, sizeof(char)); | 570 | return; |
723 | if (!sway_assert(buffer, "Unable to allocate title string")) { | 571 | } |
724 | return; | 572 | container_build_representation(con->layout, con->children, |
573 | con->formatted_title); | ||
574 | container_calculate_title_height(con); | ||
575 | container_update_title_textures(con); | ||
725 | } | 576 | } |
726 | get_tree_representation(container, buffer); | 577 | if (con->parent) { |
727 | 578 | container_update_representation(con->parent); | |
728 | container->formatted_title = buffer; | 579 | } else if (con->workspace) { |
729 | if (container->type != C_WORKSPACE) { | 580 | workspace_update_representation(con->workspace); |
730 | container_calculate_title_height(container); | ||
731 | container_update_title_textures(container); | ||
732 | container_notify_subtree_changed(container->parent); | ||
733 | } | 581 | } |
734 | } | 582 | } |
735 | 583 | ||
@@ -738,11 +586,7 @@ size_t container_titlebar_height() { | |||
738 | } | 586 | } |
739 | 587 | ||
740 | void container_init_floating(struct sway_container *con) { | 588 | void container_init_floating(struct sway_container *con) { |
741 | if (!sway_assert(con->type == C_VIEW || con->type == C_CONTAINER, | 589 | struct sway_workspace *ws = con->workspace; |
742 | "Expected a view or container")) { | ||
743 | return; | ||
744 | } | ||
745 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | ||
746 | int min_width, min_height; | 590 | int min_width, min_height; |
747 | int max_width, max_height; | 591 | int max_width, max_height; |
748 | 592 | ||
@@ -778,13 +622,13 @@ void container_init_floating(struct sway_container *con) { | |||
778 | max_height = config->floating_maximum_height; | 622 | max_height = config->floating_maximum_height; |
779 | } | 623 | } |
780 | 624 | ||
781 | if (con->type == C_CONTAINER) { | 625 | if (!con->view) { |
782 | con->width = max_width; | 626 | con->width = max_width; |
783 | con->height = max_height; | 627 | con->height = max_height; |
784 | con->x = ws->x + (ws->width - con->width) / 2; | 628 | con->x = ws->x + (ws->width - con->width) / 2; |
785 | con->y = ws->y + (ws->height - con->height) / 2; | 629 | con->y = ws->y + (ws->height - con->height) / 2; |
786 | } else { | 630 | } else { |
787 | struct sway_view *view = con->sway_view; | 631 | struct sway_view *view = con->view; |
788 | view->width = fmax(min_width, fmin(view->natural_width, max_width)); | 632 | view->width = fmax(min_width, fmin(view->natural_width, max_width)); |
789 | view->height = fmax(min_height, fmin(view->natural_height, max_height)); | 633 | view->height = fmax(min_height, fmin(view->natural_height, max_height)); |
790 | view->x = ws->x + (ws->width - view->width) / 2; | 634 | view->x = ws->x + (ws->width - view->width) / 2; |
@@ -794,7 +638,7 @@ void container_init_floating(struct sway_container *con) { | |||
794 | view->border_top = view->border_bottom = true; | 638 | view->border_top = view->border_bottom = true; |
795 | view->border_left = view->border_right = true; | 639 | view->border_left = view->border_right = true; |
796 | 640 | ||
797 | container_set_geometry_from_floating_view(view->swayc); | 641 | container_set_geometry_from_floating_view(con); |
798 | } | 642 | } |
799 | } | 643 | } |
800 | 644 | ||
@@ -804,32 +648,41 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
804 | } | 648 | } |
805 | 649 | ||
806 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 650 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
807 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | 651 | struct sway_workspace *workspace = container->workspace; |
808 | 652 | ||
809 | if (enable) { | 653 | if (enable) { |
810 | struct sway_container *old_parent = container_remove_child(container); | 654 | struct sway_container *old_parent = container->parent; |
655 | container_detach(container); | ||
811 | workspace_add_floating(workspace, container); | 656 | workspace_add_floating(workspace, container); |
812 | container_init_floating(container); | 657 | container_init_floating(container); |
813 | if (container->type == C_VIEW) { | 658 | if (container->view) { |
814 | view_set_tiled(container->sway_view, false); | 659 | view_set_tiled(container->view, false); |
660 | } | ||
661 | if (old_parent) { | ||
662 | container_reap_empty(old_parent); | ||
815 | } | 663 | } |
816 | container_reap_empty(old_parent); | ||
817 | } else { | 664 | } else { |
818 | // Returning to tiled | 665 | // Returning to tiled |
819 | if (container->scratchpad) { | 666 | if (container->scratchpad) { |
820 | root_scratchpad_remove_container(container); | 667 | root_scratchpad_remove_container(container); |
821 | } | 668 | } |
822 | container_remove_child(container); | 669 | container_detach(container); |
823 | struct sway_container *reference = | 670 | struct sway_container *reference = |
824 | seat_get_focus_inactive_tiling(seat, workspace); | 671 | seat_get_focus_inactive_tiling(seat, workspace); |
825 | if (reference->type == C_VIEW) { | 672 | if (reference && reference->view) { |
826 | reference = reference->parent; | 673 | reference = reference->parent; |
827 | } | 674 | } |
828 | container_add_child(reference, container); | 675 | if (reference) { |
829 | container->width = container->parent->width; | 676 | container_add_child(reference, container); |
830 | container->height = container->parent->height; | 677 | container->width = reference->width; |
831 | if (container->type == C_VIEW) { | 678 | container->height = reference->height; |
832 | view_set_tiled(container->sway_view, true); | 679 | } else { |
680 | workspace_add_tiling(workspace, container); | ||
681 | container->width = workspace->width; | ||
682 | container->height = workspace->height; | ||
683 | } | ||
684 | if (container->view) { | ||
685 | view_set_tiled(container->view, true); | ||
833 | } | 686 | } |
834 | container->is_sticky = false; | 687 | container->is_sticky = false; |
835 | } | 688 | } |
@@ -840,14 +693,13 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
840 | } | 693 | } |
841 | 694 | ||
842 | void container_set_geometry_from_floating_view(struct sway_container *con) { | 695 | void container_set_geometry_from_floating_view(struct sway_container *con) { |
843 | if (!sway_assert(con->type == C_VIEW, "Expected a view")) { | 696 | if (!sway_assert(con->view, "Expected a view")) { |
844 | return; | 697 | return; |
845 | } | 698 | } |
846 | if (!sway_assert(container_is_floating(con), | 699 | if (!sway_assert(container_is_floating(con), "Expected a floating view")) { |
847 | "Expected a floating view")) { | ||
848 | return; | 700 | return; |
849 | } | 701 | } |
850 | struct sway_view *view = con->sway_view; | 702 | struct sway_view *view = con->view; |
851 | size_t border_width = 0; | 703 | size_t border_width = 0; |
852 | size_t top = 0; | 704 | size_t top = 0; |
853 | 705 | ||
@@ -861,12 +713,12 @@ void container_set_geometry_from_floating_view(struct sway_container *con) { | |||
861 | con->y = view->y - top; | 713 | con->y = view->y - top; |
862 | con->width = view->width + border_width * 2; | 714 | con->width = view->width + border_width * 2; |
863 | con->height = top + view->height + border_width; | 715 | con->height = top + view->height + border_width; |
864 | container_set_dirty(con); | 716 | node_set_dirty(&con->node); |
865 | } | 717 | } |
866 | 718 | ||
867 | bool container_is_floating(struct sway_container *container) { | 719 | bool container_is_floating(struct sway_container *container) { |
868 | return container->parent && container->parent->type == C_WORKSPACE && | 720 | return !container->parent && container->workspace && |
869 | list_find(container->parent->sway_workspace->floating, container) != -1; | 721 | list_find(container->workspace->floating, container) != -1; |
870 | } | 722 | } |
871 | 723 | ||
872 | void container_get_box(struct sway_container *container, struct wlr_box *box) { | 724 | void container_get_box(struct sway_container *container, struct wlr_box *box) { |
@@ -883,16 +735,16 @@ void container_floating_translate(struct sway_container *con, | |||
883 | double x_amount, double y_amount) { | 735 | double x_amount, double y_amount) { |
884 | con->x += x_amount; | 736 | con->x += x_amount; |
885 | con->y += y_amount; | 737 | con->y += y_amount; |
886 | if (con->type == C_VIEW) { | 738 | if (con->view) { |
887 | con->sway_view->x += x_amount; | 739 | con->view->x += x_amount; |
888 | con->sway_view->y += y_amount; | 740 | con->view->y += y_amount; |
889 | } else { | 741 | } else { |
890 | for (int i = 0; i < con->children->length; ++i) { | 742 | for (int i = 0; i < con->children->length; ++i) { |
891 | struct sway_container *child = con->children->items[i]; | 743 | struct sway_container *child = con->children->items[i]; |
892 | container_floating_translate(child, x_amount, y_amount); | 744 | container_floating_translate(child, x_amount, y_amount); |
893 | } | 745 | } |
894 | } | 746 | } |
895 | container_set_dirty(con); | 747 | node_set_dirty(&con->node); |
896 | } | 748 | } |
897 | 749 | ||
898 | /** | 750 | /** |
@@ -902,17 +754,16 @@ void container_floating_translate(struct sway_container *con, | |||
902 | * one, otherwise we'll choose whichever output is closest to the container's | 754 | * one, otherwise we'll choose whichever output is closest to the container's |
903 | * center. | 755 | * center. |
904 | */ | 756 | */ |
905 | struct sway_container *container_floating_find_output( | 757 | struct sway_output *container_floating_find_output(struct sway_container *con) { |
906 | struct sway_container *con) { | ||
907 | double center_x = con->x + con->width / 2; | 758 | double center_x = con->x + con->width / 2; |
908 | double center_y = con->y + con->height / 2; | 759 | double center_y = con->y + con->height / 2; |
909 | struct sway_container *closest_output = NULL; | 760 | struct sway_output *closest_output = NULL; |
910 | double closest_distance = DBL_MAX; | 761 | double closest_distance = DBL_MAX; |
911 | for (int i = 0; i < root_container.children->length; ++i) { | 762 | for (int i = 0; i < root->outputs->length; ++i) { |
912 | struct sway_container *output = root_container.children->items[i]; | 763 | struct sway_output *output = root->outputs->items[i]; |
913 | struct wlr_box output_box; | 764 | struct wlr_box output_box; |
914 | double closest_x, closest_y; | 765 | double closest_x, closest_y; |
915 | container_get_box(output, &output_box); | 766 | output_get_box(output, &output_box); |
916 | wlr_box_closest_point(&output_box, center_x, center_y, | 767 | wlr_box_closest_point(&output_box, center_x, center_y, |
917 | &closest_x, &closest_y); | 768 | &closest_x, &closest_y); |
918 | if (center_x == closest_x && center_y == closest_y) { | 769 | if (center_x == closest_x && center_y == closest_y) { |
@@ -937,18 +788,18 @@ void container_floating_move_to(struct sway_container *con, | |||
937 | return; | 788 | return; |
938 | } | 789 | } |
939 | container_floating_translate(con, lx - con->x, ly - con->y); | 790 | container_floating_translate(con, lx - con->x, ly - con->y); |
940 | struct sway_container *old_workspace = container_parent(con, C_WORKSPACE); | 791 | struct sway_workspace *old_workspace = con->workspace; |
941 | struct sway_container *new_output = container_floating_find_output(con); | 792 | struct sway_output *new_output = container_floating_find_output(con); |
942 | if (!sway_assert(new_output, "Unable to find any output")) { | 793 | if (!sway_assert(new_output, "Unable to find any output")) { |
943 | return; | 794 | return; |
944 | } | 795 | } |
945 | struct sway_container *new_workspace = | 796 | struct sway_workspace *new_workspace = |
946 | output_get_active_workspace(new_output->sway_output); | 797 | output_get_active_workspace(new_output); |
947 | if (old_workspace != new_workspace) { | 798 | if (old_workspace != new_workspace) { |
948 | container_remove_child(con); | 799 | container_detach(con); |
949 | workspace_add_floating(new_workspace, con); | 800 | workspace_add_floating(new_workspace, con); |
950 | arrange_windows(old_workspace); | 801 | arrange_workspace(old_workspace); |
951 | arrange_windows(new_workspace); | 802 | arrange_workspace(new_workspace); |
952 | workspace_detect_urgent(old_workspace); | 803 | workspace_detect_urgent(old_workspace); |
953 | workspace_detect_urgent(new_workspace); | 804 | workspace_detect_urgent(new_workspace); |
954 | } | 805 | } |
@@ -959,22 +810,14 @@ void container_floating_move_to_center(struct sway_container *con) { | |||
959 | "Expected a floating container")) { | 810 | "Expected a floating container")) { |
960 | return; | 811 | return; |
961 | } | 812 | } |
962 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 813 | struct sway_workspace *ws = con->workspace; |
963 | double new_lx = ws->x + (ws->width - con->width) / 2; | 814 | double new_lx = ws->x + (ws->width - con->width) / 2; |
964 | double new_ly = ws->y + (ws->height - con->height) / 2; | 815 | double new_ly = ws->y + (ws->height - con->height) / 2; |
965 | container_floating_translate(con, new_lx - con->x, new_ly - con->y); | 816 | container_floating_translate(con, new_lx - con->x, new_ly - con->y); |
966 | } | 817 | } |
967 | 818 | ||
968 | void container_set_dirty(struct sway_container *container) { | ||
969 | if (container->dirty) { | ||
970 | return; | ||
971 | } | ||
972 | container->dirty = true; | ||
973 | list_add(server.dirty_containers, container); | ||
974 | } | ||
975 | |||
976 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | 819 | static bool find_urgent_iterator(struct sway_container *con, void *data) { |
977 | return con->type == C_VIEW && view_is_urgent(con->sway_view); | 820 | return con->view && view_is_urgent(con->view); |
978 | } | 821 | } |
979 | 822 | ||
980 | bool container_has_urgent_child(struct sway_container *container) { | 823 | bool container_has_urgent_child(struct sway_container *container) { |
@@ -991,12 +834,12 @@ void container_end_mouse_operation(struct sway_container *container) { | |||
991 | } | 834 | } |
992 | 835 | ||
993 | static void set_fullscreen_iterator(struct sway_container *con, void *data) { | 836 | static void set_fullscreen_iterator(struct sway_container *con, void *data) { |
994 | if (con->type != C_VIEW) { | 837 | if (!con->view) { |
995 | return; | 838 | return; |
996 | } | 839 | } |
997 | if (con->sway_view->impl->set_fullscreen) { | 840 | if (con->view->impl->set_fullscreen) { |
998 | bool *enable = data; | 841 | bool *enable = data; |
999 | con->sway_view->impl->set_fullscreen(con->sway_view, *enable); | 842 | con->view->impl->set_fullscreen(con->view, *enable); |
1000 | } | 843 | } |
1001 | } | 844 | } |
1002 | 845 | ||
@@ -1005,9 +848,9 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { | |||
1005 | return; | 848 | return; |
1006 | } | 849 | } |
1007 | 850 | ||
1008 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | 851 | struct sway_workspace *workspace = container->workspace; |
1009 | if (enable && workspace->sway_workspace->fullscreen) { | 852 | if (enable && workspace->fullscreen) { |
1010 | container_set_fullscreen(workspace->sway_workspace->fullscreen, false); | 853 | container_set_fullscreen(workspace->fullscreen, false); |
1011 | } | 854 | } |
1012 | 855 | ||
1013 | set_fullscreen_iterator(container, &enable); | 856 | set_fullscreen_iterator(container, &enable); |
@@ -1016,36 +859,32 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { | |||
1016 | container->is_fullscreen = enable; | 859 | container->is_fullscreen = enable; |
1017 | 860 | ||
1018 | if (enable) { | 861 | if (enable) { |
1019 | workspace->sway_workspace->fullscreen = container; | 862 | workspace->fullscreen = container; |
1020 | container->saved_x = container->x; | 863 | container->saved_x = container->x; |
1021 | container->saved_y = container->y; | 864 | container->saved_y = container->y; |
1022 | container->saved_width = container->width; | 865 | container->saved_width = container->width; |
1023 | container->saved_height = container->height; | 866 | container->saved_height = container->height; |
1024 | 867 | ||
1025 | struct sway_seat *seat; | 868 | struct sway_seat *seat; |
1026 | struct sway_container *focus, *focus_ws; | 869 | struct sway_workspace *focus_ws; |
1027 | wl_list_for_each(seat, &input_manager->seats, link) { | 870 | wl_list_for_each(seat, &input_manager->seats, link) { |
1028 | focus = seat_get_focus(seat); | 871 | focus_ws = seat_get_focused_workspace(seat); |
1029 | if (focus) { | 872 | if (focus_ws) { |
1030 | focus_ws = focus; | ||
1031 | if (focus_ws->type != C_WORKSPACE) { | ||
1032 | focus_ws = container_parent(focus_ws, C_WORKSPACE); | ||
1033 | } | ||
1034 | if (focus_ws == workspace) { | 873 | if (focus_ws == workspace) { |
1035 | seat_set_focus(seat, container); | 874 | seat_set_focus(seat, &container->node); |
1036 | } | 875 | } |
1037 | } | 876 | } |
1038 | } | 877 | } |
1039 | } else { | 878 | } else { |
1040 | workspace->sway_workspace->fullscreen = NULL; | 879 | workspace->fullscreen = NULL; |
1041 | if (container_is_floating(container)) { | 880 | if (container_is_floating(container)) { |
1042 | container->x = container->saved_x; | 881 | container->x = container->saved_x; |
1043 | container->y = container->saved_y; | 882 | container->y = container->saved_y; |
1044 | container->width = container->saved_width; | 883 | container->width = container->saved_width; |
1045 | container->height = container->saved_height; | 884 | container->height = container->saved_height; |
1046 | struct sway_container *output = | 885 | struct sway_output *output = |
1047 | container_floating_find_output(container); | 886 | container_floating_find_output(container); |
1048 | if (!container_has_ancestor(container, output)) { | 887 | if (workspace->output != output) { |
1049 | container_floating_move_to_center(container); | 888 | container_floating_move_to_center(container); |
1050 | } | 889 | } |
1051 | } else { | 890 | } else { |
@@ -1060,7 +899,7 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { | |||
1060 | } | 899 | } |
1061 | 900 | ||
1062 | bool container_is_floating_or_child(struct sway_container *container) { | 901 | bool container_is_floating_or_child(struct sway_container *container) { |
1063 | while (container->parent && container->parent->type != C_WORKSPACE) { | 902 | while (container->parent) { |
1064 | container = container->parent; | 903 | container = container->parent; |
1065 | } | 904 | } |
1066 | return container_is_floating(container); | 905 | return container_is_floating(container); |
@@ -1072,7 +911,7 @@ bool container_is_fullscreen_or_child(struct sway_container *container) { | |||
1072 | return true; | 911 | return true; |
1073 | } | 912 | } |
1074 | container = container->parent; | 913 | container = container->parent; |
1075 | } while (container && container->type != C_WORKSPACE); | 914 | } while (container); |
1076 | 915 | ||
1077 | return false; | 916 | return false; |
1078 | } | 917 | } |
@@ -1090,42 +929,37 @@ static void surface_send_leave_iterator(struct wlr_surface *surface, | |||
1090 | } | 929 | } |
1091 | 930 | ||
1092 | void container_discover_outputs(struct sway_container *con) { | 931 | void container_discover_outputs(struct sway_container *con) { |
1093 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, | ||
1094 | "Expected a container or view")) { | ||
1095 | return; | ||
1096 | } | ||
1097 | struct wlr_box con_box = { | 932 | struct wlr_box con_box = { |
1098 | .x = con->current.swayc_x, | 933 | .x = con->current.con_x, |
1099 | .y = con->current.swayc_y, | 934 | .y = con->current.con_y, |
1100 | .width = con->current.swayc_width, | 935 | .width = con->current.con_width, |
1101 | .height = con->current.swayc_height, | 936 | .height = con->current.con_height, |
1102 | }; | 937 | }; |
1103 | struct sway_output *old_output = container_get_effective_output(con); | 938 | struct sway_output *old_output = container_get_effective_output(con); |
1104 | 939 | ||
1105 | for (int i = 0; i < root_container.children->length; ++i) { | 940 | for (int i = 0; i < root->outputs->length; ++i) { |
1106 | struct sway_container *output = root_container.children->items[i]; | 941 | struct sway_output *output = root->outputs->items[i]; |
1107 | struct sway_output *sway_output = output->sway_output; | ||
1108 | struct wlr_box output_box; | 942 | struct wlr_box output_box; |
1109 | container_get_box(output, &output_box); | 943 | output_get_box(output, &output_box); |
1110 | struct wlr_box intersection; | 944 | struct wlr_box intersection; |
1111 | bool intersects = | 945 | bool intersects = |
1112 | wlr_box_intersection(&con_box, &output_box, &intersection); | 946 | wlr_box_intersection(&con_box, &output_box, &intersection); |
1113 | int index = list_find(con->outputs, sway_output); | 947 | int index = list_find(con->outputs, output); |
1114 | 948 | ||
1115 | if (intersects && index == -1) { | 949 | if (intersects && index == -1) { |
1116 | // Send enter | 950 | // Send enter |
1117 | wlr_log(WLR_DEBUG, "Con %p entered output %p", con, sway_output); | 951 | wlr_log(WLR_DEBUG, "Container %p entered output %p", con, output); |
1118 | if (con->type == C_VIEW) { | 952 | if (con->view) { |
1119 | view_for_each_surface(con->sway_view, | 953 | view_for_each_surface(con->view, |
1120 | surface_send_enter_iterator, sway_output->wlr_output); | 954 | surface_send_enter_iterator, output->wlr_output); |
1121 | } | 955 | } |
1122 | list_add(con->outputs, sway_output); | 956 | list_add(con->outputs, output); |
1123 | } else if (!intersects && index != -1) { | 957 | } else if (!intersects && index != -1) { |
1124 | // Send leave | 958 | // Send leave |
1125 | wlr_log(WLR_DEBUG, "Con %p left output %p", con, sway_output); | 959 | wlr_log(WLR_DEBUG, "Container %p left output %p", con, output); |
1126 | if (con->type == C_VIEW) { | 960 | if (con->view) { |
1127 | view_for_each_surface(con->sway_view, | 961 | view_for_each_surface(con->view, |
1128 | surface_send_leave_iterator, sway_output->wlr_output); | 962 | surface_send_leave_iterator, output->wlr_output); |
1129 | } | 963 | } |
1130 | list_del(con->outputs, index); | 964 | list_del(con->outputs, index); |
1131 | } | 965 | } |
@@ -1135,17 +969,13 @@ void container_discover_outputs(struct sway_container *con) { | |||
1135 | double new_scale = new_output ? new_output->wlr_output->scale : -1; | 969 | double new_scale = new_output ? new_output->wlr_output->scale : -1; |
1136 | if (old_scale != new_scale) { | 970 | if (old_scale != new_scale) { |
1137 | container_update_title_textures(con); | 971 | container_update_title_textures(con); |
1138 | if (con->type == C_VIEW) { | 972 | if (con->view) { |
1139 | view_update_marks_textures(con->sway_view); | 973 | view_update_marks_textures(con->view); |
1140 | } | 974 | } |
1141 | } | 975 | } |
1142 | } | 976 | } |
1143 | 977 | ||
1144 | void container_remove_gaps(struct sway_container *c) { | 978 | void container_remove_gaps(struct sway_container *c) { |
1145 | if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW, | ||
1146 | "Expected a container or view")) { | ||
1147 | return; | ||
1148 | } | ||
1149 | if (c->current_gaps == 0) { | 979 | if (c->current_gaps == 0) { |
1150 | return; | 980 | return; |
1151 | } | 981 | } |
@@ -1158,25 +988,20 @@ void container_remove_gaps(struct sway_container *c) { | |||
1158 | } | 988 | } |
1159 | 989 | ||
1160 | void container_add_gaps(struct sway_container *c) { | 990 | void container_add_gaps(struct sway_container *c) { |
1161 | if (!sway_assert(c->type == C_CONTAINER || c->type == C_VIEW, | ||
1162 | "Expected a container or view")) { | ||
1163 | return; | ||
1164 | } | ||
1165 | if (c->current_gaps > 0) { | 991 | if (c->current_gaps > 0) { |
1166 | return; | 992 | return; |
1167 | } | 993 | } |
1168 | // Linear containers don't have gaps because it'd create double gaps | 994 | // Linear containers don't have gaps because it'd create double gaps |
1169 | if (c->type == C_CONTAINER && | 995 | if (!c->view && c->layout != L_TABBED && c->layout != L_STACKED) { |
1170 | c->layout != L_TABBED && c->layout != L_STACKED) { | ||
1171 | return; | 996 | return; |
1172 | } | 997 | } |
1173 | // Children of tabbed/stacked containers re-use the gaps of the container | 998 | // Children of tabbed/stacked containers re-use the gaps of the container |
1174 | enum sway_container_layout layout = c->parent->layout; | 999 | enum sway_container_layout layout = container_parent_layout(c); |
1175 | if (layout == L_TABBED || layout == L_STACKED) { | 1000 | if (layout == L_TABBED || layout == L_STACKED) { |
1176 | return; | 1001 | return; |
1177 | } | 1002 | } |
1178 | 1003 | ||
1179 | struct sway_container *ws = container_parent(c, C_WORKSPACE); | 1004 | struct sway_workspace *ws = c->workspace; |
1180 | 1005 | ||
1181 | c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner; | 1006 | c->current_gaps = ws->has_gaps ? ws->gaps_inner : config->gaps_inner; |
1182 | c->x += c->current_gaps; | 1007 | c->x += c->current_gaps; |
@@ -1185,222 +1010,154 @@ void container_add_gaps(struct sway_container *c) { | |||
1185 | c->height -= 2 * c->current_gaps; | 1010 | c->height -= 2 * c->current_gaps; |
1186 | } | 1011 | } |
1187 | 1012 | ||
1188 | int container_sibling_index(const struct sway_container *child) { | 1013 | enum sway_container_layout container_parent_layout(struct sway_container *con) { |
1189 | return list_find(child->parent->children, child); | 1014 | if (con->parent) { |
1015 | return con->parent->layout; | ||
1016 | } | ||
1017 | return con->workspace->layout; | ||
1190 | } | 1018 | } |
1191 | 1019 | ||
1192 | void container_handle_fullscreen_reparent(struct sway_container *con, | 1020 | enum sway_container_layout container_current_parent_layout( |
1193 | struct sway_container *old_parent) { | 1021 | struct sway_container *con) { |
1194 | if (!con->is_fullscreen) { | 1022 | if (con->current.parent) { |
1195 | return; | 1023 | return con->current.parent->current.layout; |
1196 | } | 1024 | } |
1197 | struct sway_container *old_workspace = old_parent; | 1025 | return con->current.workspace->current.layout; |
1198 | if (old_workspace && old_workspace->type != C_WORKSPACE) { | 1026 | } |
1199 | old_workspace = container_parent(old_workspace, C_WORKSPACE); | 1027 | |
1028 | list_t *container_get_siblings(const struct sway_container *container) { | ||
1029 | if (container->parent) { | ||
1030 | return container->parent->children; | ||
1200 | } | 1031 | } |
1201 | struct sway_container *new_workspace = container_parent(con, C_WORKSPACE); | 1032 | if (!container->workspace) { |
1202 | if (old_workspace == new_workspace) { | 1033 | return NULL; |
1203 | return; | ||
1204 | } | 1034 | } |
1205 | // Unmark the old workspace as fullscreen | 1035 | if (list_find(container->workspace->tiling, container) != -1) { |
1206 | if (old_workspace) { | 1036 | return container->workspace->tiling; |
1207 | old_workspace->sway_workspace->fullscreen = NULL; | ||
1208 | } | 1037 | } |
1038 | return container->workspace->floating; | ||
1039 | } | ||
1209 | 1040 | ||
1210 | // Mark the new workspace as fullscreen | 1041 | int container_sibling_index(const struct sway_container *child) { |
1211 | if (new_workspace->sway_workspace->fullscreen) { | 1042 | return list_find(container_get_siblings(child), child); |
1212 | container_set_fullscreen( | 1043 | } |
1213 | new_workspace->sway_workspace->fullscreen, false); | ||
1214 | } | ||
1215 | new_workspace->sway_workspace->fullscreen = con; | ||
1216 | 1044 | ||
1217 | // Resize container to new output dimensions | 1045 | list_t *container_get_current_siblings(struct sway_container *container) { |
1218 | struct sway_container *output = new_workspace->parent; | 1046 | if (container->current.parent) { |
1219 | con->x = output->x; | 1047 | return container->current.parent->current.children; |
1220 | con->y = output->y; | 1048 | } |
1221 | con->width = output->width; | 1049 | return container->current.workspace->current.tiling; |
1222 | con->height = output->height; | 1050 | } |
1223 | 1051 | ||
1224 | if (con->type == C_VIEW) { | 1052 | void container_handle_fullscreen_reparent(struct sway_container *con) { |
1225 | struct sway_view *view = con->sway_view; | 1053 | if (!con->is_fullscreen || con->workspace->fullscreen == con) { |
1226 | view->x = output->x; | 1054 | return; |
1227 | view->y = output->y; | ||
1228 | view->width = output->width; | ||
1229 | view->height = output->height; | ||
1230 | } else { | ||
1231 | arrange_windows(new_workspace); | ||
1232 | } | 1055 | } |
1056 | if (con->workspace->fullscreen) { | ||
1057 | container_set_fullscreen(con->workspace->fullscreen, false); | ||
1058 | } | ||
1059 | con->workspace->fullscreen = con; | ||
1060 | |||
1061 | arrange_workspace(con->workspace); | ||
1062 | } | ||
1063 | |||
1064 | static void set_workspace(struct sway_container *container, void *data) { | ||
1065 | container->workspace = container->parent->workspace; | ||
1233 | } | 1066 | } |
1234 | 1067 | ||
1235 | void container_insert_child(struct sway_container *parent, | 1068 | void container_insert_child(struct sway_container *parent, |
1236 | struct sway_container *child, int i) { | 1069 | struct sway_container *child, int i) { |
1237 | struct sway_container *old_parent = child->parent; | 1070 | if (child->workspace) { |
1238 | if (old_parent) { | 1071 | container_detach(child); |
1239 | container_remove_child(child); | ||
1240 | } | 1072 | } |
1241 | wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i); | ||
1242 | list_insert(parent->children, i, child); | 1073 | list_insert(parent->children, i, child); |
1243 | child->parent = parent; | 1074 | child->parent = parent; |
1244 | container_handle_fullscreen_reparent(child, old_parent); | 1075 | child->workspace = parent->workspace; |
1076 | container_for_each_child(child, set_workspace, NULL); | ||
1077 | container_handle_fullscreen_reparent(child); | ||
1078 | container_update_representation(parent); | ||
1245 | } | 1079 | } |
1246 | 1080 | ||
1247 | struct sway_container *container_add_sibling(struct sway_container *fixed, | 1081 | void container_add_sibling(struct sway_container *fixed, |
1248 | struct sway_container *active) { | 1082 | struct sway_container *active, int offset) { |
1249 | // TODO handle floating | 1083 | if (active->workspace) { |
1250 | struct sway_container *old_parent = NULL; | 1084 | container_detach(active); |
1251 | if (active->parent) { | 1085 | } |
1252 | old_parent = active->parent; | 1086 | list_t *siblings = container_get_siblings(fixed); |
1253 | container_remove_child(active); | 1087 | int index = list_find(siblings, fixed); |
1254 | } | 1088 | list_insert(siblings, index + offset, active); |
1255 | struct sway_container *parent = fixed->parent; | 1089 | active->parent = fixed->parent; |
1256 | int i = container_sibling_index(fixed); | 1090 | active->workspace = fixed->workspace; |
1257 | list_insert(parent->children, i + 1, active); | 1091 | container_for_each_child(active, set_workspace, NULL); |
1258 | active->parent = parent; | 1092 | container_handle_fullscreen_reparent(active); |
1259 | container_handle_fullscreen_reparent(active, old_parent); | 1093 | container_update_representation(active); |
1260 | return active->parent; | ||
1261 | } | 1094 | } |
1262 | 1095 | ||
1263 | void container_add_child(struct sway_container *parent, | 1096 | void container_add_child(struct sway_container *parent, |
1264 | struct sway_container *child) { | 1097 | struct sway_container *child) { |
1265 | wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", | 1098 | if (child->workspace) { |
1266 | child, child->type, child->width, child->height, | 1099 | container_detach(child); |
1267 | parent, parent->type, parent->width, parent->height); | 1100 | } |
1268 | struct sway_container *old_parent = child->parent; | ||
1269 | list_add(parent->children, child); | 1101 | list_add(parent->children, child); |
1270 | child->parent = parent; | 1102 | child->parent = parent; |
1271 | container_handle_fullscreen_reparent(child, old_parent); | 1103 | child->workspace = parent->workspace; |
1272 | if (old_parent) { | 1104 | container_for_each_child(child, set_workspace, NULL); |
1273 | container_set_dirty(old_parent); | 1105 | container_handle_fullscreen_reparent(child); |
1274 | } | 1106 | container_update_representation(parent); |
1275 | container_set_dirty(child); | 1107 | node_set_dirty(&child->node); |
1108 | node_set_dirty(&parent->node); | ||
1276 | } | 1109 | } |
1277 | 1110 | ||
1278 | struct sway_container *container_remove_child(struct sway_container *child) { | 1111 | void container_detach(struct sway_container *child) { |
1279 | if (child->is_fullscreen) { | 1112 | if (child->is_fullscreen) { |
1280 | struct sway_container *workspace = container_parent(child, C_WORKSPACE); | 1113 | child->workspace->fullscreen = NULL; |
1281 | workspace->sway_workspace->fullscreen = NULL; | ||
1282 | } | 1114 | } |
1283 | 1115 | ||
1284 | struct sway_container *parent = child->parent; | 1116 | struct sway_container *old_parent = child->parent; |
1285 | list_t *list = container_is_floating(child) ? | 1117 | struct sway_workspace *old_workspace = child->workspace; |
1286 | parent->sway_workspace->floating : parent->children; | 1118 | list_t *siblings = container_get_siblings(child); |
1287 | int index = list_find(list, child); | 1119 | int index = list_find(siblings, child); |
1288 | if (index != -1) { | 1120 | if (index != -1) { |
1289 | list_del(list, index); | 1121 | list_del(siblings, index); |
1290 | } | 1122 | } |
1291 | child->parent = NULL; | 1123 | child->parent = NULL; |
1292 | container_notify_subtree_changed(parent); | 1124 | child->workspace = NULL; |
1293 | 1125 | container_for_each_child(child, set_workspace, NULL); | |
1294 | container_set_dirty(parent); | ||
1295 | container_set_dirty(child); | ||
1296 | |||
1297 | return parent; | ||
1298 | } | ||
1299 | |||
1300 | enum sway_container_layout container_get_default_layout( | ||
1301 | struct sway_container *con) { | ||
1302 | if (con->type != C_OUTPUT) { | ||
1303 | con = container_parent(con, C_OUTPUT); | ||
1304 | } | ||
1305 | 1126 | ||
1306 | if (!sway_assert(con != NULL, | 1127 | if (old_parent) { |
1307 | "container_get_default_layout must be called on an attached" | 1128 | container_update_representation(old_parent); |
1308 | " container below the root container")) { | 1129 | node_set_dirty(&old_parent->node); |
1309 | return 0; | ||
1310 | } | ||
1311 | |||
1312 | if (config->default_layout != L_NONE) { | ||
1313 | return config->default_layout; | ||
1314 | } else if (config->default_orientation != L_NONE) { | ||
1315 | return config->default_orientation; | ||
1316 | } else if (con->width >= con->height) { | ||
1317 | return L_HORIZ; | ||
1318 | } else { | 1130 | } else { |
1319 | return L_VERT; | 1131 | workspace_update_representation(old_workspace); |
1132 | node_set_dirty(&old_workspace->node); | ||
1320 | } | 1133 | } |
1134 | node_set_dirty(&child->node); | ||
1321 | } | 1135 | } |
1322 | 1136 | ||
1323 | struct sway_container *container_replace_child(struct sway_container *child, | 1137 | void container_replace(struct sway_container *container, |
1324 | struct sway_container *new_child) { | 1138 | struct sway_container *replacement) { |
1325 | struct sway_container *parent = child->parent; | 1139 | container_add_sibling(container, replacement, 1); |
1326 | if (parent == NULL) { | 1140 | container_detach(container); |
1327 | return NULL; | ||
1328 | } | ||
1329 | |||
1330 | list_t *list = container_is_floating(child) ? | ||
1331 | parent->sway_workspace->floating : parent->children; | ||
1332 | int i = list_find(list, child); | ||
1333 | |||
1334 | if (new_child->parent) { | ||
1335 | container_remove_child(new_child); | ||
1336 | } | ||
1337 | list->items[i] = new_child; | ||
1338 | new_child->parent = parent; | ||
1339 | child->parent = NULL; | ||
1340 | |||
1341 | // Set geometry for new child | ||
1342 | new_child->x = child->x; | ||
1343 | new_child->y = child->y; | ||
1344 | new_child->width = child->width; | ||
1345 | new_child->height = child->height; | ||
1346 | |||
1347 | // reset geometry for child | ||
1348 | child->width = 0; | ||
1349 | child->height = 0; | ||
1350 | |||
1351 | return parent; | ||
1352 | } | 1141 | } |
1353 | 1142 | ||
1354 | struct sway_container *container_split(struct sway_container *child, | 1143 | struct sway_container *container_split(struct sway_container *child, |
1355 | enum sway_container_layout layout) { | 1144 | enum sway_container_layout layout) { |
1356 | // TODO floating: cannot split a floating container | 1145 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
1357 | if (!sway_assert(child, "child cannot be null")) { | 1146 | bool set_focus = (seat_get_focus(seat) == &child->node); |
1358 | return NULL; | ||
1359 | } | ||
1360 | if (child->type == C_WORKSPACE && child->children->length == 0) { | ||
1361 | // Special case: this just behaves like splitt | ||
1362 | child->prev_split_layout = child->layout; | ||
1363 | child->layout = layout; | ||
1364 | return child; | ||
1365 | } | ||
1366 | |||
1367 | struct sway_container *cont = container_create(C_CONTAINER); | ||
1368 | |||
1369 | wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child); | ||
1370 | 1147 | ||
1371 | cont->prev_split_layout = L_NONE; | 1148 | struct sway_container *cont = container_create(NULL); |
1372 | cont->width = child->width; | 1149 | cont->width = child->width; |
1373 | cont->height = child->height; | 1150 | cont->height = child->height; |
1374 | cont->x = child->x; | ||
1375 | cont->y = child->y; | ||
1376 | cont->current_gaps = child->current_gaps; | 1151 | cont->current_gaps = child->current_gaps; |
1152 | cont->layout = layout; | ||
1377 | 1153 | ||
1378 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | 1154 | container_replace(child, cont); |
1379 | bool set_focus = (seat_get_focus(seat) == child); | 1155 | container_add_child(cont, child); |
1380 | |||
1381 | if (child->type == C_WORKSPACE) { | ||
1382 | struct sway_container *workspace = child; | ||
1383 | while (workspace->children->length) { | ||
1384 | struct sway_container *ws_child = workspace->children->items[0]; | ||
1385 | container_remove_child(ws_child); | ||
1386 | container_add_child(cont, ws_child); | ||
1387 | } | ||
1388 | |||
1389 | container_add_child(workspace, cont); | ||
1390 | enum sway_container_layout old_layout = workspace->layout; | ||
1391 | workspace->layout = layout; | ||
1392 | cont->layout = old_layout; | ||
1393 | } else { | ||
1394 | cont->layout = layout; | ||
1395 | container_replace_child(child, cont); | ||
1396 | container_add_child(cont, child); | ||
1397 | } | ||
1398 | 1156 | ||
1399 | if (set_focus) { | 1157 | if (set_focus) { |
1400 | seat_set_focus(seat, cont); | 1158 | seat_set_focus(seat, &cont->node); |
1401 | seat_set_focus(seat, child); | 1159 | seat_set_focus(seat, &child->node); |
1402 | } | 1160 | } |
1403 | 1161 | ||
1404 | container_notify_subtree_changed(cont); | ||
1405 | return cont; | 1162 | return cont; |
1406 | } | 1163 | } |
diff --git a/sway/tree/node.c b/sway/tree/node.c new file mode 100644 index 00000000..74661c1a --- /dev/null +++ b/sway/tree/node.c | |||
@@ -0,0 +1,151 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | ||
2 | #include "sway/output.h" | ||
3 | #include "sway/server.h" | ||
4 | #include "sway/tree/container.h" | ||
5 | #include "sway/tree/node.h" | ||
6 | #include "sway/tree/root.h" | ||
7 | #include "sway/tree/workspace.h" | ||
8 | #include "log.h" | ||
9 | |||
10 | void node_init(struct sway_node *node, enum sway_node_type type, void *thing) { | ||
11 | static size_t next_id = 1; | ||
12 | node->id = next_id++; | ||
13 | node->type = type; | ||
14 | node->sway_root = thing; | ||
15 | wl_signal_init(&node->events.destroy); | ||
16 | } | ||
17 | |||
18 | const char *node_type_to_str(enum sway_node_type type) { | ||
19 | switch (type) { | ||
20 | case N_ROOT: | ||
21 | return "N_ROOT"; | ||
22 | case N_OUTPUT: | ||
23 | return "N_OUTPUT"; | ||
24 | case N_WORKSPACE: | ||
25 | return "N_WORKSPACE"; | ||
26 | case N_CONTAINER: | ||
27 | return "N_CONTAINER"; | ||
28 | } | ||
29 | return ""; | ||
30 | } | ||
31 | |||
32 | void node_set_dirty(struct sway_node *node) { | ||
33 | if (node->dirty) { | ||
34 | return; | ||
35 | } | ||
36 | node->dirty = true; | ||
37 | list_add(server.dirty_nodes, node); | ||
38 | } | ||
39 | |||
40 | bool node_is_view(struct sway_node *node) { | ||
41 | return node->type == N_CONTAINER && node->sway_container->view; | ||
42 | } | ||
43 | |||
44 | char *node_get_name(struct sway_node *node) { | ||
45 | switch (node->type) { | ||
46 | case N_ROOT: | ||
47 | return "root"; | ||
48 | case N_OUTPUT: | ||
49 | return node->sway_output->wlr_output->name; | ||
50 | case N_WORKSPACE: | ||
51 | return node->sway_workspace->name; | ||
52 | case N_CONTAINER: | ||
53 | return node->sway_container->title; | ||
54 | } | ||
55 | return NULL; | ||
56 | } | ||
57 | |||
58 | void node_get_box(struct sway_node *node, struct wlr_box *box) { | ||
59 | switch (node->type) { | ||
60 | case N_ROOT: | ||
61 | root_get_box(root, box); | ||
62 | break; | ||
63 | case N_OUTPUT: | ||
64 | output_get_box(node->sway_output, box); | ||
65 | break; | ||
66 | case N_WORKSPACE: | ||
67 | workspace_get_box(node->sway_workspace, box); | ||
68 | break; | ||
69 | case N_CONTAINER: | ||
70 | container_get_box(node->sway_container, box); | ||
71 | break; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | struct sway_output *node_get_output(struct sway_node *node) { | ||
76 | switch (node->type) { | ||
77 | case N_CONTAINER: | ||
78 | return node->sway_container->workspace->output; | ||
79 | case N_WORKSPACE: | ||
80 | return node->sway_workspace->output; | ||
81 | case N_OUTPUT: | ||
82 | return node->sway_output; | ||
83 | case N_ROOT: | ||
84 | return NULL; | ||
85 | } | ||
86 | return NULL; | ||
87 | } | ||
88 | |||
89 | enum sway_container_layout node_get_layout(struct sway_node *node) { | ||
90 | switch (node->type) { | ||
91 | case N_CONTAINER: | ||
92 | return node->sway_container->layout; | ||
93 | case N_WORKSPACE: | ||
94 | return node->sway_workspace->layout; | ||
95 | case N_OUTPUT: | ||
96 | case N_ROOT: | ||
97 | return L_NONE; | ||
98 | } | ||
99 | return L_NONE; | ||
100 | } | ||
101 | |||
102 | struct sway_node *node_get_parent(struct sway_node *node) { | ||
103 | switch (node->type) { | ||
104 | case N_CONTAINER: { | ||
105 | struct sway_container *con = node->sway_container; | ||
106 | if (con->parent) { | ||
107 | return &con->parent->node; | ||
108 | } | ||
109 | if (con->workspace) { | ||
110 | return &con->workspace->node; | ||
111 | } | ||
112 | } | ||
113 | return NULL; | ||
114 | case N_WORKSPACE: { | ||
115 | struct sway_workspace *ws = node->sway_workspace; | ||
116 | if (ws->output) { | ||
117 | return &ws->output->node; | ||
118 | } | ||
119 | } | ||
120 | return NULL; | ||
121 | case N_OUTPUT: | ||
122 | return &root->node; | ||
123 | case N_ROOT: | ||
124 | return NULL; | ||
125 | } | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | list_t *node_get_children(struct sway_node *node) { | ||
130 | switch (node->type) { | ||
131 | case N_CONTAINER: | ||
132 | return node->sway_container->children; | ||
133 | case N_WORKSPACE: | ||
134 | return node->sway_workspace->tiling; | ||
135 | case N_OUTPUT: | ||
136 | case N_ROOT: | ||
137 | return NULL; | ||
138 | } | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { | ||
143 | struct sway_node *parent = node_get_parent(node); | ||
144 | while (parent) { | ||
145 | if (parent == ancestor) { | ||
146 | return true; | ||
147 | } | ||
148 | parent = node_get_parent(parent); | ||
149 | } | ||
150 | return false; | ||
151 | } | ||
diff --git a/sway/tree/output.c b/sway/tree/output.c index 6601220b..d72eb1a1 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -2,28 +2,31 @@ | |||
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <strings.h> | 4 | #include <strings.h> |
5 | #include <wlr/types/wlr_output_damage.h> | ||
5 | #include "sway/ipc-server.h" | 6 | #include "sway/ipc-server.h" |
7 | #include "sway/layers.h" | ||
6 | #include "sway/output.h" | 8 | #include "sway/output.h" |
7 | #include "sway/tree/arrange.h" | 9 | #include "sway/tree/arrange.h" |
8 | #include "sway/tree/output.h" | 10 | #include "sway/tree/output.h" |
9 | #include "sway/tree/workspace.h" | 11 | #include "sway/tree/workspace.h" |
10 | #include "log.h" | 12 | #include "log.h" |
13 | #include "util.h" | ||
11 | 14 | ||
12 | static void restore_workspaces(struct sway_container *output) { | 15 | static void restore_workspaces(struct sway_output *output) { |
13 | // Workspace output priority | 16 | // Workspace output priority |
14 | for (int i = 0; i < root_container.children->length; i++) { | 17 | for (int i = 0; i < root->outputs->length; i++) { |
15 | struct sway_container *other = root_container.children->items[i]; | 18 | struct sway_output *other = root->outputs->items[i]; |
16 | if (other == output) { | 19 | if (other == output) { |
17 | continue; | 20 | continue; |
18 | } | 21 | } |
19 | 22 | ||
20 | for (int j = 0; j < other->children->length; j++) { | 23 | for (int j = 0; j < other->workspaces->length; j++) { |
21 | struct sway_container *ws = other->children->items[j]; | 24 | struct sway_workspace *ws = other->workspaces->items[j]; |
22 | struct sway_container *highest = | 25 | struct sway_output *highest = |
23 | workspace_output_get_highest_available(ws, NULL); | 26 | workspace_output_get_highest_available(ws, NULL); |
24 | if (highest == output) { | 27 | if (highest == output) { |
25 | container_remove_child(ws); | 28 | workspace_detach(ws); |
26 | container_add_child(output, ws); | 29 | output_add_workspace(output, ws); |
27 | ipc_event_workspace(NULL, ws, "move"); | 30 | ipc_event_workspace(NULL, ws, "move"); |
28 | j--; | 31 | j--; |
29 | } | 32 | } |
@@ -31,111 +34,111 @@ static void restore_workspaces(struct sway_container *output) { | |||
31 | } | 34 | } |
32 | 35 | ||
33 | // Saved workspaces | 36 | // Saved workspaces |
34 | list_t *saved = root_container.sway_root->saved_workspaces; | 37 | for (int i = 0; i < root->saved_workspaces->length; ++i) { |
35 | for (int i = 0; i < saved->length; ++i) { | 38 | struct sway_workspace *ws = root->saved_workspaces->items[i]; |
36 | struct sway_container *ws = saved->items[i]; | 39 | output_add_workspace(output, ws); |
37 | container_add_child(output, ws); | ||
38 | ipc_event_workspace(NULL, ws, "move"); | 40 | ipc_event_workspace(NULL, ws, "move"); |
39 | } | 41 | } |
40 | saved->length = 0; | 42 | root->saved_workspaces->length = 0; |
41 | 43 | ||
42 | output_sort_workspaces(output); | 44 | output_sort_workspaces(output); |
43 | } | 45 | } |
44 | 46 | ||
45 | struct sway_container *output_create( | 47 | struct sway_output *output_create(struct wlr_output *wlr_output) { |
46 | struct sway_output *sway_output) { | 48 | struct sway_output *output = calloc(1, sizeof(struct sway_output)); |
47 | const char *name = sway_output->wlr_output->name; | 49 | node_init(&output->node, N_OUTPUT, output); |
48 | char identifier[128]; | 50 | output->wlr_output = wlr_output; |
49 | output_get_identifier(identifier, sizeof(identifier), sway_output); | 51 | wlr_output->data = output; |
50 | 52 | ||
51 | struct output_config *oc = NULL, *all = NULL; | 53 | wl_signal_add(&wlr_output->events.destroy, &output->destroy); |
52 | for (int i = 0; i < config->output_configs->length; ++i) { | ||
53 | struct output_config *cur = config->output_configs->items[i]; | ||
54 | 54 | ||
55 | if (strcasecmp(name, cur->name) == 0 || | 55 | wl_list_insert(&root->all_outputs, &output->link); |
56 | strcasecmp(identifier, cur->name) == 0) { | ||
57 | wlr_log(WLR_DEBUG, "Matched output config for %s", name); | ||
58 | oc = cur; | ||
59 | } | ||
60 | if (strcasecmp("*", cur->name) == 0) { | ||
61 | wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name); | ||
62 | all = cur; | ||
63 | } | ||
64 | 56 | ||
65 | if (oc && all) { | 57 | if (!wl_list_empty(&wlr_output->modes)) { |
66 | break; | 58 | struct wlr_output_mode *mode = |
67 | } | 59 | wl_container_of(wlr_output->modes.prev, mode, link); |
68 | } | 60 | wlr_output_set_mode(wlr_output, mode); |
69 | if (!oc) { | ||
70 | oc = all; | ||
71 | } | 61 | } |
72 | 62 | ||
73 | if (oc && !oc->enabled) { | 63 | output->workspaces = create_list(); |
74 | return NULL; | 64 | output->current.workspaces = create_list(); |
75 | } | ||
76 | 65 | ||
77 | struct sway_container *output = container_create(C_OUTPUT); | 66 | return output; |
78 | output->sway_output = sway_output; | 67 | } |
79 | output->name = strdup(name); | ||
80 | if (output->name == NULL) { | ||
81 | output_begin_destroy(output); | ||
82 | return NULL; | ||
83 | } | ||
84 | 68 | ||
69 | void output_enable(struct sway_output *output, struct output_config *oc) { | ||
70 | if (!sway_assert(!output->enabled, "output is already enabled")) { | ||
71 | return; | ||
72 | } | ||
73 | struct wlr_output *wlr_output = output->wlr_output; | ||
74 | output->enabled = true; | ||
85 | apply_output_config(oc, output); | 75 | apply_output_config(oc, output); |
86 | container_add_child(&root_container, output); | 76 | list_add(root->outputs, output); |
87 | load_swaybars(); | ||
88 | |||
89 | struct wlr_box size; | ||
90 | wlr_output_effective_resolution(sway_output->wlr_output, &size.width, | ||
91 | &size.height); | ||
92 | output->width = size.width; | ||
93 | output->height = size.height; | ||
94 | 77 | ||
95 | restore_workspaces(output); | 78 | restore_workspaces(output); |
96 | 79 | ||
97 | if (!output->children->length) { | 80 | if (!output->workspaces->length) { |
98 | // Create workspace | 81 | // Create workspace |
99 | char *ws_name = workspace_next_name(output->name); | 82 | char *ws_name = workspace_next_name(wlr_output->name); |
100 | wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); | 83 | wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); |
101 | struct sway_container *ws = workspace_create(output, ws_name); | 84 | struct sway_workspace *ws = workspace_create(output, ws_name); |
102 | // Set each seat's focus if not already set | 85 | // Set each seat's focus if not already set |
103 | struct sway_seat *seat = NULL; | 86 | struct sway_seat *seat = NULL; |
104 | wl_list_for_each(seat, &input_manager->seats, link) { | 87 | wl_list_for_each(seat, &input_manager->seats, link) { |
105 | if (!seat->has_focus) { | 88 | if (!seat->has_focus) { |
106 | seat_set_focus(seat, ws); | 89 | seat_set_focus(seat, &ws->node); |
107 | } | 90 | } |
108 | } | 91 | } |
109 | free(ws_name); | 92 | free(ws_name); |
110 | } | 93 | } |
111 | 94 | ||
112 | container_create_notify(output); | 95 | size_t len = sizeof(output->layers) / sizeof(output->layers[0]); |
113 | return output; | 96 | for (size_t i = 0; i < len; ++i) { |
97 | wl_list_init(&output->layers[i]); | ||
98 | } | ||
99 | wl_signal_init(&output->events.destroy); | ||
100 | |||
101 | input_manager_configure_xcursor(input_manager); | ||
102 | |||
103 | wl_signal_add(&wlr_output->events.mode, &output->mode); | ||
104 | wl_signal_add(&wlr_output->events.transform, &output->transform); | ||
105 | wl_signal_add(&wlr_output->events.scale, &output->scale); | ||
106 | wl_signal_add(&output->damage->events.frame, &output->damage_frame); | ||
107 | wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); | ||
108 | |||
109 | output_add_listeners(output); | ||
110 | |||
111 | wl_signal_emit(&root->events.new_node, &output->node); | ||
112 | |||
113 | load_swaybars(); | ||
114 | |||
115 | arrange_layers(output); | ||
116 | arrange_root(); | ||
114 | } | 117 | } |
115 | 118 | ||
116 | static void output_evacuate(struct sway_container *output) { | 119 | static void output_evacuate(struct sway_output *output) { |
117 | if (!output->children->length) { | 120 | if (!output->workspaces->length) { |
118 | return; | 121 | return; |
119 | } | 122 | } |
120 | struct sway_container *fallback_output = NULL; | 123 | struct sway_output *fallback_output = NULL; |
121 | if (root_container.children->length > 1) { | 124 | if (root->outputs->length > 1) { |
122 | fallback_output = root_container.children->items[0]; | 125 | fallback_output = root->outputs->items[0]; |
123 | if (fallback_output == output) { | 126 | if (fallback_output == output) { |
124 | fallback_output = root_container.children->items[1]; | 127 | fallback_output = root->outputs->items[1]; |
125 | } | 128 | } |
126 | } | 129 | } |
127 | 130 | ||
128 | while (output->children->length) { | 131 | while (output->workspaces->length) { |
129 | struct sway_container *workspace = output->children->items[0]; | 132 | struct sway_workspace *workspace = output->workspaces->items[0]; |
130 | 133 | ||
131 | container_remove_child(workspace); | 134 | workspace_detach(workspace); |
132 | 135 | ||
133 | if (workspace_is_empty(workspace)) { | 136 | if (workspace_is_empty(workspace)) { |
134 | workspace_begin_destroy(workspace); | 137 | workspace_begin_destroy(workspace); |
135 | continue; | 138 | continue; |
136 | } | 139 | } |
137 | 140 | ||
138 | struct sway_container *new_output = | 141 | struct sway_output *new_output = |
139 | workspace_output_get_highest_available(workspace, output); | 142 | workspace_output_get_highest_available(workspace, output); |
140 | if (!new_output) { | 143 | if (!new_output) { |
141 | new_output = fallback_output; | 144 | new_output = fallback_output; |
@@ -143,39 +146,31 @@ static void output_evacuate(struct sway_container *output) { | |||
143 | 146 | ||
144 | if (new_output) { | 147 | if (new_output) { |
145 | workspace_output_add_priority(workspace, new_output); | 148 | workspace_output_add_priority(workspace, new_output); |
146 | container_add_child(new_output, workspace); | 149 | output_add_workspace(new_output, workspace); |
147 | output_sort_workspaces(new_output); | 150 | output_sort_workspaces(new_output); |
148 | ipc_event_workspace(NULL, workspace, "move"); | 151 | ipc_event_workspace(NULL, workspace, "move"); |
149 | } else { | 152 | } else { |
150 | list_add(root_container.sway_root->saved_workspaces, workspace); | 153 | list_add(root->saved_workspaces, workspace); |
151 | } | 154 | } |
152 | } | 155 | } |
153 | } | 156 | } |
154 | 157 | ||
155 | void output_destroy(struct sway_container *output) { | 158 | void output_destroy(struct sway_output *output) { |
156 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 159 | if (!sway_assert(output->node.destroying, |
160 | "Tried to free output which wasn't marked as destroying")) { | ||
157 | return; | 161 | return; |
158 | } | 162 | } |
159 | if (!sway_assert(output->destroying, | 163 | if (!sway_assert(output->wlr_output == NULL, |
160 | "Tried to free output which wasn't marked as destroying")) { | 164 | "Tried to free output which still had a wlr_output")) { |
161 | return; | 165 | return; |
162 | } | 166 | } |
163 | if (!sway_assert(output->ntxnrefs == 0, "Tried to free output " | 167 | if (!sway_assert(output->node.ntxnrefs == 0, "Tried to free output " |
164 | "which is still referenced by transactions")) { | 168 | "which is still referenced by transactions")) { |
165 | return; | 169 | return; |
166 | } | 170 | } |
167 | free(output->name); | 171 | list_free(output->workspaces); |
168 | free(output->formatted_title); | 172 | list_free(output->current.workspaces); |
169 | wlr_texture_destroy(output->title_focused); | ||
170 | wlr_texture_destroy(output->title_focused_inactive); | ||
171 | wlr_texture_destroy(output->title_unfocused); | ||
172 | wlr_texture_destroy(output->title_urgent); | ||
173 | list_free(output->children); | ||
174 | list_free(output->current.children); | ||
175 | list_free(output->outputs); | ||
176 | free(output); | 173 | free(output); |
177 | |||
178 | // NOTE: We don't actually destroy the sway_output here | ||
179 | } | 174 | } |
180 | 175 | ||
181 | static void untrack_output(struct sway_container *con, void *data) { | 176 | static void untrack_output(struct sway_container *con, void *data) { |
@@ -186,76 +181,131 @@ static void untrack_output(struct sway_container *con, void *data) { | |||
186 | } | 181 | } |
187 | } | 182 | } |
188 | 183 | ||
189 | void output_begin_destroy(struct sway_container *output) { | 184 | void output_disable(struct sway_output *output) { |
190 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 185 | if (!sway_assert(output->enabled, "Expected an enabled output")) { |
191 | return; | 186 | return; |
192 | } | 187 | } |
193 | wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); | 188 | wlr_log(WLR_DEBUG, "Disabling output '%s'", output->wlr_output->name); |
194 | wl_signal_emit(&output->events.destroy, output); | 189 | wl_signal_emit(&output->events.destroy, output); |
195 | 190 | ||
196 | output_evacuate(output); | 191 | output_evacuate(output); |
197 | 192 | ||
198 | output->destroying = true; | 193 | root_for_each_container(untrack_output, output); |
199 | container_set_dirty(output); | 194 | |
195 | int index = list_find(root->outputs, output); | ||
196 | list_del(root->outputs, index); | ||
200 | 197 | ||
201 | root_for_each_container(untrack_output, output->sway_output); | 198 | wl_list_remove(&output->mode.link); |
199 | wl_list_remove(&output->transform.link); | ||
200 | wl_list_remove(&output->scale.link); | ||
201 | wl_list_remove(&output->damage_destroy.link); | ||
202 | wl_list_remove(&output->damage_frame.link); | ||
202 | 203 | ||
203 | wl_list_remove(&output->sway_output->mode.link); | 204 | output->enabled = false; |
204 | wl_list_remove(&output->sway_output->transform.link); | ||
205 | wl_list_remove(&output->sway_output->scale.link); | ||
206 | wl_list_remove(&output->sway_output->damage_destroy.link); | ||
207 | wl_list_remove(&output->sway_output->damage_frame.link); | ||
208 | 205 | ||
209 | output->sway_output->swayc = NULL; | 206 | arrange_root(); |
210 | output->sway_output = NULL; | 207 | } |
211 | 208 | ||
212 | if (output->parent) { | 209 | void output_begin_destroy(struct sway_output *output) { |
213 | container_remove_child(output); | 210 | if (!sway_assert(!output->enabled, "Expected a disabled output")) { |
211 | return; | ||
214 | } | 212 | } |
213 | wlr_log(WLR_DEBUG, "Destroying output '%s'", output->wlr_output->name); | ||
214 | |||
215 | output->node.destroying = true; | ||
216 | node_set_dirty(&output->node); | ||
217 | |||
218 | wl_list_remove(&output->link); | ||
219 | wl_list_remove(&output->destroy.link); | ||
220 | output->wlr_output->data = NULL; | ||
221 | output->wlr_output = NULL; | ||
215 | } | 222 | } |
216 | 223 | ||
217 | struct sway_container *output_from_wlr_output(struct wlr_output *output) { | 224 | struct output_config *output_find_config(struct sway_output *output) { |
218 | if (output == NULL) { | 225 | const char *name = output->wlr_output->name; |
226 | char identifier[128]; | ||
227 | output_get_identifier(identifier, sizeof(identifier), output); | ||
228 | |||
229 | struct output_config *oc = NULL, *all = NULL; | ||
230 | for (int i = 0; i < config->output_configs->length; ++i) { | ||
231 | struct output_config *cur = config->output_configs->items[i]; | ||
232 | |||
233 | if (strcasecmp(name, cur->name) == 0 || | ||
234 | strcasecmp(identifier, cur->name) == 0) { | ||
235 | wlr_log(WLR_DEBUG, "Matched output config for %s", name); | ||
236 | oc = cur; | ||
237 | } | ||
238 | if (strcasecmp("*", cur->name) == 0) { | ||
239 | wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name); | ||
240 | all = cur; | ||
241 | } | ||
242 | |||
243 | if (oc && all) { | ||
244 | break; | ||
245 | } | ||
246 | } | ||
247 | if (!oc) { | ||
248 | oc = all; | ||
249 | } | ||
250 | |||
251 | if (oc && !oc->enabled) { | ||
219 | return NULL; | 252 | return NULL; |
220 | } | 253 | } |
221 | for (int i = 0; i < root_container.children->length; ++i) { | 254 | return oc; |
222 | struct sway_container *o = root_container.children->items[i]; | 255 | } |
223 | if (o->type == C_OUTPUT && o->sway_output->wlr_output == output) { | 256 | |
224 | return o; | 257 | struct sway_output *output_from_wlr_output(struct wlr_output *output) { |
225 | } | 258 | return output->data; |
259 | } | ||
260 | |||
261 | struct sway_output *output_get_in_direction(struct sway_output *reference, | ||
262 | enum movement_direction direction) { | ||
263 | enum wlr_direction wlr_dir = 0; | ||
264 | if (!sway_assert(sway_dir_to_wlr(direction, &wlr_dir), | ||
265 | "got invalid direction: %d", direction)) { | ||
266 | return NULL; | ||
226 | } | 267 | } |
227 | return NULL; | 268 | int lx = reference->wlr_output->lx + reference->wlr_output->width / 2; |
269 | int ly = reference->wlr_output->ly + reference->wlr_output->height / 2; | ||
270 | struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output( | ||
271 | root->output_layout, wlr_dir, reference->wlr_output, lx, ly); | ||
272 | if (!wlr_adjacent) { | ||
273 | return NULL; | ||
274 | } | ||
275 | return output_from_wlr_output(wlr_adjacent); | ||
228 | } | 276 | } |
229 | 277 | ||
230 | void output_for_each_workspace(struct sway_container *output, | 278 | void output_add_workspace(struct sway_output *output, |
231 | void (*f)(struct sway_container *con, void *data), void *data) { | 279 | struct sway_workspace *workspace) { |
232 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 280 | if (workspace->output) { |
233 | return; | 281 | workspace_detach(workspace); |
234 | } | 282 | } |
235 | for (int i = 0; i < output->children->length; ++i) { | 283 | list_add(output->workspaces, workspace); |
236 | struct sway_container *workspace = output->children->items[i]; | 284 | workspace->output = output; |
285 | node_set_dirty(&output->node); | ||
286 | node_set_dirty(&workspace->node); | ||
287 | } | ||
288 | |||
289 | void output_for_each_workspace(struct sway_output *output, | ||
290 | void (*f)(struct sway_workspace *ws, void *data), void *data) { | ||
291 | for (int i = 0; i < output->workspaces->length; ++i) { | ||
292 | struct sway_workspace *workspace = output->workspaces->items[i]; | ||
237 | f(workspace, data); | 293 | f(workspace, data); |
238 | } | 294 | } |
239 | } | 295 | } |
240 | 296 | ||
241 | void output_for_each_container(struct sway_container *output, | 297 | void output_for_each_container(struct sway_output *output, |
242 | void (*f)(struct sway_container *con, void *data), void *data) { | 298 | void (*f)(struct sway_container *con, void *data), void *data) { |
243 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 299 | for (int i = 0; i < output->workspaces->length; ++i) { |
244 | return; | 300 | struct sway_workspace *workspace = output->workspaces->items[i]; |
245 | } | ||
246 | for (int i = 0; i < output->children->length; ++i) { | ||
247 | struct sway_container *workspace = output->children->items[i]; | ||
248 | workspace_for_each_container(workspace, f, data); | 301 | workspace_for_each_container(workspace, f, data); |
249 | } | 302 | } |
250 | } | 303 | } |
251 | 304 | ||
252 | struct sway_container *output_find_workspace(struct sway_container *output, | 305 | struct sway_workspace *output_find_workspace(struct sway_output *output, |
253 | bool (*test)(struct sway_container *con, void *data), void *data) { | 306 | bool (*test)(struct sway_workspace *ws, void *data), void *data) { |
254 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 307 | for (int i = 0; i < output->workspaces->length; ++i) { |
255 | return NULL; | 308 | struct sway_workspace *workspace = output->workspaces->items[i]; |
256 | } | ||
257 | for (int i = 0; i < output->children->length; ++i) { | ||
258 | struct sway_container *workspace = output->children->items[i]; | ||
259 | if (test(workspace, data)) { | 309 | if (test(workspace, data)) { |
260 | return workspace; | 310 | return workspace; |
261 | } | 311 | } |
@@ -263,14 +313,11 @@ struct sway_container *output_find_workspace(struct sway_container *output, | |||
263 | return NULL; | 313 | return NULL; |
264 | } | 314 | } |
265 | 315 | ||
266 | struct sway_container *output_find_container(struct sway_container *output, | 316 | struct sway_container *output_find_container(struct sway_output *output, |
267 | bool (*test)(struct sway_container *con, void *data), void *data) { | 317 | bool (*test)(struct sway_container *con, void *data), void *data) { |
268 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
269 | return NULL; | ||
270 | } | ||
271 | struct sway_container *result = NULL; | 318 | struct sway_container *result = NULL; |
272 | for (int i = 0; i < output->children->length; ++i) { | 319 | for (int i = 0; i < output->workspaces->length; ++i) { |
273 | struct sway_container *workspace = output->children->items[i]; | 320 | struct sway_workspace *workspace = output->workspaces->items[i]; |
274 | if ((result = workspace_find_container(workspace, test, data))) { | 321 | if ((result = workspace_find_container(workspace, test, data))) { |
275 | return result; | 322 | return result; |
276 | } | 323 | } |
@@ -279,8 +326,8 @@ struct sway_container *output_find_container(struct sway_container *output, | |||
279 | } | 326 | } |
280 | 327 | ||
281 | static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | 328 | static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { |
282 | struct sway_container *a = *(void **)_a; | 329 | struct sway_workspace *a = *(void **)_a; |
283 | struct sway_container *b = *(void **)_b; | 330 | struct sway_workspace *b = *(void **)_b; |
284 | 331 | ||
285 | if (isdigit(a->name[0]) && isdigit(b->name[0])) { | 332 | if (isdigit(a->name[0]) && isdigit(b->name[0])) { |
286 | int a_num = strtol(a->name, NULL, 10); | 333 | int a_num = strtol(a->name, NULL, 10); |
@@ -294,6 +341,27 @@ static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | |||
294 | return 0; | 341 | return 0; |
295 | } | 342 | } |
296 | 343 | ||
297 | void output_sort_workspaces(struct sway_container *output) { | 344 | void output_sort_workspaces(struct sway_output *output) { |
298 | list_stable_sort(output->children, sort_workspace_cmp_qsort); | 345 | list_stable_sort(output->workspaces, sort_workspace_cmp_qsort); |
346 | } | ||
347 | |||
348 | void output_get_box(struct sway_output *output, struct wlr_box *box) { | ||
349 | box->x = output->wlr_output->lx; | ||
350 | box->y = output->wlr_output->ly; | ||
351 | box->width = output->wlr_output->width; | ||
352 | box->height = output->wlr_output->height; | ||
353 | } | ||
354 | |||
355 | enum sway_container_layout output_get_default_layout( | ||
356 | struct sway_output *output) { | ||
357 | if (config->default_layout != L_NONE) { | ||
358 | return config->default_layout; | ||
359 | } | ||
360 | if (config->default_orientation != L_NONE) { | ||
361 | return config->default_orientation; | ||
362 | } | ||
363 | if (output->wlr_output->height > output->wlr_output->width) { | ||
364 | return L_VERT; | ||
365 | } | ||
366 | return L_HORIZ; | ||
299 | } | 367 | } |
diff --git a/sway/tree/root.c b/sway/tree/root.c index b42371de..ecc04ddb 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c | |||
@@ -14,54 +14,45 @@ | |||
14 | #include "log.h" | 14 | #include "log.h" |
15 | #include "util.h" | 15 | #include "util.h" |
16 | 16 | ||
17 | struct sway_container root_container; | 17 | struct sway_root *root; |
18 | 18 | ||
19 | static void output_layout_handle_change(struct wl_listener *listener, | 19 | static void output_layout_handle_change(struct wl_listener *listener, |
20 | void *data) { | 20 | void *data) { |
21 | arrange_windows(&root_container); | 21 | arrange_root(); |
22 | transaction_commit_dirty(); | 22 | transaction_commit_dirty(); |
23 | } | 23 | } |
24 | 24 | ||
25 | void root_create(void) { | 25 | struct sway_root *root_create(void) { |
26 | root_container.id = 0; // normally assigned in new_swayc() | 26 | struct sway_root *root = calloc(1, sizeof(struct sway_root)); |
27 | root_container.type = C_ROOT; | 27 | if (!root) { |
28 | root_container.layout = L_NONE; | 28 | wlr_log(WLR_ERROR, "Unable to allocate sway_root"); |
29 | root_container.name = strdup("root"); | 29 | return NULL; |
30 | root_container.children = create_list(); | 30 | } |
31 | root_container.current.children = create_list(); | 31 | node_init(&root->node, N_ROOT, root); |
32 | wl_signal_init(&root_container.events.destroy); | 32 | root->output_layout = wlr_output_layout_create(); |
33 | 33 | wl_list_init(&root->all_outputs); | |
34 | root_container.sway_root = calloc(1, sizeof(*root_container.sway_root)); | ||
35 | root_container.sway_root->output_layout = wlr_output_layout_create(); | ||
36 | wl_list_init(&root_container.sway_root->all_outputs); | ||
37 | #ifdef HAVE_XWAYLAND | 34 | #ifdef HAVE_XWAYLAND |
38 | wl_list_init(&root_container.sway_root->xwayland_unmanaged); | 35 | wl_list_init(&root->xwayland_unmanaged); |
39 | #endif | 36 | #endif |
40 | wl_list_init(&root_container.sway_root->drag_icons); | 37 | wl_list_init(&root->drag_icons); |
41 | wl_signal_init(&root_container.sway_root->events.new_container); | 38 | wl_signal_init(&root->events.new_node); |
42 | root_container.sway_root->scratchpad = create_list(); | 39 | root->outputs = create_list(); |
43 | root_container.sway_root->saved_workspaces = create_list(); | 40 | root->scratchpad = create_list(); |
44 | 41 | root->saved_workspaces = create_list(); | |
45 | root_container.sway_root->output_layout_change.notify = | 42 | |
46 | output_layout_handle_change; | 43 | root->output_layout_change.notify = output_layout_handle_change; |
47 | wl_signal_add(&root_container.sway_root->output_layout->events.change, | 44 | wl_signal_add(&root->output_layout->events.change, |
48 | &root_container.sway_root->output_layout_change); | 45 | &root->output_layout_change); |
46 | return root; | ||
49 | } | 47 | } |
50 | 48 | ||
51 | void root_destroy(void) { | 49 | void root_destroy(struct sway_root *root) { |
52 | // sway_root | 50 | wl_list_remove(&root->output_layout_change.link); |
53 | wl_list_remove(&root_container.sway_root->output_layout_change.link); | 51 | list_free(root->scratchpad); |
54 | list_free(root_container.sway_root->scratchpad); | 52 | list_free(root->saved_workspaces); |
55 | list_free(root_container.sway_root->saved_workspaces); | 53 | list_free(root->outputs); |
56 | wlr_output_layout_destroy(root_container.sway_root->output_layout); | 54 | wlr_output_layout_destroy(root->output_layout); |
57 | free(root_container.sway_root); | 55 | free(root); |
58 | |||
59 | // root_container | ||
60 | list_free(root_container.children); | ||
61 | list_free(root_container.current.children); | ||
62 | free(root_container.name); | ||
63 | |||
64 | memset(&root_container, 0, sizeof(root_container)); | ||
65 | } | 56 | } |
66 | 57 | ||
67 | void root_scratchpad_add_container(struct sway_container *con) { | 58 | void root_scratchpad_add_container(struct sway_container *con) { |
@@ -69,15 +60,21 @@ void root_scratchpad_add_container(struct sway_container *con) { | |||
69 | return; | 60 | return; |
70 | } | 61 | } |
71 | con->scratchpad = true; | 62 | con->scratchpad = true; |
72 | list_add(root_container.sway_root->scratchpad, con); | 63 | list_add(root->scratchpad, con); |
73 | 64 | ||
74 | struct sway_container *parent = con->parent; | 65 | struct sway_container *parent = con->parent; |
66 | struct sway_workspace *workspace = con->workspace; | ||
75 | container_set_floating(con, true); | 67 | container_set_floating(con, true); |
76 | container_remove_child(con); | 68 | container_detach(con); |
77 | arrange_windows(parent); | ||
78 | 69 | ||
79 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 70 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
80 | seat_set_focus(seat, seat_get_focus_inactive(seat, parent)); | 71 | if (parent) { |
72 | arrange_container(parent); | ||
73 | seat_set_focus(seat, seat_get_focus_inactive(seat, &parent->node)); | ||
74 | } else { | ||
75 | arrange_workspace(workspace); | ||
76 | seat_set_focus(seat, seat_get_focus_inactive(seat, &workspace->node)); | ||
77 | } | ||
81 | } | 78 | } |
82 | 79 | ||
83 | void root_scratchpad_remove_container(struct sway_container *con) { | 80 | void root_scratchpad_remove_container(struct sway_container *con) { |
@@ -85,28 +82,25 @@ void root_scratchpad_remove_container(struct sway_container *con) { | |||
85 | return; | 82 | return; |
86 | } | 83 | } |
87 | con->scratchpad = false; | 84 | con->scratchpad = false; |
88 | int index = list_find(root_container.sway_root->scratchpad, con); | 85 | int index = list_find(root->scratchpad, con); |
89 | if (index != -1) { | 86 | if (index != -1) { |
90 | list_del(root_container.sway_root->scratchpad, index); | 87 | list_del(root->scratchpad, index); |
91 | } | 88 | } |
92 | } | 89 | } |
93 | 90 | ||
94 | void root_scratchpad_show(struct sway_container *con) { | 91 | void root_scratchpad_show(struct sway_container *con) { |
95 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 92 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
96 | struct sway_container *ws = seat_get_focus(seat); | 93 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
97 | if (ws->type != C_WORKSPACE) { | ||
98 | ws = container_parent(ws, C_WORKSPACE); | ||
99 | } | ||
100 | 94 | ||
101 | // If the current con or any of its parents are in fullscreen mode, we | 95 | // If the current con or any of its parents are in fullscreen mode, we |
102 | // first need to disable it before showing the scratchpad con. | 96 | // first need to disable it before showing the scratchpad con. |
103 | if (ws->sway_workspace->fullscreen) { | 97 | if (ws->fullscreen) { |
104 | container_set_fullscreen(ws->sway_workspace->fullscreen, false); | 98 | container_set_fullscreen(ws->fullscreen, false); |
105 | } | 99 | } |
106 | 100 | ||
107 | // Show the container | 101 | // Show the container |
108 | if (con->parent) { | 102 | if (con->workspace) { |
109 | container_remove_child(con); | 103 | container_detach(con); |
110 | } | 104 | } |
111 | workspace_add_floating(ws, con); | 105 | workspace_add_floating(ws, con); |
112 | 106 | ||
@@ -115,7 +109,7 @@ void root_scratchpad_show(struct sway_container *con) { | |||
115 | double center_ly = con->y + con->height / 2; | 109 | double center_ly = con->y + con->height / 2; |
116 | 110 | ||
117 | struct wlr_box workspace_box; | 111 | struct wlr_box workspace_box; |
118 | container_get_box(ws, &workspace_box); | 112 | workspace_get_box(ws, &workspace_box); |
119 | if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { | 113 | if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) { |
120 | // Maybe resize it | 114 | // Maybe resize it |
121 | if (con->width > ws->width || con->height > ws->height) { | 115 | if (con->width > ws->width || con->height > ws->height) { |
@@ -128,23 +122,21 @@ void root_scratchpad_show(struct sway_container *con) { | |||
128 | container_floating_move_to(con, new_lx, new_ly); | 122 | container_floating_move_to(con, new_lx, new_ly); |
129 | } | 123 | } |
130 | 124 | ||
131 | arrange_windows(ws); | 125 | arrange_workspace(ws); |
132 | seat_set_focus(seat, seat_get_focus_inactive(seat, con)); | 126 | seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node)); |
133 | |||
134 | container_set_dirty(con->parent); | ||
135 | } | 127 | } |
136 | 128 | ||
137 | void root_scratchpad_hide(struct sway_container *con) { | 129 | void root_scratchpad_hide(struct sway_container *con) { |
138 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 130 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
139 | struct sway_container *focus = seat_get_focus(seat); | 131 | struct sway_node *focus = seat_get_focus(seat); |
140 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 132 | struct sway_workspace *ws = con->workspace; |
141 | 133 | ||
142 | container_remove_child(con); | 134 | container_detach(con); |
143 | arrange_windows(ws); | 135 | arrange_workspace(ws); |
144 | if (con == focus) { | 136 | if (&con->node == focus) { |
145 | seat_set_focus(seat, seat_get_focus_inactive(seat, ws)); | 137 | seat_set_focus(seat, seat_get_focus_inactive(seat, &ws->node)); |
146 | } | 138 | } |
147 | list_move_to_end(root_container.sway_root->scratchpad, con); | 139 | list_move_to_end(root->scratchpad, con); |
148 | } | 140 | } |
149 | 141 | ||
150 | struct pid_workspace { | 142 | struct pid_workspace { |
@@ -152,7 +144,7 @@ struct pid_workspace { | |||
152 | char *workspace; | 144 | char *workspace; |
153 | struct timespec time_added; | 145 | struct timespec time_added; |
154 | 146 | ||
155 | struct sway_container *output; | 147 | struct sway_output *output; |
156 | struct wl_listener output_destroy; | 148 | struct wl_listener output_destroy; |
157 | 149 | ||
158 | struct wl_list link; | 150 | struct wl_list link; |
@@ -160,13 +152,13 @@ struct pid_workspace { | |||
160 | 152 | ||
161 | static struct wl_list pid_workspaces; | 153 | static struct wl_list pid_workspaces; |
162 | 154 | ||
163 | struct sway_container *root_workspace_for_pid(pid_t pid) { | 155 | struct sway_workspace *root_workspace_for_pid(pid_t pid) { |
164 | if (!pid_workspaces.prev && !pid_workspaces.next) { | 156 | if (!pid_workspaces.prev && !pid_workspaces.next) { |
165 | wl_list_init(&pid_workspaces); | 157 | wl_list_init(&pid_workspaces); |
166 | return NULL; | 158 | return NULL; |
167 | } | 159 | } |
168 | 160 | ||
169 | struct sway_container *ws = NULL; | 161 | struct sway_workspace *ws = NULL; |
170 | struct pid_workspace *pw = NULL; | 162 | struct pid_workspace *pw = NULL; |
171 | 163 | ||
172 | wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); | 164 | wlr_log(WLR_DEBUG, "Looking up workspace for pid %d", pid); |
@@ -219,16 +211,12 @@ void root_record_workspace_pid(pid_t pid) { | |||
219 | } | 211 | } |
220 | 212 | ||
221 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 213 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
222 | struct sway_container *ws = | 214 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
223 | seat_get_focus_inactive(seat, &root_container); | ||
224 | if (ws && ws->type != C_WORKSPACE) { | ||
225 | ws = container_parent(ws, C_WORKSPACE); | ||
226 | } | ||
227 | if (!ws) { | 215 | if (!ws) { |
228 | wlr_log(WLR_DEBUG, "Bailing out, no workspace"); | 216 | wlr_log(WLR_DEBUG, "Bailing out, no workspace"); |
229 | return; | 217 | return; |
230 | } | 218 | } |
231 | struct sway_container *output = ws->parent; | 219 | struct sway_output *output = ws->output; |
232 | if (!output) { | 220 | if (!output) { |
233 | wlr_log(WLR_DEBUG, "Bailing out, no output"); | 221 | wlr_log(WLR_DEBUG, "Bailing out, no output"); |
234 | return; | 222 | return; |
@@ -255,30 +243,28 @@ void root_record_workspace_pid(pid_t pid) { | |||
255 | pw->pid = pid; | 243 | pw->pid = pid; |
256 | memcpy(&pw->time_added, &now, sizeof(struct timespec)); | 244 | memcpy(&pw->time_added, &now, sizeof(struct timespec)); |
257 | pw->output_destroy.notify = pw_handle_output_destroy; | 245 | pw->output_destroy.notify = pw_handle_output_destroy; |
258 | wl_signal_add(&output->sway_output->wlr_output->events.destroy, | 246 | wl_signal_add(&output->wlr_output->events.destroy, &pw->output_destroy); |
259 | &pw->output_destroy); | ||
260 | wl_list_insert(&pid_workspaces, &pw->link); | 247 | wl_list_insert(&pid_workspaces, &pw->link); |
261 | } | 248 | } |
262 | 249 | ||
263 | void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), | 250 | void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data), |
264 | void *data) { | 251 | void *data) { |
265 | for (int i = 0; i < root_container.children->length; ++i) { | 252 | for (int i = 0; i < root->outputs->length; ++i) { |
266 | struct sway_container *output = root_container.children->items[i]; | 253 | struct sway_output *output = root->outputs->items[i]; |
267 | output_for_each_workspace(output, f, data); | 254 | output_for_each_workspace(output, f, data); |
268 | } | 255 | } |
269 | } | 256 | } |
270 | 257 | ||
271 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), | 258 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), |
272 | void *data) { | 259 | void *data) { |
273 | for (int i = 0; i < root_container.children->length; ++i) { | 260 | for (int i = 0; i < root->outputs->length; ++i) { |
274 | struct sway_container *output = root_container.children->items[i]; | 261 | struct sway_output *output = root->outputs->items[i]; |
275 | output_for_each_container(output, f, data); | 262 | output_for_each_container(output, f, data); |
276 | } | 263 | } |
277 | 264 | ||
278 | // Scratchpad | 265 | // Scratchpad |
279 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | 266 | for (int i = 0; i < root->scratchpad->length; ++i) { |
280 | struct sway_container *container = | 267 | struct sway_container *container = root->scratchpad->items[i]; |
281 | root_container.sway_root->scratchpad->items[i]; | ||
282 | // If the container has a parent then it's visible on a workspace | 268 | // If the container has a parent then it's visible on a workspace |
283 | // and will have been iterated in the previous for loop. So we only | 269 | // and will have been iterated in the previous for loop. So we only |
284 | // iterate the hidden scratchpad containers here. | 270 | // iterate the hidden scratchpad containers here. |
@@ -289,10 +275,10 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data), | |||
289 | } | 275 | } |
290 | } | 276 | } |
291 | 277 | ||
292 | struct sway_container *root_find_output( | 278 | struct sway_output *root_find_output( |
293 | bool (*test)(struct sway_container *con, void *data), void *data) { | 279 | bool (*test)(struct sway_output *output, void *data), void *data) { |
294 | for (int i = 0; i < root_container.children->length; ++i) { | 280 | for (int i = 0; i < root->outputs->length; ++i) { |
295 | struct sway_container *output = root_container.children->items[i]; | 281 | struct sway_output *output = root->outputs->items[i]; |
296 | if (test(output, data)) { | 282 | if (test(output, data)) { |
297 | return output; | 283 | return output; |
298 | } | 284 | } |
@@ -300,11 +286,11 @@ struct sway_container *root_find_output( | |||
300 | return NULL; | 286 | return NULL; |
301 | } | 287 | } |
302 | 288 | ||
303 | struct sway_container *root_find_workspace( | 289 | struct sway_workspace *root_find_workspace( |
304 | bool (*test)(struct sway_container *con, void *data), void *data) { | 290 | bool (*test)(struct sway_workspace *ws, void *data), void *data) { |
305 | struct sway_container *result = NULL; | 291 | struct sway_workspace *result = NULL; |
306 | for (int i = 0; i < root_container.children->length; ++i) { | 292 | for (int i = 0; i < root->outputs->length; ++i) { |
307 | struct sway_container *output = root_container.children->items[i]; | 293 | struct sway_output *output = root->outputs->items[i]; |
308 | if ((result = output_find_workspace(output, test, data))) { | 294 | if ((result = output_find_workspace(output, test, data))) { |
309 | return result; | 295 | return result; |
310 | } | 296 | } |
@@ -315,17 +301,16 @@ struct sway_container *root_find_workspace( | |||
315 | struct sway_container *root_find_container( | 301 | struct sway_container *root_find_container( |
316 | bool (*test)(struct sway_container *con, void *data), void *data) { | 302 | bool (*test)(struct sway_container *con, void *data), void *data) { |
317 | struct sway_container *result = NULL; | 303 | struct sway_container *result = NULL; |
318 | for (int i = 0; i < root_container.children->length; ++i) { | 304 | for (int i = 0; i < root->outputs->length; ++i) { |
319 | struct sway_container *output = root_container.children->items[i]; | 305 | struct sway_output *output = root->outputs->items[i]; |
320 | if ((result = output_find_container(output, test, data))) { | 306 | if ((result = output_find_container(output, test, data))) { |
321 | return result; | 307 | return result; |
322 | } | 308 | } |
323 | } | 309 | } |
324 | 310 | ||
325 | // Scratchpad | 311 | // Scratchpad |
326 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | 312 | for (int i = 0; i < root->scratchpad->length; ++i) { |
327 | struct sway_container *container = | 313 | struct sway_container *container = root->scratchpad->items[i]; |
328 | root_container.sway_root->scratchpad->items[i]; | ||
329 | if (!container->parent) { | 314 | if (!container->parent) { |
330 | if (test(container, data)) { | 315 | if (test(container, data)) { |
331 | return container; | 316 | return container; |
@@ -337,3 +322,10 @@ struct sway_container *root_find_container( | |||
337 | } | 322 | } |
338 | return NULL; | 323 | return NULL; |
339 | } | 324 | } |
325 | |||
326 | void root_get_box(struct sway_root *root, struct wlr_box *box) { | ||
327 | box->x = root->x; | ||
328 | box->y = root->y; | ||
329 | box->width = root->width; | ||
330 | box->height = root->height; | ||
331 | } | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index 6bd0ef67..452c2bd1 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -33,6 +33,8 @@ void view_init(struct sway_view *view, enum sway_view_type type, | |||
33 | view->marks = create_list(); | 33 | view->marks = create_list(); |
34 | view->allow_request_urgent = true; | 34 | view->allow_request_urgent = true; |
35 | wl_signal_init(&view->events.unmap); | 35 | wl_signal_init(&view->events.unmap); |
36 | |||
37 | view->container = container_create(view); | ||
36 | } | 38 | } |
37 | 39 | ||
38 | void view_destroy(struct sway_view *view) { | 40 | void view_destroy(struct sway_view *view) { |
@@ -43,8 +45,8 @@ void view_destroy(struct sway_view *view) { | |||
43 | "Tried to free view which wasn't marked as destroying")) { | 45 | "Tried to free view which wasn't marked as destroying")) { |
44 | return; | 46 | return; |
45 | } | 47 | } |
46 | if (!sway_assert(view->swayc == NULL, | 48 | if (!sway_assert(view->container == NULL, |
47 | "Tried to free view which still has a swayc " | 49 | "Tried to free view which still has a container " |
48 | "(might have a pending transaction?)")) { | 50 | "(might have a pending transaction?)")) { |
49 | return; | 51 | return; |
50 | } | 52 | } |
@@ -57,6 +59,7 @@ void view_destroy(struct sway_view *view) { | |||
57 | wlr_texture_destroy(view->marks_focused_inactive); | 59 | wlr_texture_destroy(view->marks_focused_inactive); |
58 | wlr_texture_destroy(view->marks_unfocused); | 60 | wlr_texture_destroy(view->marks_unfocused); |
59 | wlr_texture_destroy(view->marks_urgent); | 61 | wlr_texture_destroy(view->marks_urgent); |
62 | free(view->title_format); | ||
60 | 63 | ||
61 | if (view->impl->destroy) { | 64 | if (view->impl->destroy) { |
62 | view->impl->destroy(view); | 65 | view->impl->destroy(view); |
@@ -65,23 +68,13 @@ void view_destroy(struct sway_view *view) { | |||
65 | } | 68 | } |
66 | } | 69 | } |
67 | 70 | ||
68 | /** | ||
69 | * The view may or may not be involved in a transaction. For example, a view may | ||
70 | * unmap then attempt to destroy itself before we've applied the new layout. If | ||
71 | * an unmapping view is still involved in a transaction then it'll still have a | ||
72 | * swayc. | ||
73 | * | ||
74 | * If there's no transaction we can simply free the view. Otherwise the | ||
75 | * destroying flag will make the view get freed when the transaction is | ||
76 | * finished. | ||
77 | */ | ||
78 | void view_begin_destroy(struct sway_view *view) { | 71 | void view_begin_destroy(struct sway_view *view) { |
79 | if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { | 72 | if (!sway_assert(view->surface == NULL, "Tried to destroy a mapped view")) { |
80 | return; | 73 | return; |
81 | } | 74 | } |
82 | view->destroying = true; | 75 | view->destroying = true; |
83 | 76 | ||
84 | if (!view->swayc) { | 77 | if (!view->container) { |
85 | view_destroy(view); | 78 | view_destroy(view); |
86 | } | 79 | } |
87 | } | 80 | } |
@@ -171,30 +164,27 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, | |||
171 | } | 164 | } |
172 | 165 | ||
173 | void view_autoconfigure(struct sway_view *view) { | 166 | void view_autoconfigure(struct sway_view *view) { |
174 | if (!sway_assert(view->swayc, | 167 | struct sway_output *output = view->container->workspace->output; |
175 | "Called view_autoconfigure() on a view without a swayc")) { | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | ||
180 | 168 | ||
181 | if (view->swayc->is_fullscreen) { | 169 | if (view->container->is_fullscreen) { |
182 | view->x = output->x; | 170 | view->x = output->wlr_output->lx; |
183 | view->y = output->y; | 171 | view->y = output->wlr_output->ly; |
184 | view->width = output->width; | 172 | view->width = output->wlr_output->width; |
185 | view->height = output->height; | 173 | view->height = output->wlr_output->height; |
186 | return; | 174 | return; |
187 | } | 175 | } |
188 | 176 | ||
189 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 177 | struct sway_workspace *ws = view->container->workspace; |
190 | 178 | ||
191 | int other_views = 0; | 179 | bool other_views = false; |
192 | if (config->hide_edge_borders == E_SMART) { | 180 | if (config->hide_edge_borders == E_SMART) { |
193 | struct sway_container *con = view->swayc; | 181 | struct sway_container *con = view->container; |
194 | while (con != output) { | 182 | while (con) { |
195 | if (con->layout != L_TABBED && con->layout != L_STACKED) { | 183 | enum sway_container_layout layout = container_parent_layout(con); |
196 | other_views += con->children ? con->children->length - 1 : 0; | 184 | if (layout != L_TABBED && layout != L_STACKED) { |
197 | if (other_views > 0) { | 185 | list_t *siblings = container_get_siblings(con); |
186 | if (siblings && siblings->length > 1) { | ||
187 | other_views = true; | ||
198 | break; | 188 | break; |
199 | } | 189 | } |
200 | } | 190 | } |
@@ -202,7 +192,7 @@ void view_autoconfigure(struct sway_view *view) { | |||
202 | } | 192 | } |
203 | } | 193 | } |
204 | 194 | ||
205 | struct sway_container *con = view->swayc; | 195 | struct sway_container *con = view->container; |
206 | 196 | ||
207 | view->border_top = view->border_bottom = true; | 197 | view->border_top = view->border_bottom = true; |
208 | view->border_left = view->border_right = true; | 198 | view->border_left = view->border_right = true; |
@@ -228,7 +218,8 @@ void view_autoconfigure(struct sway_view *view) { | |||
228 | // In a tabbed or stacked container, the swayc's y is the bottom of the | 218 | // In a tabbed or stacked container, the swayc's y is the bottom of the |
229 | // title area. We have to disable any top border because the title bar is | 219 | // title area. We have to disable any top border because the title bar is |
230 | // rendered by the parent. | 220 | // rendered by the parent. |
231 | if (con->parent->layout == L_TABBED || con->parent->layout == L_STACKED) { | 221 | enum sway_container_layout layout = container_parent_layout(con); |
222 | if (layout == L_TABBED || layout == L_STACKED) { | ||
232 | view->border_top = false; | 223 | view->border_top = false; |
233 | } else { | 224 | } else { |
234 | y_offset = container_titlebar_height(); | 225 | y_offset = container_titlebar_height(); |
@@ -281,13 +272,16 @@ void view_set_activated(struct sway_view *view, bool activated) { | |||
281 | } | 272 | } |
282 | 273 | ||
283 | void view_request_activate(struct sway_view *view) { | 274 | void view_request_activate(struct sway_view *view) { |
284 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 275 | struct sway_workspace *ws = view->container->workspace; |
276 | if (!ws) { // hidden scratchpad container | ||
277 | return; | ||
278 | } | ||
285 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 279 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
286 | 280 | ||
287 | switch (config->focus_on_window_activation) { | 281 | switch (config->focus_on_window_activation) { |
288 | case FOWA_SMART: | 282 | case FOWA_SMART: |
289 | if (workspace_is_visible(ws)) { | 283 | if (workspace_is_visible(ws)) { |
290 | seat_set_focus(seat, view->swayc); | 284 | seat_set_focus(seat, &view->container->node); |
291 | } else { | 285 | } else { |
292 | view_set_urgent(view, true); | 286 | view_set_urgent(view, true); |
293 | } | 287 | } |
@@ -296,7 +290,7 @@ void view_request_activate(struct sway_view *view) { | |||
296 | view_set_urgent(view, true); | 290 | view_set_urgent(view, true); |
297 | break; | 291 | break; |
298 | case FOWA_FOCUS: | 292 | case FOWA_FOCUS: |
299 | seat_set_focus(seat, view->swayc); | 293 | seat_set_focus(seat, &view->container->node); |
300 | break; | 294 | break; |
301 | case FOWA_NONE: | 295 | case FOWA_NONE: |
302 | break; | 296 | break; |
@@ -331,23 +325,12 @@ void view_close_popups(struct sway_view *view) { | |||
331 | } | 325 | } |
332 | 326 | ||
333 | void view_damage_from(struct sway_view *view) { | 327 | void view_damage_from(struct sway_view *view) { |
334 | for (int i = 0; i < root_container.children->length; ++i) { | 328 | for (int i = 0; i < root->outputs->length; ++i) { |
335 | struct sway_container *cont = root_container.children->items[i]; | 329 | struct sway_output *output = root->outputs->items[i]; |
336 | if (cont->type == C_OUTPUT) { | 330 | output_damage_from_view(output, view); |
337 | output_damage_from_view(cont->sway_output, view); | ||
338 | } | ||
339 | } | 331 | } |
340 | } | 332 | } |
341 | 333 | ||
342 | static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { | ||
343 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | ||
344 | |||
345 | box->x = output->x + view->swayc->x; | ||
346 | box->y = output->y + view->swayc->y; | ||
347 | box->width = view->width; | ||
348 | box->height = view->height; | ||
349 | } | ||
350 | |||
351 | void view_for_each_surface(struct sway_view *view, | 334 | void view_for_each_surface(struct sway_view *view, |
352 | wlr_surface_iterator_func_t iterator, void *user_data) { | 335 | wlr_surface_iterator_func_t iterator, void *user_data) { |
353 | if (!view->surface) { | 336 | if (!view->surface) { |
@@ -396,11 +379,8 @@ static bool view_has_executed_criteria(struct sway_view *view, | |||
396 | } | 379 | } |
397 | 380 | ||
398 | void view_execute_criteria(struct sway_view *view) { | 381 | void view_execute_criteria(struct sway_view *view) { |
399 | if (!view->swayc) { | ||
400 | return; | ||
401 | } | ||
402 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 382 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
403 | struct sway_container *prior_focus = seat_get_focus(seat); | 383 | struct sway_node *prior_focus = seat_get_focus(seat); |
404 | list_t *criterias = criteria_for_view(view, CT_COMMAND); | 384 | list_t *criterias = criteria_for_view(view, CT_COMMAND); |
405 | for (int i = 0; i < criterias->length; i++) { | 385 | for (int i = 0; i < criterias->length; i++) { |
406 | struct criteria *criteria = criterias->items[i]; | 386 | struct criteria *criteria = criterias->items[i]; |
@@ -411,7 +391,7 @@ void view_execute_criteria(struct sway_view *view) { | |||
411 | } | 391 | } |
412 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", | 392 | wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", |
413 | criteria->raw, view, criteria->cmdlist); | 393 | criteria->raw, view, criteria->cmdlist); |
414 | seat_set_focus(seat, view->swayc); | 394 | seat_set_focus(seat, &view->container->node); |
415 | list_add(view->executed_criteria, criteria); | 395 | list_add(view->executed_criteria, criteria); |
416 | struct cmd_results *res = execute_command(criteria->cmdlist, NULL); | 396 | struct cmd_results *res = execute_command(criteria->cmdlist, NULL); |
417 | if (res->status != CMD_SUCCESS) { | 397 | if (res->status != CMD_SUCCESS) { |
@@ -423,19 +403,19 @@ void view_execute_criteria(struct sway_view *view) { | |||
423 | seat_set_focus(seat, prior_focus); | 403 | seat_set_focus(seat, prior_focus); |
424 | } | 404 | } |
425 | 405 | ||
426 | static struct sway_container *select_workspace(struct sway_view *view) { | 406 | static struct sway_workspace *select_workspace(struct sway_view *view) { |
427 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 407 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
428 | 408 | ||
429 | // Check if there's any `assign` criteria for the view | 409 | // Check if there's any `assign` criteria for the view |
430 | list_t *criterias = criteria_for_view(view, | 410 | list_t *criterias = criteria_for_view(view, |
431 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT); | 411 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT); |
432 | struct sway_container *ws = NULL; | 412 | struct sway_workspace *ws = NULL; |
433 | for (int i = 0; i < criterias->length; ++i) { | 413 | for (int i = 0; i < criterias->length; ++i) { |
434 | struct criteria *criteria = criterias->items[i]; | 414 | struct criteria *criteria = criterias->items[i]; |
435 | if (criteria->type == CT_ASSIGN_OUTPUT) { | 415 | if (criteria->type == CT_ASSIGN_OUTPUT) { |
436 | struct sway_container *output = output_by_name(criteria->target); | 416 | struct sway_output *output = output_by_name(criteria->target); |
437 | if (output) { | 417 | if (output) { |
438 | ws = seat_get_active_child(seat, output); | 418 | ws = output_get_active_workspace(output); |
439 | break; | 419 | break; |
440 | } | 420 | } |
441 | } else { | 421 | } else { |
@@ -484,20 +464,14 @@ static struct sway_container *select_workspace(struct sway_view *view) { | |||
484 | } | 464 | } |
485 | 465 | ||
486 | // Use the focused workspace | 466 | // Use the focused workspace |
487 | ws = seat_get_focus_inactive(seat, &root_container); | 467 | return seat_get_focused_workspace(seat); |
488 | if (ws->type != C_WORKSPACE) { | ||
489 | ws = container_parent(ws, C_WORKSPACE); | ||
490 | } | ||
491 | return ws; | ||
492 | } | 468 | } |
493 | 469 | ||
494 | static bool should_focus(struct sway_view *view) { | 470 | static bool should_focus(struct sway_view *view) { |
495 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 471 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
496 | struct sway_container *prev_focus = | 472 | struct sway_container *prev_con = seat_get_focused_container(seat); |
497 | seat_get_focus_inactive(seat, &root_container); | 473 | struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); |
498 | struct sway_container *prev_ws = prev_focus->type == C_WORKSPACE ? | 474 | struct sway_workspace *map_ws = view->container->workspace; |
499 | prev_focus : container_parent(prev_focus, C_WORKSPACE); | ||
500 | struct sway_container *map_ws = container_parent(view->swayc, C_WORKSPACE); | ||
501 | 475 | ||
502 | // Views can only take focus if they are mapped into the active workspace | 476 | // Views can only take focus if they are mapped into the active workspace |
503 | if (prev_ws != map_ws) { | 477 | if (prev_ws != map_ws) { |
@@ -506,10 +480,9 @@ static bool should_focus(struct sway_view *view) { | |||
506 | 480 | ||
507 | // If the view is the only one in the focused workspace, it'll get focus | 481 | // If the view is the only one in the focused workspace, it'll get focus |
508 | // regardless of any no_focus criteria. | 482 | // regardless of any no_focus criteria. |
509 | struct sway_container *parent = view->swayc->parent; | 483 | if (!view->container->parent && !prev_con) { |
510 | if (parent->type == C_WORKSPACE && prev_focus == parent) { | 484 | size_t num_children = view->container->workspace->tiling->length + |
511 | size_t num_children = parent->children->length + | 485 | view->container->workspace->floating->length; |
512 | parent->sway_workspace->floating->length; | ||
513 | if (num_children == 1) { | 486 | if (num_children == 1) { |
514 | return true; | 487 | return true; |
515 | } | 488 | } |
@@ -529,16 +502,24 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
529 | view->surface = wlr_surface; | 502 | view->surface = wlr_surface; |
530 | 503 | ||
531 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 504 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
532 | struct sway_container *ws = select_workspace(view); | 505 | struct sway_workspace *ws = select_workspace(view); |
533 | struct sway_container *target_sibling = seat_get_focus_inactive(seat, ws); | 506 | struct sway_node *node = seat_get_focus_inactive(seat, &ws->node); |
507 | struct sway_container *target_sibling = node->type == N_CONTAINER ? | ||
508 | node->sway_container : NULL; | ||
534 | 509 | ||
535 | // If we're about to launch the view into the floating container, then | 510 | // If we're about to launch the view into the floating container, then |
536 | // launch it as a tiled view in the root of the workspace instead. | 511 | // launch it as a tiled view in the root of the workspace instead. |
537 | if (container_is_floating(target_sibling)) { | 512 | if (target_sibling && container_is_floating(target_sibling)) { |
538 | target_sibling = target_sibling->parent; | 513 | target_sibling = NULL; |
539 | } | 514 | } |
540 | 515 | ||
541 | view->swayc = container_view_create(target_sibling, view); | 516 | view->container = container_create(view); |
517 | if (target_sibling) { | ||
518 | container_add_sibling(target_sibling, view->container, 1); | ||
519 | } else { | ||
520 | workspace_add_tiling(ws, view->container); | ||
521 | } | ||
522 | ipc_event_window(view->container, "new"); | ||
542 | 523 | ||
543 | view_init_subsurfaces(view, wlr_surface); | 524 | view_init_subsurfaces(view, wlr_surface); |
544 | wl_signal_add(&wlr_surface->events.new_subsurface, | 525 | wl_signal_add(&wlr_surface->events.new_subsurface, |
@@ -548,7 +529,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
548 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { | 529 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { |
549 | view->border = config->floating_border; | 530 | view->border = config->floating_border; |
550 | view->border_thickness = config->floating_border_thickness; | 531 | view->border_thickness = config->floating_border_thickness; |
551 | container_set_floating(view->swayc, true); | 532 | container_set_floating(view->container, true); |
552 | } else { | 533 | } else { |
553 | view->border = config->border; | 534 | view->border = config->border; |
554 | view->border_thickness = config->border_thickness; | 535 | view->border_thickness = config->border_thickness; |
@@ -556,11 +537,11 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
556 | } | 537 | } |
557 | 538 | ||
558 | if (should_focus(view)) { | 539 | if (should_focus(view)) { |
559 | input_manager_set_focus(input_manager, view->swayc); | 540 | input_manager_set_focus(input_manager, &view->container->node); |
560 | } | 541 | } |
561 | 542 | ||
562 | view_update_title(view, false); | 543 | view_update_title(view, false); |
563 | container_notify_subtree_changed(view->swayc->parent); | 544 | container_update_representation(view->container); |
564 | view_execute_criteria(view); | 545 | view_execute_criteria(view); |
565 | } | 546 | } |
566 | 547 | ||
@@ -574,17 +555,17 @@ void view_unmap(struct sway_view *view) { | |||
574 | view->urgent_timer = NULL; | 555 | view->urgent_timer = NULL; |
575 | } | 556 | } |
576 | 557 | ||
577 | bool was_fullscreen = view->swayc->is_fullscreen; | 558 | struct sway_container *parent = view->container->parent; |
578 | struct sway_container *parent = view->swayc->parent; | 559 | struct sway_workspace *ws = view->container->workspace; |
579 | container_begin_destroy(view->swayc); | 560 | container_begin_destroy(view->container); |
580 | struct sway_container *surviving_ancestor = container_reap_empty(parent); | 561 | if (parent) { |
562 | container_reap_empty(parent); | ||
563 | } else { | ||
564 | workspace_consider_destroy(ws); | ||
565 | } | ||
581 | 566 | ||
582 | // If the workspace wasn't reaped | 567 | if (!ws->node.destroying) { |
583 | if (surviving_ancestor && surviving_ancestor->type >= C_WORKSPACE) { | 568 | arrange_workspace(ws); |
584 | struct sway_container *ws = surviving_ancestor->type == C_WORKSPACE ? | ||
585 | surviving_ancestor : | ||
586 | container_parent(surviving_ancestor, C_WORKSPACE); | ||
587 | arrange_windows(was_fullscreen ? ws : surviving_ancestor); | ||
588 | workspace_detect_urgent(ws); | 569 | workspace_detect_urgent(ws); |
589 | } | 570 | } |
590 | 571 | ||
@@ -593,15 +574,15 @@ void view_unmap(struct sway_view *view) { | |||
593 | } | 574 | } |
594 | 575 | ||
595 | void view_update_size(struct sway_view *view, int width, int height) { | 576 | void view_update_size(struct sway_view *view, int width, int height) { |
596 | if (!sway_assert(container_is_floating(view->swayc), | 577 | if (!sway_assert(container_is_floating(view->container), |
597 | "Expected a floating container")) { | 578 | "Expected a floating container")) { |
598 | return; | 579 | return; |
599 | } | 580 | } |
600 | view->width = width; | 581 | view->width = width; |
601 | view->height = height; | 582 | view->height = height; |
602 | view->swayc->current.view_width = width; | 583 | view->container->current.view_width = width; |
603 | view->swayc->current.view_height = height; | 584 | view->container->current.view_height = height; |
604 | container_set_geometry_from_floating_view(view->swayc); | 585 | container_set_geometry_from_floating_view(view->container); |
605 | } | 586 | } |
606 | 587 | ||
607 | static void view_subsurface_create(struct sway_view *view, | 588 | static void view_subsurface_create(struct sway_view *view, |
@@ -670,27 +651,18 @@ void view_child_init(struct sway_view_child *child, | |||
670 | wl_signal_add(&view->events.unmap, &child->view_unmap); | 651 | wl_signal_add(&view->events.unmap, &child->view_unmap); |
671 | child->view_unmap.notify = view_child_handle_view_unmap; | 652 | child->view_unmap.notify = view_child_handle_view_unmap; |
672 | 653 | ||
673 | struct sway_container *output = child->view->swayc->parent; | 654 | struct sway_output *output = child->view->container->workspace->output; |
674 | if (output != NULL) { | 655 | wlr_surface_send_enter(child->surface, output->wlr_output); |
675 | if (output->type != C_OUTPUT) { | ||
676 | output = container_parent(output, C_OUTPUT); | ||
677 | } | ||
678 | wlr_surface_send_enter(child->surface, output->sway_output->wlr_output); | ||
679 | } | ||
680 | 656 | ||
681 | view_init_subsurfaces(child->view, surface); | 657 | view_init_subsurfaces(child->view, surface); |
682 | 658 | ||
683 | // TODO: only damage the whole child | 659 | // TODO: only damage the whole child |
684 | if (child->view->swayc) { | 660 | container_damage_whole(child->view->container); |
685 | container_damage_whole(child->view->swayc); | ||
686 | } | ||
687 | } | 661 | } |
688 | 662 | ||
689 | void view_child_destroy(struct sway_view_child *child) { | 663 | void view_child_destroy(struct sway_view_child *child) { |
690 | // TODO: only damage the whole child | 664 | // TODO: only damage the whole child |
691 | if (child->view->swayc) { | 665 | container_damage_whole(child->view->container); |
692 | container_damage_whole(child->view->swayc); | ||
693 | } | ||
694 | 666 | ||
695 | wl_list_remove(&child->surface_commit.link); | 667 | wl_list_remove(&child->surface_commit.link); |
696 | wl_list_remove(&child->surface_destroy.link); | 668 | wl_list_remove(&child->surface_destroy.link); |
@@ -808,22 +780,20 @@ static char *escape_title(char *buffer) { | |||
808 | } | 780 | } |
809 | 781 | ||
810 | void view_update_title(struct sway_view *view, bool force) { | 782 | void view_update_title(struct sway_view *view, bool force) { |
811 | if (!view->swayc) { | ||
812 | return; | ||
813 | } | ||
814 | const char *title = view_get_title(view); | 783 | const char *title = view_get_title(view); |
815 | 784 | ||
816 | if (!force) { | 785 | if (!force) { |
817 | if (title && view->swayc->name && strcmp(title, view->swayc->name) == 0) { | 786 | if (title && view->container->title && |
787 | strcmp(title, view->container->title) == 0) { | ||
818 | return; | 788 | return; |
819 | } | 789 | } |
820 | if (!title && !view->swayc->name) { | 790 | if (!title && !view->container->title) { |
821 | return; | 791 | return; |
822 | } | 792 | } |
823 | } | 793 | } |
824 | 794 | ||
825 | free(view->swayc->name); | 795 | free(view->container->title); |
826 | free(view->swayc->formatted_title); | 796 | free(view->container->formatted_title); |
827 | if (title) { | 797 | if (title) { |
828 | size_t len = parse_title_format(view, NULL); | 798 | size_t len = parse_title_format(view, NULL); |
829 | char *buffer = calloc(len + 1, sizeof(char)); | 799 | char *buffer = calloc(len + 1, sizeof(char)); |
@@ -836,25 +806,25 @@ void view_update_title(struct sway_view *view, bool force) { | |||
836 | buffer = escape_title(buffer); | 806 | buffer = escape_title(buffer); |
837 | } | 807 | } |
838 | 808 | ||
839 | view->swayc->name = strdup(title); | 809 | view->container->title = strdup(title); |
840 | view->swayc->formatted_title = buffer; | 810 | view->container->formatted_title = buffer; |
841 | } else { | 811 | } else { |
842 | view->swayc->name = NULL; | 812 | view->container->title = NULL; |
843 | view->swayc->formatted_title = NULL; | 813 | view->container->formatted_title = NULL; |
844 | } | 814 | } |
845 | container_calculate_title_height(view->swayc); | 815 | container_calculate_title_height(view->container); |
846 | config_update_font_height(false); | 816 | config_update_font_height(false); |
847 | 817 | ||
848 | // Update title after the global font height is updated | 818 | // Update title after the global font height is updated |
849 | container_update_title_textures(view->swayc); | 819 | container_update_title_textures(view->container); |
850 | 820 | ||
851 | ipc_event_window(view->swayc, "title"); | 821 | ipc_event_window(view->container, "title"); |
852 | } | 822 | } |
853 | 823 | ||
854 | static bool find_by_mark_iterator(struct sway_container *con, | 824 | static bool find_by_mark_iterator(struct sway_container *con, |
855 | void *data) { | 825 | void *data) { |
856 | char *mark = data; | 826 | char *mark = data; |
857 | return con->type == C_VIEW && view_has_mark(con->sway_view, mark); | 827 | return con->view && view_has_mark(con->view, mark); |
858 | } | 828 | } |
859 | 829 | ||
860 | struct sway_view *view_find_mark(char *mark) { | 830 | struct sway_view *view_find_mark(char *mark) { |
@@ -863,7 +833,7 @@ struct sway_view *view_find_mark(char *mark) { | |||
863 | if (!container) { | 833 | if (!container) { |
864 | return NULL; | 834 | return NULL; |
865 | } | 835 | } |
866 | return container->sway_view; | 836 | return container->view; |
867 | } | 837 | } |
868 | 838 | ||
869 | bool view_find_and_unmark(char *mark) { | 839 | bool view_find_and_unmark(char *mark) { |
@@ -872,7 +842,7 @@ bool view_find_and_unmark(char *mark) { | |||
872 | if (!container) { | 842 | if (!container) { |
873 | return false; | 843 | return false; |
874 | } | 844 | } |
875 | struct sway_view *view = container->sway_view; | 845 | struct sway_view *view = container->view; |
876 | 846 | ||
877 | for (int i = 0; i < view->marks->length; ++i) { | 847 | for (int i = 0; i < view->marks->length; ++i) { |
878 | char *view_mark = view->marks->items[i]; | 848 | char *view_mark = view->marks->items[i]; |
@@ -888,10 +858,9 @@ bool view_find_and_unmark(char *mark) { | |||
888 | } | 858 | } |
889 | 859 | ||
890 | void view_clear_marks(struct sway_view *view) { | 860 | void view_clear_marks(struct sway_view *view) { |
891 | while (view->marks->length) { | 861 | list_foreach(view->marks, free); |
892 | list_del(view->marks, 0); | 862 | view->marks->length = 0; |
893 | ipc_event_window(view->swayc, "mark"); | 863 | ipc_event_window(view->container, "mark"); |
894 | } | ||
895 | } | 864 | } |
896 | 865 | ||
897 | bool view_has_mark(struct sway_view *view, char *mark) { | 866 | bool view_has_mark(struct sway_view *view, char *mark) { |
@@ -906,12 +875,13 @@ bool view_has_mark(struct sway_view *view, char *mark) { | |||
906 | 875 | ||
907 | void view_add_mark(struct sway_view *view, char *mark) { | 876 | void view_add_mark(struct sway_view *view, char *mark) { |
908 | list_add(view->marks, strdup(mark)); | 877 | list_add(view->marks, strdup(mark)); |
909 | ipc_event_window(view->swayc, "mark"); | 878 | ipc_event_window(view->container, "mark"); |
910 | } | 879 | } |
911 | 880 | ||
912 | static void update_marks_texture(struct sway_view *view, | 881 | static void update_marks_texture(struct sway_view *view, |
913 | struct wlr_texture **texture, struct border_colors *class) { | 882 | struct wlr_texture **texture, struct border_colors *class) { |
914 | struct sway_output *output = container_get_effective_output(view->swayc); | 883 | struct sway_output *output = |
884 | container_get_effective_output(view->container); | ||
915 | if (!output) { | 885 | if (!output) { |
916 | return; | 886 | return; |
917 | } | 887 | } |
@@ -949,7 +919,7 @@ static void update_marks_texture(struct sway_view *view, | |||
949 | 919 | ||
950 | double scale = output->wlr_output->scale; | 920 | double scale = output->wlr_output->scale; |
951 | int width = 0; | 921 | int width = 0; |
952 | int height = view->swayc->title_height * scale; | 922 | int height = view->container->title_height * scale; |
953 | 923 | ||
954 | cairo_t *c = cairo_create(NULL); | 924 | cairo_t *c = cairo_create(NULL); |
955 | get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); | 925 | get_text_size(c, config->font, &width, NULL, scale, false, "%s", buffer); |
@@ -994,44 +964,40 @@ void view_update_marks_textures(struct sway_view *view) { | |||
994 | &config->border_colors.unfocused); | 964 | &config->border_colors.unfocused); |
995 | update_marks_texture(view, &view->marks_urgent, | 965 | update_marks_texture(view, &view->marks_urgent, |
996 | &config->border_colors.urgent); | 966 | &config->border_colors.urgent); |
997 | container_damage_whole(view->swayc); | 967 | container_damage_whole(view->container); |
998 | } | 968 | } |
999 | 969 | ||
1000 | bool view_is_visible(struct sway_view *view) { | 970 | bool view_is_visible(struct sway_view *view) { |
1001 | if (!view->swayc || view->swayc->destroying) { | 971 | if (view->container->node.destroying) { |
1002 | return false; | 972 | return false; |
1003 | } | 973 | } |
1004 | struct sway_container *workspace = | 974 | struct sway_workspace *workspace = view->container->workspace; |
1005 | container_parent(view->swayc, C_WORKSPACE); | ||
1006 | if (!workspace) { | 975 | if (!workspace) { |
1007 | return false; | 976 | return false; |
1008 | } | 977 | } |
1009 | // Determine if view is nested inside a floating container which is sticky. | 978 | // Determine if view is nested inside a floating container which is sticky |
1010 | // A simple floating view will have this ancestry: | 979 | struct sway_container *floater = view->container; |
1011 | // C_VIEW -> floating -> workspace | 980 | while (floater->parent) { |
1012 | // A more complex ancestry could be: | ||
1013 | // C_VIEW -> C_CONTAINER (tabbed) -> floating -> workspace | ||
1014 | struct sway_container *floater = view->swayc; | ||
1015 | while (floater->parent->type != C_WORKSPACE | ||
1016 | && floater->parent->parent->type != C_WORKSPACE) { | ||
1017 | floater = floater->parent; | 981 | floater = floater->parent; |
1018 | } | 982 | } |
1019 | bool is_sticky = container_is_floating(floater) && floater->is_sticky; | 983 | bool is_sticky = container_is_floating(floater) && floater->is_sticky; |
1020 | // Check view isn't in a tabbed or stacked container on an inactive tab | 984 | // Check view isn't in a tabbed or stacked container on an inactive tab |
1021 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 985 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
1022 | struct sway_container *container = view->swayc; | 986 | struct sway_container *container = view->container; |
1023 | while (container->type != C_WORKSPACE) { | 987 | while (container) { |
1024 | if (container->parent->layout == L_TABBED || | 988 | enum sway_container_layout layout = container_parent_layout(container); |
1025 | container->parent->layout == L_STACKED) { | 989 | if (layout == L_TABBED || layout == L_STACKED) { |
1026 | if (seat_get_active_child(seat, container->parent) != container) { | 990 | struct sway_node *parent = container->parent ? |
991 | &container->parent->node : &container->workspace->node; | ||
992 | if (seat_get_active_child(seat, parent) != &container->node) { | ||
1027 | return false; | 993 | return false; |
1028 | } | 994 | } |
1029 | } | 995 | } |
1030 | container = container->parent; | 996 | container = container->parent; |
1031 | } | 997 | } |
1032 | // Check view isn't hidden by another fullscreen view | 998 | // Check view isn't hidden by another fullscreen view |
1033 | if (workspace->sway_workspace->fullscreen && | 999 | if (workspace->fullscreen && |
1034 | !container_is_fullscreen_or_child(view->swayc)) { | 1000 | !container_is_fullscreen_or_child(view->container)) { |
1035 | return false; | 1001 | return false; |
1036 | } | 1002 | } |
1037 | // Check the workspace is visible | 1003 | // Check the workspace is visible |
@@ -1047,7 +1013,7 @@ void view_set_urgent(struct sway_view *view, bool enable) { | |||
1047 | } | 1013 | } |
1048 | if (enable) { | 1014 | if (enable) { |
1049 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 1015 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
1050 | if (seat_get_focus(seat) == view->swayc) { | 1016 | if (seat_get_focused_container(seat) == view->container) { |
1051 | return; | 1017 | return; |
1052 | } | 1018 | } |
1053 | clock_gettime(CLOCK_MONOTONIC, &view->urgent); | 1019 | clock_gettime(CLOCK_MONOTONIC, &view->urgent); |
@@ -1058,12 +1024,11 @@ void view_set_urgent(struct sway_view *view, bool enable) { | |||
1058 | view->urgent_timer = NULL; | 1024 | view->urgent_timer = NULL; |
1059 | } | 1025 | } |
1060 | } | 1026 | } |
1061 | container_damage_whole(view->swayc); | 1027 | container_damage_whole(view->container); |
1062 | 1028 | ||
1063 | ipc_event_window(view->swayc, "urgent"); | 1029 | ipc_event_window(view->container, "urgent"); |
1064 | 1030 | ||
1065 | struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); | 1031 | workspace_detect_urgent(view->container->workspace); |
1066 | workspace_detect_urgent(ws); | ||
1067 | } | 1032 | } |
1068 | 1033 | ||
1069 | bool view_is_urgent(struct sway_view *view) { | 1034 | bool view_is_urgent(struct sway_view *view) { |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 1957d94f..38ee478e 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -12,128 +12,105 @@ | |||
12 | #include "sway/output.h" | 12 | #include "sway/output.h" |
13 | #include "sway/tree/arrange.h" | 13 | #include "sway/tree/arrange.h" |
14 | #include "sway/tree/container.h" | 14 | #include "sway/tree/container.h" |
15 | #include "sway/tree/node.h" | ||
15 | #include "sway/tree/view.h" | 16 | #include "sway/tree/view.h" |
16 | #include "sway/tree/workspace.h" | 17 | #include "sway/tree/workspace.h" |
17 | #include "list.h" | 18 | #include "list.h" |
18 | #include "log.h" | 19 | #include "log.h" |
19 | #include "util.h" | 20 | #include "util.h" |
20 | 21 | ||
21 | struct sway_container *workspace_get_initial_output(const char *name) { | 22 | struct sway_output *workspace_get_initial_output(const char *name) { |
22 | struct sway_container *parent; | ||
23 | // Search for workspace<->output pair | 23 | // Search for workspace<->output pair |
24 | int e = config->workspace_outputs->length; | ||
25 | for (int i = 0; i < config->workspace_outputs->length; ++i) { | 24 | for (int i = 0; i < config->workspace_outputs->length; ++i) { |
26 | struct workspace_output *wso = config->workspace_outputs->items[i]; | 25 | struct workspace_output *wso = config->workspace_outputs->items[i]; |
27 | if (strcasecmp(wso->workspace, name) == 0) { | 26 | if (strcasecmp(wso->workspace, name) == 0) { |
28 | // Find output to use if it exists | 27 | // Find output to use if it exists |
29 | e = root_container.children->length; | 28 | struct sway_output *output = output_by_name(wso->output); |
30 | for (i = 0; i < e; ++i) { | 29 | if (output) { |
31 | parent = root_container.children->items[i]; | 30 | return output; |
32 | if (strcmp(parent->name, wso->output) == 0) { | ||
33 | return parent; | ||
34 | } | ||
35 | } | 31 | } |
36 | break; | 32 | break; |
37 | } | 33 | } |
38 | } | 34 | } |
39 | // Otherwise put it on the focused output | 35 | // Otherwise put it on the focused output |
40 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 36 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
41 | struct sway_container *focus = | 37 | struct sway_workspace *focus = seat_get_focused_workspace(seat); |
42 | seat_get_focus_inactive(seat, &root_container); | 38 | return focus->output; |
43 | parent = focus; | ||
44 | parent = container_parent(parent, C_OUTPUT); | ||
45 | return parent; | ||
46 | } | 39 | } |
47 | 40 | ||
48 | struct sway_container *workspace_create(struct sway_container *output, | 41 | struct sway_workspace *workspace_create(struct sway_output *output, |
49 | const char *name) { | 42 | const char *name) { |
50 | if (output == NULL) { | 43 | if (output == NULL) { |
51 | output = workspace_get_initial_output(name); | 44 | output = workspace_get_initial_output(name); |
52 | } | 45 | } |
53 | 46 | ||
54 | wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); | 47 | wlr_log(WLR_DEBUG, "Adding workspace %s for output %s", name, |
55 | struct sway_container *workspace = container_create(C_WORKSPACE); | 48 | output->wlr_output->name); |
56 | |||
57 | workspace->x = output->x; | ||
58 | workspace->y = output->y; | ||
59 | workspace->width = output->width; | ||
60 | workspace->height = output->height; | ||
61 | workspace->name = !name ? NULL : strdup(name); | ||
62 | workspace->prev_split_layout = L_NONE; | ||
63 | workspace->layout = container_get_default_layout(output); | ||
64 | 49 | ||
65 | struct sway_workspace *swayws = calloc(1, sizeof(struct sway_workspace)); | 50 | struct sway_workspace *ws = calloc(1, sizeof(struct sway_workspace)); |
66 | if (!swayws) { | 51 | if (!ws) { |
52 | wlr_log(WLR_ERROR, "Unable to allocate sway_workspace"); | ||
67 | return NULL; | 53 | return NULL; |
68 | } | 54 | } |
69 | swayws->swayc = workspace; | 55 | node_init(&ws->node, N_WORKSPACE, ws); |
70 | swayws->floating = create_list(); | 56 | ws->x = output->wlr_output->lx; |
71 | swayws->output_priority = create_list(); | 57 | ws->y = output->wlr_output->ly; |
72 | workspace->sway_workspace = swayws; | 58 | ws->width = output->wlr_output->width; |
73 | workspace_output_add_priority(workspace, output); | 59 | ws->height = output->wlr_output->height; |
74 | 60 | ws->name = name ? strdup(name) : NULL; | |
75 | container_add_child(output, workspace); | 61 | ws->prev_split_layout = L_NONE; |
62 | ws->layout = output_get_default_layout(output); | ||
63 | ws->floating = create_list(); | ||
64 | ws->tiling = create_list(); | ||
65 | ws->output_priority = create_list(); | ||
66 | workspace_output_add_priority(ws, output); | ||
67 | |||
68 | output_add_workspace(output, ws); | ||
76 | output_sort_workspaces(output); | 69 | output_sort_workspaces(output); |
77 | container_create_notify(workspace); | ||
78 | 70 | ||
79 | return workspace; | 71 | ipc_event_workspace(NULL, ws, "init"); |
72 | wl_signal_emit(&root->events.new_node, &ws->node); | ||
73 | |||
74 | return ws; | ||
80 | } | 75 | } |
81 | 76 | ||
82 | void workspace_destroy(struct sway_container *workspace) { | 77 | void workspace_destroy(struct sway_workspace *workspace) { |
83 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 78 | if (!sway_assert(workspace->node.destroying, |
84 | return; | ||
85 | } | ||
86 | if (!sway_assert(workspace->destroying, | ||
87 | "Tried to free workspace which wasn't marked as destroying")) { | 79 | "Tried to free workspace which wasn't marked as destroying")) { |
88 | return; | 80 | return; |
89 | } | 81 | } |
90 | if (!sway_assert(workspace->ntxnrefs == 0, "Tried to free workspace " | 82 | if (!sway_assert(workspace->node.ntxnrefs == 0, "Tried to free workspace " |
91 | "which is still referenced by transactions")) { | 83 | "which is still referenced by transactions")) { |
92 | return; | 84 | return; |
93 | } | 85 | } |
94 | // sway_workspace | ||
95 | struct sway_workspace *ws = workspace->sway_workspace; | ||
96 | list_foreach(ws->output_priority, free); | ||
97 | list_free(ws->output_priority); | ||
98 | list_free(ws->floating); | ||
99 | free(ws); | ||
100 | 86 | ||
101 | // swayc | ||
102 | free(workspace->name); | 87 | free(workspace->name); |
103 | free(workspace->formatted_title); | 88 | free(workspace->representation); |
104 | wlr_texture_destroy(workspace->title_focused); | 89 | list_foreach(workspace->output_priority, free); |
105 | wlr_texture_destroy(workspace->title_focused_inactive); | 90 | list_free(workspace->output_priority); |
106 | wlr_texture_destroy(workspace->title_unfocused); | 91 | list_free(workspace->floating); |
107 | wlr_texture_destroy(workspace->title_urgent); | 92 | list_free(workspace->tiling); |
108 | list_free(workspace->children); | 93 | list_free(workspace->current.floating); |
109 | list_free(workspace->current.children); | 94 | list_free(workspace->current.tiling); |
110 | list_free(workspace->outputs); | ||
111 | free(workspace); | 95 | free(workspace); |
112 | } | 96 | } |
113 | 97 | ||
114 | void workspace_begin_destroy(struct sway_container *workspace) { | 98 | void workspace_begin_destroy(struct sway_workspace *workspace) { |
115 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | ||
116 | return; | ||
117 | } | ||
118 | wlr_log(WLR_DEBUG, "Destroying workspace '%s'", workspace->name); | 99 | wlr_log(WLR_DEBUG, "Destroying workspace '%s'", workspace->name); |
119 | wl_signal_emit(&workspace->events.destroy, workspace); | ||
120 | ipc_event_workspace(NULL, workspace, "empty"); // intentional | 100 | ipc_event_workspace(NULL, workspace, "empty"); // intentional |
101 | wl_signal_emit(&workspace->node.events.destroy, &workspace->node); | ||
121 | 102 | ||
122 | workspace->destroying = true; | 103 | if (workspace->output) { |
123 | container_set_dirty(workspace); | 104 | workspace_detach(workspace); |
124 | |||
125 | if (workspace->parent) { | ||
126 | container_remove_child(workspace); | ||
127 | } | 105 | } |
106 | |||
107 | workspace->node.destroying = true; | ||
108 | node_set_dirty(&workspace->node); | ||
128 | } | 109 | } |
129 | 110 | ||
130 | void workspace_consider_destroy(struct sway_container *ws) { | 111 | void workspace_consider_destroy(struct sway_workspace *ws) { |
131 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | 112 | if (ws->tiling->length == 0 && ws->floating->length == 0 |
132 | return; | 113 | && output_get_active_workspace(ws->output) != ws) { |
133 | } | ||
134 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
135 | if (ws->children->length == 0 && ws->sway_workspace->floating->length == 0 | ||
136 | && seat_get_active_child(seat, ws->parent) != ws) { | ||
137 | workspace_begin_destroy(ws); | 114 | workspace_begin_destroy(ws); |
138 | } | 115 | } |
139 | } | 116 | } |
@@ -272,59 +249,49 @@ char *workspace_next_name(const char *output_name) { | |||
272 | } | 249 | } |
273 | // As a fall back, get the current number of active workspaces | 250 | // As a fall back, get the current number of active workspaces |
274 | // and return that + 1 for the next workspace's name | 251 | // and return that + 1 for the next workspace's name |
275 | int ws_num = root_container.children->length; | 252 | int ws_num = root->outputs->length; |
276 | int l = snprintf(NULL, 0, "%d", ws_num); | 253 | int l = snprintf(NULL, 0, "%d", ws_num); |
277 | char *name = malloc(l + 1); | 254 | char *name = malloc(l + 1); |
278 | if (!sway_assert(name, "Cloud not allocate workspace name")) { | 255 | if (!sway_assert(name, "Could not allocate workspace name")) { |
279 | return NULL; | 256 | return NULL; |
280 | } | 257 | } |
281 | sprintf(name, "%d", ws_num++); | 258 | sprintf(name, "%d", ws_num++); |
282 | return name; | 259 | return name; |
283 | } | 260 | } |
284 | 261 | ||
285 | static bool _workspace_by_number(struct sway_container *view, void *data) { | 262 | static bool _workspace_by_number(struct sway_workspace *ws, void *data) { |
286 | if (view->type != C_WORKSPACE) { | ||
287 | return false; | ||
288 | } | ||
289 | char *name = data; | 263 | char *name = data; |
290 | char *view_name = view->name; | 264 | char *ws_name = ws->name; |
291 | while (isdigit(*name)) { | 265 | while (isdigit(*name)) { |
292 | if (*name++ != *view_name++) { | 266 | if (*name++ != *ws_name++) { |
293 | return false; | 267 | return false; |
294 | } | 268 | } |
295 | } | 269 | } |
296 | return !isdigit(*view_name); | 270 | return !isdigit(*ws_name); |
297 | } | 271 | } |
298 | 272 | ||
299 | struct sway_container *workspace_by_number(const char* name) { | 273 | struct sway_workspace *workspace_by_number(const char* name) { |
300 | return root_find_workspace(_workspace_by_number, (void *) name); | 274 | return root_find_workspace(_workspace_by_number, (void *) name); |
301 | } | 275 | } |
302 | 276 | ||
303 | static bool _workspace_by_name(struct sway_container *view, void *data) { | 277 | static bool _workspace_by_name(struct sway_workspace *ws, void *data) { |
304 | return (view->type == C_WORKSPACE) && | 278 | return strcasecmp(ws->name, data) == 0; |
305 | (strcasecmp(view->name, (char *) data) == 0); | ||
306 | } | 279 | } |
307 | 280 | ||
308 | struct sway_container *workspace_by_name(const char *name) { | 281 | struct sway_workspace *workspace_by_name(const char *name) { |
309 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 282 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
310 | struct sway_container *current_workspace = NULL, *current_output = NULL; | 283 | struct sway_workspace *current = seat_get_focused_workspace(seat); |
311 | struct sway_container *focus = seat_get_focus(seat); | ||
312 | if (focus) { | ||
313 | current_workspace = focus->type == C_WORKSPACE ? | ||
314 | focus : container_parent(focus, C_WORKSPACE); | ||
315 | current_output = container_parent(focus, C_OUTPUT); | ||
316 | } | ||
317 | 284 | ||
318 | if (strcmp(name, "prev") == 0) { | 285 | if (strcmp(name, "prev") == 0) { |
319 | return workspace_prev(current_workspace); | 286 | return workspace_prev(current); |
320 | } else if (strcmp(name, "prev_on_output") == 0) { | 287 | } else if (strcmp(name, "prev_on_output") == 0) { |
321 | return workspace_output_prev(current_output); | 288 | return workspace_output_prev(current); |
322 | } else if (strcmp(name, "next") == 0) { | 289 | } else if (strcmp(name, "next") == 0) { |
323 | return workspace_next(current_workspace); | 290 | return workspace_next(current); |
324 | } else if (strcmp(name, "next_on_output") == 0) { | 291 | } else if (strcmp(name, "next_on_output") == 0) { |
325 | return workspace_output_next(current_output); | 292 | return workspace_output_next(current); |
326 | } else if (strcmp(name, "current") == 0) { | 293 | } else if (strcmp(name, "current") == 0) { |
327 | return current_workspace; | 294 | return current; |
328 | } else if (strcasecmp(name, "back_and_forth") == 0) { | 295 | } else if (strcasecmp(name, "back_and_forth") == 0) { |
329 | return prev_workspace_name ? | 296 | return prev_workspace_name ? |
330 | root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) | 297 | root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) |
@@ -339,97 +306,68 @@ struct sway_container *workspace_by_name(const char *name) { | |||
339 | * the end and beginning. If next is false, the previous workspace is returned, | 306 | * the end and beginning. If next is false, the previous workspace is returned, |
340 | * otherwise the next one is returned. | 307 | * otherwise the next one is returned. |
341 | */ | 308 | */ |
342 | static struct sway_container *workspace_output_prev_next_impl( | 309 | static struct sway_workspace *workspace_output_prev_next_impl( |
343 | struct sway_container *output, int dir) { | 310 | struct sway_output *output, int dir) { |
344 | if (!output) { | ||
345 | return NULL; | ||
346 | } | ||
347 | if (!sway_assert(output->type == C_OUTPUT, | ||
348 | "Argument must be an output, is %d", output->type)) { | ||
349 | return NULL; | ||
350 | } | ||
351 | |||
352 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 311 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
353 | struct sway_container *focus = seat_get_focus_inactive(seat, output); | 312 | struct sway_workspace *workspace = seat_get_focused_workspace(seat); |
354 | struct sway_container *workspace = (focus->type == C_WORKSPACE ? | ||
355 | focus : | ||
356 | container_parent(focus, C_WORKSPACE)); | ||
357 | 313 | ||
358 | int index = list_find(output->children, workspace); | 314 | int index = list_find(output->workspaces, workspace); |
359 | size_t new_index = wrap(index + dir, output->children->length); | 315 | size_t new_index = wrap(index + dir, output->workspaces->length); |
360 | return output->children->items[new_index]; | 316 | return output->workspaces->items[new_index]; |
361 | } | 317 | } |
362 | 318 | ||
363 | /** | 319 | /** |
364 | * Get the previous or next workspace. If the first/last workspace on an output | 320 | * Get the previous or next workspace. If the first/last workspace on an output |
365 | * is active, proceed to the previous/next output's previous/next workspace. | 321 | * is active, proceed to the previous/next output's previous/next workspace. |
366 | */ | 322 | */ |
367 | static struct sway_container *workspace_prev_next_impl( | 323 | static struct sway_workspace *workspace_prev_next_impl( |
368 | struct sway_container *workspace, int dir) { | 324 | struct sway_workspace *workspace, int dir) { |
369 | if (!workspace) { | 325 | struct sway_output *output = workspace->output; |
370 | return NULL; | 326 | int index = list_find(output->workspaces, workspace); |
371 | } | ||
372 | if (!sway_assert(workspace->type == C_WORKSPACE, | ||
373 | "Argument must be a workspace, is %d", workspace->type)) { | ||
374 | return NULL; | ||
375 | } | ||
376 | |||
377 | struct sway_container *output = workspace->parent; | ||
378 | int index = list_find(output->children, workspace); | ||
379 | int new_index = index + dir; | 327 | int new_index = index + dir; |
380 | 328 | ||
381 | if (new_index >= 0 && new_index < output->children->length) { | 329 | if (new_index >= 0 && new_index < output->workspaces->length) { |
382 | return output->children->items[index + dir]; | 330 | return output->workspaces->items[new_index]; |
383 | } | 331 | } |
384 | 332 | ||
385 | // Look on a different output | 333 | // Look on a different output |
386 | int output_index = list_find(root_container.children, output); | 334 | int output_index = list_find(root->outputs, output); |
387 | new_index = wrap(output_index + dir, root_container.children->length); | 335 | new_index = wrap(output_index + dir, root->outputs->length); |
388 | output = root_container.children->items[new_index]; | 336 | output = root->outputs->items[new_index]; |
389 | 337 | ||
390 | if (dir == 1) { | 338 | if (dir == 1) { |
391 | return output->children->items[0]; | 339 | return output->workspaces->items[0]; |
392 | } else { | 340 | } else { |
393 | return output->children->items[output->children->length - 1]; | 341 | return output->workspaces->items[output->workspaces->length - 1]; |
394 | } | 342 | } |
395 | } | 343 | } |
396 | 344 | ||
397 | struct sway_container *workspace_output_next(struct sway_container *current) { | 345 | struct sway_workspace *workspace_output_next(struct sway_workspace *current) { |
398 | return workspace_output_prev_next_impl(current, 1); | 346 | return workspace_output_prev_next_impl(current->output, 1); |
399 | } | 347 | } |
400 | 348 | ||
401 | struct sway_container *workspace_next(struct sway_container *current) { | 349 | struct sway_workspace *workspace_next(struct sway_workspace *current) { |
402 | return workspace_prev_next_impl(current, 1); | 350 | return workspace_prev_next_impl(current, 1); |
403 | } | 351 | } |
404 | 352 | ||
405 | struct sway_container *workspace_output_prev(struct sway_container *current) { | 353 | struct sway_workspace *workspace_output_prev(struct sway_workspace *current) { |
406 | return workspace_output_prev_next_impl(current, -1); | 354 | return workspace_output_prev_next_impl(current->output, -1); |
407 | } | 355 | } |
408 | 356 | ||
409 | struct sway_container *workspace_prev(struct sway_container *current) { | 357 | struct sway_workspace *workspace_prev(struct sway_workspace *current) { |
410 | return workspace_prev_next_impl(current, -1); | 358 | return workspace_prev_next_impl(current, -1); |
411 | } | 359 | } |
412 | 360 | ||
413 | bool workspace_switch(struct sway_container *workspace, | 361 | bool workspace_switch(struct sway_workspace *workspace, |
414 | bool no_auto_back_and_forth) { | 362 | bool no_auto_back_and_forth) { |
415 | if (!workspace) { | ||
416 | return false; | ||
417 | } | ||
418 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 363 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
419 | struct sway_container *focus = | 364 | struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); |
420 | seat_get_focus_inactive(seat, &root_container); | 365 | struct sway_workspace *active_ws = seat_get_focused_workspace(seat); |
421 | if (!seat || !focus) { | ||
422 | return false; | ||
423 | } | ||
424 | struct sway_container *active_ws = focus; | ||
425 | if (active_ws->type != C_WORKSPACE) { | ||
426 | active_ws = container_parent(focus, C_WORKSPACE); | ||
427 | } | ||
428 | 366 | ||
429 | if (!no_auto_back_and_forth && config->auto_back_and_forth | 367 | if (!no_auto_back_and_forth && config->auto_back_and_forth |
430 | && active_ws == workspace | 368 | && active_ws == workspace |
431 | && prev_workspace_name) { | 369 | && prev_workspace_name) { |
432 | struct sway_container *new_ws = workspace_by_name(prev_workspace_name); | 370 | struct sway_workspace *new_ws = workspace_by_name(prev_workspace_name); |
433 | workspace = new_ws ? | 371 | workspace = new_ws ? |
434 | new_ws : | 372 | new_ws : |
435 | workspace_create(NULL, prev_workspace_name); | 373 | workspace_create(NULL, prev_workspace_name); |
@@ -447,21 +385,21 @@ bool workspace_switch(struct sway_container *workspace, | |||
447 | } | 385 | } |
448 | 386 | ||
449 | // Move sticky containers to new workspace | 387 | // Move sticky containers to new workspace |
450 | struct sway_container *next_output = workspace->parent; | 388 | struct sway_output *next_output = workspace->output; |
451 | struct sway_container *next_output_prev_ws = | 389 | struct sway_workspace *next_output_prev_ws = |
452 | seat_get_active_child(seat, next_output); | 390 | output_get_active_workspace(next_output); |
453 | list_t *floating = next_output_prev_ws->sway_workspace->floating; | ||
454 | bool has_sticky = false; | 391 | bool has_sticky = false; |
455 | if (workspace != next_output_prev_ws) { | 392 | if (workspace != next_output_prev_ws) { |
456 | for (int i = 0; i < floating->length; ++i) { | 393 | for (int i = 0; i < next_output_prev_ws->floating->length; ++i) { |
457 | struct sway_container *floater = floating->items[i]; | 394 | struct sway_container *floater = |
395 | next_output_prev_ws->floating->items[i]; | ||
458 | if (floater->is_sticky) { | 396 | if (floater->is_sticky) { |
459 | has_sticky = true; | 397 | has_sticky = true; |
460 | container_remove_child(floater); | 398 | container_detach(floater); |
461 | workspace_add_floating(workspace, floater); | 399 | workspace_add_floating(workspace, floater); |
462 | if (floater == focus) { | 400 | if (&floater->node == focus) { |
463 | seat_set_focus(seat, NULL); | 401 | seat_set_focus(seat, NULL); |
464 | seat_set_focus(seat, floater); | 402 | seat_set_focus(seat, &floater->node); |
465 | } | 403 | } |
466 | --i; | 404 | --i; |
467 | } | 405 | } |
@@ -470,9 +408,9 @@ bool workspace_switch(struct sway_container *workspace, | |||
470 | 408 | ||
471 | wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", | 409 | wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", |
472 | workspace, workspace->name); | 410 | workspace, workspace->name); |
473 | struct sway_container *next = seat_get_focus_inactive(seat, workspace); | 411 | struct sway_node *next = seat_get_focus_inactive(seat, &workspace->node); |
474 | if (next == NULL) { | 412 | if (next == NULL) { |
475 | next = workspace; | 413 | next = &workspace->node; |
476 | } | 414 | } |
477 | if (has_sticky) { | 415 | if (has_sticky) { |
478 | // If there's a sticky container, we might be setting focus to the same | 416 | // If there's a sticky container, we might be setting focus to the same |
@@ -483,35 +421,24 @@ bool workspace_switch(struct sway_container *workspace, | |||
483 | workspace_consider_destroy(active_ws); | 421 | workspace_consider_destroy(active_ws); |
484 | } | 422 | } |
485 | seat_set_focus(seat, next); | 423 | seat_set_focus(seat, next); |
486 | struct sway_container *output = container_parent(workspace, C_OUTPUT); | 424 | arrange_workspace(workspace); |
487 | arrange_windows(output); | ||
488 | return true; | 425 | return true; |
489 | } | 426 | } |
490 | 427 | ||
491 | bool workspace_is_visible(struct sway_container *ws) { | 428 | bool workspace_is_visible(struct sway_workspace *ws) { |
492 | if (ws->destroying) { | 429 | if (ws->node.destroying) { |
493 | return false; | 430 | return false; |
494 | } | 431 | } |
495 | struct sway_container *output = container_parent(ws, C_OUTPUT); | 432 | return output_get_active_workspace(ws->output) == ws; |
496 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
497 | struct sway_container *focus = seat_get_focus_inactive(seat, output); | ||
498 | if (focus->type != C_WORKSPACE) { | ||
499 | focus = container_parent(focus, C_WORKSPACE); | ||
500 | } | ||
501 | return focus == ws; | ||
502 | } | 433 | } |
503 | 434 | ||
504 | bool workspace_is_empty(struct sway_container *ws) { | 435 | bool workspace_is_empty(struct sway_workspace *ws) { |
505 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | 436 | if (ws->tiling->length) { |
506 | return false; | ||
507 | } | ||
508 | if (ws->children->length) { | ||
509 | return false; | 437 | return false; |
510 | } | 438 | } |
511 | // Sticky views are not considered to be part of this workspace | 439 | // Sticky views are not considered to be part of this workspace |
512 | list_t *floating = ws->sway_workspace->floating; | 440 | for (int i = 0; i < ws->floating->length; ++i) { |
513 | for (int i = 0; i < floating->length; ++i) { | 441 | struct sway_container *floater = ws->floating->items[i]; |
514 | struct sway_container *floater = floating->items[i]; | ||
515 | if (!floater->is_sticky) { | 442 | if (!floater->is_sticky) { |
516 | return false; | 443 | return false; |
517 | } | 444 | } |
@@ -523,20 +450,19 @@ static int find_output(const void *id1, const void *id2) { | |||
523 | return strcmp(id1, id2) ? 0 : 1; | 450 | return strcmp(id1, id2) ? 0 : 1; |
524 | } | 451 | } |
525 | 452 | ||
526 | void workspace_output_raise_priority(struct sway_container *workspace, | 453 | void workspace_output_raise_priority(struct sway_workspace *ws, |
527 | struct sway_container *old_output, struct sway_container *output) { | 454 | struct sway_output *old_output, struct sway_output *output) { |
528 | struct sway_workspace *ws = workspace->sway_workspace; | ||
529 | |||
530 | int old_index = list_seq_find(ws->output_priority, find_output, | 455 | int old_index = list_seq_find(ws->output_priority, find_output, |
531 | old_output->name); | 456 | old_output->wlr_output->name); |
532 | if (old_index < 0) { | 457 | if (old_index < 0) { |
533 | return; | 458 | return; |
534 | } | 459 | } |
535 | 460 | ||
536 | int new_index = list_seq_find(ws->output_priority, find_output, | 461 | int new_index = list_seq_find(ws->output_priority, find_output, |
537 | output->name); | 462 | output->wlr_output->name); |
538 | if (new_index < 0) { | 463 | if (new_index < 0) { |
539 | list_insert(ws->output_priority, old_index, strdup(output->name)); | 464 | list_insert(ws->output_priority, old_index, |
465 | strdup(output->wlr_output->name)); | ||
540 | } else if (new_index > old_index) { | 466 | } else if (new_index > old_index) { |
541 | char *name = ws->output_priority->items[new_index]; | 467 | char *name = ws->output_priority->items[new_index]; |
542 | list_del(ws->output_priority, new_index); | 468 | list_del(ws->output_priority, new_index); |
@@ -544,29 +470,24 @@ void workspace_output_raise_priority(struct sway_container *workspace, | |||
544 | } | 470 | } |
545 | } | 471 | } |
546 | 472 | ||
547 | void workspace_output_add_priority(struct sway_container *workspace, | 473 | void workspace_output_add_priority(struct sway_workspace *workspace, |
548 | struct sway_container *output) { | 474 | struct sway_output *output) { |
549 | int index = list_seq_find(workspace->sway_workspace->output_priority, | 475 | int index = list_seq_find(workspace->output_priority, |
550 | find_output, output->name); | 476 | find_output, output->wlr_output->name); |
551 | if (index < 0) { | 477 | if (index < 0) { |
552 | list_add(workspace->sway_workspace->output_priority, | 478 | list_add(workspace->output_priority, strdup(output->wlr_output->name)); |
553 | strdup(output->name)); | ||
554 | } | 479 | } |
555 | } | 480 | } |
556 | 481 | ||
557 | static bool _output_by_name(struct sway_container *output, void *data) { | 482 | struct sway_output *workspace_output_get_highest_available( |
558 | return output->type == C_OUTPUT && strcasecmp(output->name, data) == 0; | 483 | struct sway_workspace *ws, struct sway_output *exclude) { |
559 | } | 484 | for (int i = 0; i < ws->output_priority->length; i++) { |
560 | 485 | char *name = ws->output_priority->items[i]; | |
561 | struct sway_container *workspace_output_get_highest_available( | 486 | if (exclude && strcasecmp(name, exclude->wlr_output->name) == 0) { |
562 | struct sway_container *ws, struct sway_container *exclude) { | ||
563 | for (int i = 0; i < ws->sway_workspace->output_priority->length; i++) { | ||
564 | char *name = ws->sway_workspace->output_priority->items[i]; | ||
565 | if (exclude && strcasecmp(name, exclude->name) == 0) { | ||
566 | continue; | 487 | continue; |
567 | } | 488 | } |
568 | 489 | ||
569 | struct sway_container *output = root_find_output(_output_by_name, name); | 490 | struct sway_output *output = output_by_name(name); |
570 | if (output) { | 491 | if (output) { |
571 | return output; | 492 | return output; |
572 | } | 493 | } |
@@ -576,49 +497,42 @@ struct sway_container *workspace_output_get_highest_available( | |||
576 | } | 497 | } |
577 | 498 | ||
578 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | 499 | static bool find_urgent_iterator(struct sway_container *con, void *data) { |
579 | return con->type == C_VIEW && view_is_urgent(con->sway_view); | 500 | return con->view && view_is_urgent(con->view); |
580 | } | 501 | } |
581 | 502 | ||
582 | void workspace_detect_urgent(struct sway_container *workspace) { | 503 | void workspace_detect_urgent(struct sway_workspace *workspace) { |
583 | bool new_urgent = (bool)workspace_find_container(workspace, | 504 | bool new_urgent = (bool)workspace_find_container(workspace, |
584 | find_urgent_iterator, NULL); | 505 | find_urgent_iterator, NULL); |
585 | 506 | ||
586 | if (workspace->sway_workspace->urgent != new_urgent) { | 507 | if (workspace->urgent != new_urgent) { |
587 | workspace->sway_workspace->urgent = new_urgent; | 508 | workspace->urgent = new_urgent; |
588 | ipc_event_workspace(NULL, workspace, "urgent"); | 509 | ipc_event_workspace(NULL, workspace, "urgent"); |
589 | container_damage_whole(workspace); | 510 | output_damage_whole(workspace->output); |
590 | } | 511 | } |
591 | } | 512 | } |
592 | 513 | ||
593 | void workspace_for_each_container(struct sway_container *ws, | 514 | void workspace_for_each_container(struct sway_workspace *ws, |
594 | void (*f)(struct sway_container *con, void *data), void *data) { | 515 | void (*f)(struct sway_container *con, void *data), void *data) { |
595 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
596 | return; | ||
597 | } | ||
598 | // Tiling | 516 | // Tiling |
599 | for (int i = 0; i < ws->children->length; ++i) { | 517 | for (int i = 0; i < ws->tiling->length; ++i) { |
600 | struct sway_container *container = ws->children->items[i]; | 518 | struct sway_container *container = ws->tiling->items[i]; |
601 | f(container, data); | 519 | f(container, data); |
602 | container_for_each_child(container, f, data); | 520 | container_for_each_child(container, f, data); |
603 | } | 521 | } |
604 | // Floating | 522 | // Floating |
605 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | 523 | for (int i = 0; i < ws->floating->length; ++i) { |
606 | struct sway_container *container = | 524 | struct sway_container *container = ws->floating->items[i]; |
607 | ws->sway_workspace->floating->items[i]; | ||
608 | f(container, data); | 525 | f(container, data); |
609 | container_for_each_child(container, f, data); | 526 | container_for_each_child(container, f, data); |
610 | } | 527 | } |
611 | } | 528 | } |
612 | 529 | ||
613 | struct sway_container *workspace_find_container(struct sway_container *ws, | 530 | struct sway_container *workspace_find_container(struct sway_workspace *ws, |
614 | bool (*test)(struct sway_container *con, void *data), void *data) { | 531 | bool (*test)(struct sway_container *con, void *data), void *data) { |
615 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
616 | return NULL; | ||
617 | } | ||
618 | struct sway_container *result = NULL; | 532 | struct sway_container *result = NULL; |
619 | // Tiling | 533 | // Tiling |
620 | for (int i = 0; i < ws->children->length; ++i) { | 534 | for (int i = 0; i < ws->tiling->length; ++i) { |
621 | struct sway_container *child = ws->children->items[i]; | 535 | struct sway_container *child = ws->tiling->items[i]; |
622 | if (test(child, data)) { | 536 | if (test(child, data)) { |
623 | return child; | 537 | return child; |
624 | } | 538 | } |
@@ -627,8 +541,8 @@ struct sway_container *workspace_find_container(struct sway_container *ws, | |||
627 | } | 541 | } |
628 | } | 542 | } |
629 | // Floating | 543 | // Floating |
630 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | 544 | for (int i = 0; i < ws->floating->length; ++i) { |
631 | struct sway_container *child = ws->sway_workspace->floating->items[i]; | 545 | struct sway_container *child = ws->floating->items[i]; |
632 | if (test(child, data)) { | 546 | if (test(child, data)) { |
633 | return child; | 547 | return child; |
634 | } | 548 | } |
@@ -639,37 +553,76 @@ struct sway_container *workspace_find_container(struct sway_container *ws, | |||
639 | return NULL; | 553 | return NULL; |
640 | } | 554 | } |
641 | 555 | ||
642 | struct sway_container *workspace_wrap_children(struct sway_container *ws) { | 556 | struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { |
643 | struct sway_container *middle = container_create(C_CONTAINER); | 557 | struct sway_container *middle = container_create(NULL); |
644 | middle->layout = ws->layout; | 558 | middle->layout = ws->layout; |
645 | while (ws->children->length) { | 559 | while (ws->tiling->length) { |
646 | struct sway_container *child = ws->children->items[0]; | 560 | struct sway_container *child = ws->tiling->items[0]; |
647 | container_remove_child(child); | 561 | container_detach(child); |
648 | container_add_child(middle, child); | 562 | container_add_child(middle, child); |
649 | } | 563 | } |
650 | container_add_child(ws, middle); | 564 | workspace_add_tiling(ws, middle); |
651 | return middle; | 565 | return middle; |
652 | } | 566 | } |
653 | 567 | ||
654 | void workspace_add_floating(struct sway_container *workspace, | 568 | void workspace_detach(struct sway_workspace *workspace) { |
655 | struct sway_container *con) { | 569 | struct sway_output *output = workspace->output; |
656 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 570 | int index = list_find(output->workspaces, workspace); |
657 | return; | 571 | if (index != -1) { |
572 | list_del(output->workspaces, index); | ||
658 | } | 573 | } |
659 | if (!sway_assert(con->parent == NULL, "Expected an orphan container")) { | 574 | workspace->output = NULL; |
660 | return; | 575 | |
576 | node_set_dirty(&workspace->node); | ||
577 | node_set_dirty(&output->node); | ||
578 | } | ||
579 | |||
580 | static void set_workspace(struct sway_container *container, void *data) { | ||
581 | container->workspace = container->parent->workspace; | ||
582 | } | ||
583 | |||
584 | void workspace_add_tiling(struct sway_workspace *workspace, | ||
585 | struct sway_container *con) { | ||
586 | if (con->workspace) { | ||
587 | container_detach(con); | ||
661 | } | 588 | } |
589 | list_add(workspace->tiling, con); | ||
590 | con->workspace = workspace; | ||
591 | container_for_each_child(con, set_workspace, NULL); | ||
592 | container_handle_fullscreen_reparent(con); | ||
593 | workspace_update_representation(workspace); | ||
594 | node_set_dirty(&workspace->node); | ||
595 | node_set_dirty(&con->node); | ||
596 | } | ||
662 | 597 | ||
663 | list_add(workspace->sway_workspace->floating, con); | 598 | void workspace_add_floating(struct sway_workspace *workspace, |
664 | con->parent = workspace; | 599 | struct sway_container *con) { |
665 | container_set_dirty(workspace); | 600 | if (con->workspace) { |
666 | container_set_dirty(con); | 601 | container_detach(con); |
602 | } | ||
603 | list_add(workspace->floating, con); | ||
604 | con->workspace = workspace; | ||
605 | container_for_each_child(con, set_workspace, NULL); | ||
606 | container_handle_fullscreen_reparent(con); | ||
607 | node_set_dirty(&workspace->node); | ||
608 | node_set_dirty(&con->node); | ||
667 | } | 609 | } |
668 | 610 | ||
669 | void workspace_remove_gaps(struct sway_container *ws) { | 611 | void workspace_insert_tiling(struct sway_workspace *workspace, |
670 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | 612 | struct sway_container *con, int index) { |
671 | return; | 613 | if (con->workspace) { |
614 | container_detach(con); | ||
672 | } | 615 | } |
616 | list_insert(workspace->tiling, index, con); | ||
617 | con->workspace = workspace; | ||
618 | container_for_each_child(con, set_workspace, NULL); | ||
619 | container_handle_fullscreen_reparent(con); | ||
620 | workspace_update_representation(workspace); | ||
621 | node_set_dirty(&workspace->node); | ||
622 | node_set_dirty(&con->node); | ||
623 | } | ||
624 | |||
625 | void workspace_remove_gaps(struct sway_workspace *ws) { | ||
673 | if (ws->current_gaps == 0) { | 626 | if (ws->current_gaps == 0) { |
674 | return; | 627 | return; |
675 | } | 628 | } |
@@ -681,15 +634,12 @@ void workspace_remove_gaps(struct sway_container *ws) { | |||
681 | ws->current_gaps = 0; | 634 | ws->current_gaps = 0; |
682 | } | 635 | } |
683 | 636 | ||
684 | void workspace_add_gaps(struct sway_container *ws) { | 637 | void workspace_add_gaps(struct sway_workspace *ws) { |
685 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
686 | return; | ||
687 | } | ||
688 | if (ws->current_gaps > 0) { | 638 | if (ws->current_gaps > 0) { |
689 | return; | 639 | return; |
690 | } | 640 | } |
691 | bool should_apply = | 641 | bool should_apply = |
692 | config->edge_gaps || (config->smart_gaps && ws->children->length > 1); | 642 | config->edge_gaps || (config->smart_gaps && ws->tiling->length > 1); |
693 | if (!should_apply) { | 643 | if (!should_apply) { |
694 | return; | 644 | return; |
695 | } | 645 | } |
@@ -708,3 +658,36 @@ void workspace_add_gaps(struct sway_container *ws) { | |||
708 | ws->width -= 2 * ws->current_gaps; | 658 | ws->width -= 2 * ws->current_gaps; |
709 | ws->height -= 2 * ws->current_gaps; | 659 | ws->height -= 2 * ws->current_gaps; |
710 | } | 660 | } |
661 | |||
662 | struct sway_container *workspace_split(struct sway_workspace *workspace, | ||
663 | enum sway_container_layout layout) { | ||
664 | if (workspace->tiling->length == 0) { | ||
665 | workspace->prev_split_layout = workspace->layout; | ||
666 | workspace->layout = layout; | ||
667 | return NULL; | ||
668 | } | ||
669 | |||
670 | enum sway_container_layout old_layout = workspace->layout; | ||
671 | struct sway_container *middle = workspace_wrap_children(workspace); | ||
672 | workspace->layout = layout; | ||
673 | middle->layout = old_layout; | ||
674 | |||
675 | return middle; | ||
676 | } | ||
677 | |||
678 | void workspace_update_representation(struct sway_workspace *ws) { | ||
679 | size_t len = container_build_representation(ws->layout, ws->tiling, NULL); | ||
680 | free(ws->representation); | ||
681 | ws->representation = calloc(len + 1, sizeof(char)); | ||
682 | if (!sway_assert(ws->representation, "Unable to allocate title string")) { | ||
683 | return; | ||
684 | } | ||
685 | container_build_representation(ws->layout, ws->tiling, ws->representation); | ||
686 | } | ||
687 | |||
688 | void workspace_get_box(struct sway_workspace *workspace, struct wlr_box *box) { | ||
689 | box->x = workspace->x; | ||
690 | box->y = workspace->y; | ||
691 | box->width = workspace->width; | ||
692 | box->height = workspace->height; | ||
693 | } | ||