diff options
58 files changed, 1076 insertions, 668 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h index 545b21e6..8e91c158 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -136,6 +136,7 @@ sway_cmd cmd_mark; | |||
136 | sway_cmd cmd_mode; | 136 | sway_cmd cmd_mode; |
137 | sway_cmd cmd_mouse_warping; | 137 | sway_cmd cmd_mouse_warping; |
138 | sway_cmd cmd_move; | 138 | sway_cmd cmd_move; |
139 | sway_cmd cmd_nop; | ||
139 | sway_cmd cmd_opacity; | 140 | sway_cmd cmd_opacity; |
140 | sway_cmd cmd_new_float; | 141 | sway_cmd cmd_new_float; |
141 | sway_cmd cmd_new_window; | 142 | sway_cmd cmd_new_window; |
diff --git a/include/sway/criteria.h b/include/sway/criteria.h index b4ff7d49..7a1e547b 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h | |||
@@ -7,10 +7,11 @@ | |||
7 | #include "tree/view.h" | 7 | #include "tree/view.h" |
8 | 8 | ||
9 | enum criteria_type { | 9 | enum criteria_type { |
10 | CT_COMMAND = 1 << 0, | 10 | CT_COMMAND = 1 << 0, |
11 | CT_ASSIGN_OUTPUT = 1 << 1, | 11 | CT_ASSIGN_OUTPUT = 1 << 1, |
12 | CT_ASSIGN_WORKSPACE = 1 << 2, | 12 | CT_ASSIGN_WORKSPACE = 1 << 2, |
13 | CT_NO_FOCUS = 1 << 3, | 13 | CT_ASSIGN_WORKSPACE_NUMBER = 1 << 3, |
14 | CT_NO_FOCUS = 1 << 4, | ||
14 | }; | 15 | }; |
15 | 16 | ||
16 | struct criteria { | 17 | struct criteria { |
diff --git a/include/sway/debug.h b/include/sway/debug.h index 38d4eccd..bf3a5f6d 100644 --- a/include/sway/debug.h +++ b/include/sway/debug.h | |||
@@ -1,15 +1,22 @@ | |||
1 | #ifndef SWAY_DEBUG_H | 1 | #ifndef SWAY_DEBUG_H |
2 | #define SWAY_DEBUG_H | 2 | #define SWAY_DEBUG_H |
3 | #include <stdbool.h> | ||
3 | 4 | ||
4 | // Tree | 5 | struct sway_debug { |
5 | extern bool enable_debug_tree; | 6 | bool noatomic; // Ignore atomic layout updates |
6 | void update_debug_tree(); | 7 | bool render_tree; // Render the tree overlay |
8 | bool txn_timings; // Log verbose messages about transactions | ||
9 | bool txn_wait; // Always wait for the timeout before applying | ||
10 | |||
11 | enum { | ||
12 | DAMAGE_DEFAULT, // Default behaviour | ||
13 | DAMAGE_HIGHLIGHT, // Highlight regions of the screen being damaged | ||
14 | DAMAGE_RERENDER, // Render the full output when any damage occurs | ||
15 | } damage; | ||
16 | }; | ||
7 | 17 | ||
8 | // Damage | 18 | extern struct sway_debug debug; |
9 | extern const char *damage_debug; | ||
10 | 19 | ||
11 | // Transactions | 20 | void update_debug_tree(); |
12 | extern int txn_timeout_ms; | ||
13 | extern bool txn_debug; | ||
14 | 21 | ||
15 | #endif | 22 | #endif |
diff --git a/include/sway/desktop.h b/include/sway/desktop.h index 348fb187..c969a76b 100644 --- a/include/sway/desktop.h +++ b/include/sway/desktop.h | |||
@@ -1,8 +1,13 @@ | |||
1 | #include <wlr/types/wlr_surface.h> | 1 | #include <wlr/types/wlr_surface.h> |
2 | 2 | ||
3 | struct sway_container; | 3 | struct sway_container; |
4 | struct sway_view; | ||
4 | 5 | ||
5 | void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, | 6 | void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, |
6 | bool whole); | 7 | bool whole); |
7 | 8 | ||
8 | void desktop_damage_whole_container(struct sway_container *con); | 9 | void desktop_damage_whole_container(struct sway_container *con); |
10 | |||
11 | void desktop_damage_box(struct wlr_box *box); | ||
12 | |||
13 | void desktop_damage_view(struct sway_view *view); | ||
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index eb4202f3..5c404ecd 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -35,6 +35,14 @@ struct sway_drag_icon { | |||
35 | struct wl_listener destroy; | 35 | struct wl_listener destroy; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | enum sway_seat_operation { | ||
39 | OP_NONE, | ||
40 | OP_DOWN, | ||
41 | OP_MOVE, | ||
42 | OP_RESIZE_FLOATING, | ||
43 | OP_RESIZE_TILING, | ||
44 | }; | ||
45 | |||
38 | struct sway_seat { | 46 | struct sway_seat { |
39 | struct wlr_seat *wlr_seat; | 47 | struct wlr_seat *wlr_seat; |
40 | struct sway_cursor *cursor; | 48 | struct sway_cursor *cursor; |
@@ -54,13 +62,7 @@ struct sway_seat { | |||
54 | double touch_x, touch_y; | 62 | double touch_x, touch_y; |
55 | 63 | ||
56 | // Operations (drag and resize) | 64 | // Operations (drag and resize) |
57 | enum { | 65 | enum sway_seat_operation operation; |
58 | OP_NONE, | ||
59 | OP_MOVE, | ||
60 | OP_RESIZE_FLOATING, | ||
61 | OP_RESIZE_TILING, | ||
62 | } operation; | ||
63 | |||
64 | struct sway_container *op_container; | 66 | struct sway_container *op_container; |
65 | enum wlr_edges op_resize_edge; | 67 | enum wlr_edges op_resize_edge; |
66 | uint32_t op_button; | 68 | uint32_t op_button; |
@@ -68,6 +70,7 @@ struct sway_seat { | |||
68 | double op_ref_lx, op_ref_ly; // cursor's x/y at start of op | 70 | double op_ref_lx, op_ref_ly; // cursor's x/y at start of op |
69 | double op_ref_width, op_ref_height; // container's size at start of op | 71 | double op_ref_width, op_ref_height; // container's size at start of op |
70 | double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op | 72 | double op_ref_con_lx, op_ref_con_ly; // container's x/y at start of op |
73 | bool op_moved; // if the mouse moved during a down op | ||
71 | 74 | ||
72 | uint32_t last_button; | 75 | uint32_t last_button; |
73 | uint32_t last_button_serial; | 76 | uint32_t last_button_serial; |
@@ -157,6 +160,9 @@ bool seat_is_input_allowed(struct sway_seat *seat, struct wlr_surface *surface); | |||
157 | 160 | ||
158 | void drag_icon_update_position(struct sway_drag_icon *icon); | 161 | void drag_icon_update_position(struct sway_drag_icon *icon); |
159 | 162 | ||
163 | void seat_begin_down(struct sway_seat *seat, struct sway_container *con, | ||
164 | uint32_t button, double sx, double sy); | ||
165 | |||
160 | void seat_begin_move(struct sway_seat *seat, struct sway_container *con, | 166 | void seat_begin_move(struct sway_seat *seat, struct sway_container *con, |
161 | uint32_t button); | 167 | uint32_t button); |
162 | 168 | ||
@@ -166,6 +172,9 @@ void seat_begin_resize_floating(struct sway_seat *seat, | |||
166 | void seat_begin_resize_tiling(struct sway_seat *seat, | 172 | void seat_begin_resize_tiling(struct sway_seat *seat, |
167 | struct sway_container *con, uint32_t button, enum wlr_edges edge); | 173 | struct sway_container *con, uint32_t button, enum wlr_edges edge); |
168 | 174 | ||
175 | struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, | ||
176 | struct sway_container *container); | ||
177 | |||
169 | void seat_end_mouse_operation(struct sway_seat *seat); | 178 | void seat_end_mouse_operation(struct sway_seat *seat); |
170 | 179 | ||
171 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, | 180 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, |
diff --git a/include/sway/output.h b/include/sway/output.h index 80dcd37b..d0d034b3 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -58,6 +58,8 @@ void output_damage_whole_container(struct sway_output *output, | |||
58 | 58 | ||
59 | struct sway_container *output_by_name(const char *name); | 59 | struct sway_container *output_by_name(const char *name); |
60 | 60 | ||
61 | void output_sort_workspaces(struct sway_container *output); | ||
62 | |||
61 | void output_enable(struct sway_output *output); | 63 | void output_enable(struct sway_output *output); |
62 | 64 | ||
63 | bool output_has_opaque_overlay_layer_surface(struct sway_output *output); | 65 | bool output_has_opaque_overlay_layer_surface(struct sway_output *output); |
@@ -93,4 +95,16 @@ void output_drag_icons_for_each_surface(struct sway_output *output, | |||
93 | struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, | 95 | struct wl_list *drag_icons, sway_surface_iterator_func_t iterator, |
94 | void *user_data); | 96 | void *user_data); |
95 | 97 | ||
98 | void output_for_each_workspace(struct sway_container *output, | ||
99 | void (*f)(struct sway_container *con, void *data), void *data); | ||
100 | |||
101 | void output_for_each_container(struct sway_container *output, | ||
102 | void (*f)(struct sway_container *con, void *data), void *data); | ||
103 | |||
104 | struct sway_container *output_find_workspace(struct sway_container *output, | ||
105 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
106 | |||
107 | struct sway_container *output_find_container(struct sway_container *output, | ||
108 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
109 | |||
96 | #endif | 110 | #endif |
diff --git a/include/sway/server.h b/include/sway/server.h index b93584b6..1e20f2c8 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -54,8 +54,7 @@ struct sway_server { | |||
54 | struct wl_listener server_decoration; | 54 | struct wl_listener server_decoration; |
55 | struct wl_list decorations; // sway_server_decoration::link | 55 | struct wl_list decorations; // sway_server_decoration::link |
56 | 56 | ||
57 | bool debug_txn_timings; | 57 | size_t txn_timeout_ms; |
58 | |||
59 | list_t *transactions; | 58 | list_t *transactions; |
60 | list_t *dirty_containers; | 59 | list_t *dirty_containers; |
61 | }; | 60 | }; |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index b64a2e63..cd886cd0 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -40,7 +40,6 @@ enum sway_container_layout { | |||
40 | L_VERT, | 40 | L_VERT, |
41 | L_STACKED, | 41 | L_STACKED, |
42 | L_TABBED, | 42 | L_TABBED, |
43 | L_FLOATING, | ||
44 | }; | 43 | }; |
45 | 44 | ||
46 | enum sway_container_border { | 45 | enum sway_container_border { |
@@ -83,10 +82,11 @@ struct sway_container_state { | |||
83 | bool border_bottom; | 82 | bool border_bottom; |
84 | bool border_left; | 83 | bool border_left; |
85 | bool border_right; | 84 | bool border_right; |
85 | bool using_csd; | ||
86 | 86 | ||
87 | // Workspace properties | 87 | // Workspace properties |
88 | struct sway_container *ws_fullscreen; | 88 | struct sway_container *ws_fullscreen; |
89 | struct sway_container *ws_floating; | 89 | list_t *ws_floating; |
90 | }; | 90 | }; |
91 | 91 | ||
92 | struct sway_container { | 92 | struct sway_container { |
@@ -138,6 +138,9 @@ struct sway_container { | |||
138 | 138 | ||
139 | struct sway_container *parent; | 139 | struct sway_container *parent; |
140 | 140 | ||
141 | // Outputs currently being intersected | ||
142 | list_t *outputs; // struct sway_output | ||
143 | |||
141 | // Indicates that the container is a scratchpad container. | 144 | // Indicates that the container is a scratchpad container. |
142 | // Both hidden and visible scratchpad containers have scratchpad=true. | 145 | // Both hidden and visible scratchpad containers have scratchpad=true. |
143 | // Hidden scratchpad containers have a NULL parent. | 146 | // Hidden scratchpad containers have a NULL parent. |
@@ -166,12 +169,7 @@ struct sway_container { | |||
166 | 169 | ||
167 | struct { | 170 | struct { |
168 | struct wl_signal destroy; | 171 | struct wl_signal destroy; |
169 | // Raised after the tree updates, but before arrange_windows | ||
170 | // Passed the previous parent | ||
171 | struct wl_signal reparent; | ||
172 | } events; | 172 | } events; |
173 | |||
174 | struct wl_listener reparent; | ||
175 | }; | 173 | }; |
176 | 174 | ||
177 | struct sway_container *container_create(enum sway_container_type type); | 175 | struct sway_container *container_create(enum sway_container_type type); |
@@ -213,15 +211,11 @@ struct sway_container *container_destroy(struct sway_container *container); | |||
213 | 211 | ||
214 | struct sway_container *container_close(struct sway_container *container); | 212 | struct sway_container *container_close(struct sway_container *container); |
215 | 213 | ||
216 | void container_descendants(struct sway_container *root, | ||
217 | enum sway_container_type type, | ||
218 | void (*func)(struct sway_container *item, void *data), void *data); | ||
219 | |||
220 | /** | 214 | /** |
221 | * Search a container's descendants a container based on test criteria. Returns | 215 | * Search a container's descendants a container based on test criteria. Returns |
222 | * the first container that passes the test. | 216 | * the first container that passes the test. |
223 | */ | 217 | */ |
224 | struct sway_container *container_find(struct sway_container *container, | 218 | struct sway_container *container_find_child(struct sway_container *container, |
225 | bool (*test)(struct sway_container *view, void *data), void *data); | 219 | bool (*test)(struct sway_container *view, void *data), void *data); |
226 | 220 | ||
227 | /** | 221 | /** |
@@ -243,10 +237,7 @@ struct sway_container *tiling_container_at( | |||
243 | struct sway_container *con, double lx, double ly, | 237 | struct sway_container *con, double lx, double ly, |
244 | struct wlr_surface **surface, double *sx, double *sy); | 238 | struct wlr_surface **surface, double *sx, double *sy); |
245 | 239 | ||
246 | /** | 240 | void container_for_each_child(struct sway_container *container, |
247 | * Apply the function for each child of the container depth first. | ||
248 | */ | ||
249 | void container_for_each_descendant(struct sway_container *container, | ||
250 | void (*f)(struct sway_container *container, void *data), void *data); | 241 | void (*f)(struct sway_container *container, void *data), void *data); |
251 | 242 | ||
252 | /** | 243 | /** |
@@ -361,11 +352,11 @@ bool container_is_floating_or_child(struct sway_container *container); | |||
361 | bool container_is_fullscreen_or_child(struct sway_container *container); | 352 | bool container_is_fullscreen_or_child(struct sway_container *container); |
362 | 353 | ||
363 | /** | 354 | /** |
364 | * Wrap the children of parent in a new container. The new container will be the | 355 | * Return the output which will be used for scale purposes. |
365 | * only child of parent. | 356 | * This is the most recently entered output. |
366 | * | ||
367 | * The new container is returned. | ||
368 | */ | 357 | */ |
369 | struct sway_container *container_wrap_children(struct sway_container *parent); | 358 | struct sway_output *container_get_effective_output(struct sway_container *con); |
359 | |||
360 | void container_discover_outputs(struct sway_container *con); | ||
370 | 361 | ||
371 | #endif | 362 | #endif |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 77cd954b..519189d9 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h | |||
@@ -15,13 +15,7 @@ enum movement_direction { | |||
15 | MOVE_CHILD, | 15 | MOVE_CHILD, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | enum resize_edge { | 18 | enum wlr_edges; |
19 | RESIZE_EDGE_NONE = 0, | ||
20 | RESIZE_EDGE_LEFT = 1, | ||
21 | RESIZE_EDGE_RIGHT = 2, | ||
22 | RESIZE_EDGE_TOP = 4, | ||
23 | RESIZE_EDGE_BOTTOM = 8, | ||
24 | }; | ||
25 | 19 | ||
26 | struct sway_container; | 20 | struct sway_container; |
27 | 21 | ||
@@ -45,8 +39,6 @@ void container_move(struct sway_container *container, | |||
45 | enum sway_container_layout container_get_default_layout( | 39 | enum sway_container_layout container_get_default_layout( |
46 | struct sway_container *con); | 40 | struct sway_container *con); |
47 | 41 | ||
48 | void container_sort_workspaces(struct sway_container *output); | ||
49 | |||
50 | struct sway_container *container_get_in_direction(struct sway_container | 42 | struct sway_container *container_get_in_direction(struct sway_container |
51 | *container, struct sway_seat *seat, enum movement_direction dir); | 43 | *container, struct sway_seat *seat, enum movement_direction dir); |
52 | 44 | ||
@@ -54,7 +46,7 @@ struct sway_container *container_split(struct sway_container *child, | |||
54 | enum sway_container_layout layout); | 46 | enum sway_container_layout layout); |
55 | 47 | ||
56 | void container_recursive_resize(struct sway_container *container, | 48 | void container_recursive_resize(struct sway_container *container, |
57 | double amount, enum resize_edge edge); | 49 | double amount, enum wlr_edges edge); |
58 | 50 | ||
59 | void container_swap(struct sway_container *con1, struct sway_container *con2); | 51 | void container_swap(struct sway_container *con1, struct sway_container *con2); |
60 | 52 | ||
diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index edb7c817..d1f04a96 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h | |||
@@ -58,4 +58,19 @@ struct sway_container *root_workspace_for_pid(pid_t pid); | |||
58 | 58 | ||
59 | void root_record_workspace_pid(pid_t pid); | 59 | void root_record_workspace_pid(pid_t pid); |
60 | 60 | ||
61 | void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), | ||
62 | void *data); | ||
63 | |||
64 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), | ||
65 | void *data); | ||
66 | |||
67 | struct sway_container *root_find_output( | ||
68 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
69 | |||
70 | struct sway_container *root_find_workspace( | ||
71 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
72 | |||
73 | struct sway_container *root_find_container( | ||
74 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
75 | |||
61 | #endif | 76 | #endif |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index c2225bcb..5fdecc2b 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -88,6 +88,14 @@ struct sway_view { | |||
88 | struct wlr_buffer *saved_buffer; | 88 | struct wlr_buffer *saved_buffer; |
89 | int saved_buffer_width, saved_buffer_height; | 89 | int saved_buffer_width, saved_buffer_height; |
90 | 90 | ||
91 | // The geometry for whatever the client is committing, regardless of | ||
92 | // transaction state. Updated on every commit. | ||
93 | struct wlr_box geometry; | ||
94 | |||
95 | // The "old" geometry during a transaction. Used to damage the old location | ||
96 | // when a transaction is applied. | ||
97 | struct wlr_box saved_geometry; | ||
98 | |||
91 | bool destroying; | 99 | bool destroying; |
92 | 100 | ||
93 | list_t *executed_criteria; // struct criteria * | 101 | list_t *executed_criteria; // struct criteria * |
@@ -112,7 +120,6 @@ struct sway_view { | |||
112 | } events; | 120 | } events; |
113 | 121 | ||
114 | struct wl_listener surface_new_subsurface; | 122 | struct wl_listener surface_new_subsurface; |
115 | struct wl_listener container_reparent; | ||
116 | }; | 123 | }; |
117 | 124 | ||
118 | struct sway_xdg_shell_v6_view { | 125 | struct sway_xdg_shell_v6_view { |
@@ -285,8 +292,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface); | |||
285 | 292 | ||
286 | void view_unmap(struct sway_view *view); | 293 | void view_unmap(struct sway_view *view); |
287 | 294 | ||
288 | void view_update_position(struct sway_view *view, double lx, double ly); | ||
289 | |||
290 | void view_update_size(struct sway_view *view, int width, int height); | 295 | void view_update_size(struct sway_view *view, int width, int height); |
291 | 296 | ||
292 | void view_child_init(struct sway_view_child *child, | 297 | void view_child_init(struct sway_view_child *child, |
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 056f2329..35c91017 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -9,7 +9,7 @@ struct sway_view; | |||
9 | struct sway_workspace { | 9 | struct sway_workspace { |
10 | struct sway_container *swayc; | 10 | struct sway_container *swayc; |
11 | struct sway_container *fullscreen; | 11 | struct sway_container *fullscreen; |
12 | struct sway_container *floating; | 12 | list_t *floating; // struct sway_container |
13 | list_t *output_priority; | 13 | list_t *output_priority; |
14 | bool urgent; | 14 | bool urgent; |
15 | }; | 15 | }; |
@@ -50,4 +50,20 @@ struct sway_container *workspace_output_get_highest_available( | |||
50 | 50 | ||
51 | void workspace_detect_urgent(struct sway_container *workspace); | 51 | void workspace_detect_urgent(struct sway_container *workspace); |
52 | 52 | ||
53 | void workspace_for_each_container(struct sway_container *ws, | ||
54 | void (*f)(struct sway_container *con, void *data), void *data); | ||
55 | |||
56 | struct sway_container *workspace_find_container(struct sway_container *ws, | ||
57 | bool (*test)(struct sway_container *con, void *data), void *data); | ||
58 | |||
59 | /** | ||
60 | * Wrap the workspace's tiling children in a new container. | ||
61 | * The new container will be the only direct tiling child of the workspace. | ||
62 | * The new container is returned. | ||
63 | */ | ||
64 | struct sway_container *workspace_wrap_children(struct sway_container *ws); | ||
65 | |||
66 | void workspace_add_floating(struct sway_container *workspace, | ||
67 | struct sway_container *con); | ||
68 | |||
53 | #endif | 69 | #endif |
diff --git a/include/swaynag/swaynag.h b/include/swaynag/swaynag.h index 1bf8b640..a32d1503 100644 --- a/include/swaynag/swaynag.h +++ b/include/swaynag/swaynag.h | |||
@@ -58,7 +58,7 @@ struct swaynag_details { | |||
58 | int offset; | 58 | int offset; |
59 | int visible_lines; | 59 | int visible_lines; |
60 | int total_lines; | 60 | int total_lines; |
61 | struct swaynag_button button_details; | 61 | struct swaynag_button *button_details; |
62 | struct swaynag_button button_up; | 62 | struct swaynag_button button_up; |
63 | struct swaynag_button button_down; | 63 | struct swaynag_button button_down; |
64 | }; | 64 | }; |
diff --git a/sway/commands.c b/sway/commands.c index 364c26da..d9c54adc 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -146,6 +146,7 @@ static struct cmd_handler command_handlers[] = { | |||
146 | { "layout", cmd_layout }, | 146 | { "layout", cmd_layout }, |
147 | { "mark", cmd_mark }, | 147 | { "mark", cmd_mark }, |
148 | { "move", cmd_move }, | 148 | { "move", cmd_move }, |
149 | { "nop", cmd_nop }, | ||
149 | { "opacity", cmd_opacity }, | 150 | { "opacity", cmd_opacity }, |
150 | { "reload", cmd_reload }, | 151 | { "reload", cmd_reload }, |
151 | { "rename", cmd_rename }, | 152 | { "rename", cmd_rename }, |
diff --git a/sway/commands/assign.c b/sway/commands/assign.c index 0bc0929a..04582e88 100644 --- a/sway/commands/assign.c +++ b/sway/commands/assign.c | |||
@@ -22,27 +22,38 @@ struct cmd_results *cmd_assign(int argc, char **argv) { | |||
22 | return error; | 22 | return error; |
23 | } | 23 | } |
24 | 24 | ||
25 | ++argv; | 25 | --argc; ++argv; |
26 | int target_len = argc - 1; | ||
27 | 26 | ||
28 | if (strncmp(*argv, "→", strlen("→")) == 0) { | 27 | if (strncmp(*argv, "→", strlen("→")) == 0) { |
29 | if (argc < 3) { | 28 | if (argc < 2) { |
30 | free(criteria); | 29 | free(criteria); |
31 | return cmd_results_new(CMD_INVALID, "assign", "Missing workspace"); | 30 | return cmd_results_new(CMD_INVALID, "assign", "Missing workspace"); |
32 | } | 31 | } |
32 | --argc; | ||
33 | ++argv; | 33 | ++argv; |
34 | --target_len; | ||
35 | } | 34 | } |
36 | 35 | ||
37 | if (strcmp(*argv, "output") == 0) { | 36 | if (strcmp(*argv, "output") == 0) { |
38 | criteria->type = CT_ASSIGN_OUTPUT; | 37 | criteria->type = CT_ASSIGN_OUTPUT; |
39 | ++argv; | 38 | --argc; ++argv; |
40 | --target_len; | ||
41 | } else { | 39 | } else { |
42 | criteria->type = CT_ASSIGN_WORKSPACE; | 40 | if (strcmp(*argv, "workspace") == 0) { |
41 | --argc; ++argv; | ||
42 | } | ||
43 | if (strcmp(*argv, "number") == 0) { | ||
44 | --argc; ++argv; | ||
45 | if (argv[0][0] < '0' || argv[0][0] > '9') { | ||
46 | free(criteria); | ||
47 | return cmd_results_new(CMD_INVALID, "assign", | ||
48 | "Invalid workspace number '%s'", argv[0]); | ||
49 | } | ||
50 | criteria->type = CT_ASSIGN_WORKSPACE_NUMBER; | ||
51 | } else { | ||
52 | criteria->type = CT_ASSIGN_WORKSPACE; | ||
53 | } | ||
43 | } | 54 | } |
44 | 55 | ||
45 | criteria->target = join_args(argv, target_len); | 56 | criteria->target = join_args(argv, argc); |
46 | 57 | ||
47 | list_add(config->criteria, criteria); | 58 | list_add(config->criteria, criteria); |
48 | wlr_log(WLR_DEBUG, "assign: '%s' -> '%s' added", criteria->raw, | 59 | wlr_log(WLR_DEBUG, "assign: '%s' -> '%s' added", criteria->raw, |
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 00e39ae7..5ce7919b 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c | |||
@@ -26,7 +26,16 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) { | |||
26 | return error; | 26 | return error; |
27 | } | 27 | } |
28 | 28 | ||
29 | tmp = join_args(argv + 1, argc - 1); | 29 | --argc; ++argv; |
30 | } | ||
31 | |||
32 | if (argv[0][0] == '\'' || argv[0][0] == '"') { | ||
33 | if (argc > 0) { | ||
34 | return cmd_results_new(CMD_INVALID, "exec_always", | ||
35 | "command cannot be partially quoted"); | ||
36 | } | ||
37 | tmp = strdup(argv[0]); | ||
38 | strip_quotes(tmp); | ||
30 | } else { | 39 | } else { |
31 | tmp = join_args(argv, argc); | 40 | tmp = join_args(argv, argc); |
32 | } | 41 | } |
diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 31de5ec3..beafd9fb 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "sway/tree/container.h" | 8 | #include "sway/tree/container.h" |
9 | #include "sway/tree/layout.h" | 9 | #include "sway/tree/layout.h" |
10 | #include "sway/tree/view.h" | 10 | #include "sway/tree/view.h" |
11 | #include "sway/tree/workspace.h" | ||
11 | #include "list.h" | 12 | #include "list.h" |
12 | 13 | ||
13 | struct cmd_results *cmd_floating(int argc, char **argv) { | 14 | struct cmd_results *cmd_floating(int argc, char **argv) { |
@@ -24,7 +25,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
24 | if (container->type == C_WORKSPACE) { | 25 | if (container->type == C_WORKSPACE) { |
25 | // Wrap the workspace's children in a container so we can float it | 26 | // Wrap the workspace's children in a container so we can float it |
26 | struct sway_container *workspace = container; | 27 | struct sway_container *workspace = container; |
27 | container = container_wrap_children(container); | 28 | container = workspace_wrap_children(container); |
28 | workspace->layout = L_HORIZ; | 29 | workspace->layout = L_HORIZ; |
29 | seat_set_focus(config->handler_context.seat, container); | 30 | seat_set_focus(config->handler_context.seat, container); |
30 | } | 31 | } |
@@ -32,7 +33,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
32 | // If the container is in a floating split container, | 33 | // If the container is in a floating split container, |
33 | // operate on the split container instead of the child. | 34 | // operate on the split container instead of the child. |
34 | if (container_is_floating_or_child(container)) { | 35 | if (container_is_floating_or_child(container)) { |
35 | while (container->parent->layout != L_FLOATING) { | 36 | while (container->parent->type != C_WORKSPACE) { |
36 | container = container->parent; | 37 | container = container->parent; |
37 | } | 38 | } |
38 | } | 39 | } |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 76d3f1dc..6659a683 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -39,21 +39,24 @@ static struct cmd_results *focus_mode(struct sway_container *con, | |||
39 | // If the container is in a floating split container, | 39 | // If the container is in a floating split container, |
40 | // operate on the split container instead of the child. | 40 | // operate on the split container instead of the child. |
41 | if (container_is_floating_or_child(con)) { | 41 | if (container_is_floating_or_child(con)) { |
42 | while (con->parent->layout != L_FLOATING) { | 42 | while (con->parent->type != C_WORKSPACE) { |
43 | con = con->parent; | 43 | con = con->parent; |
44 | } | 44 | } |
45 | } | 45 | } |
46 | 46 | ||
47 | struct sway_container *new_focus = NULL; | 47 | struct sway_container *new_focus = NULL; |
48 | if (floating) { | 48 | if (floating) { |
49 | new_focus = seat_get_focus_inactive(seat, ws->sway_workspace->floating); | 49 | new_focus = seat_get_focus_inactive_floating(seat, ws); |
50 | } else { | 50 | } else { |
51 | new_focus = seat_get_focus_inactive_tiling(seat, ws); | 51 | new_focus = seat_get_focus_inactive_tiling(seat, ws); |
52 | } | 52 | } |
53 | if (!new_focus) { | 53 | if (new_focus) { |
54 | new_focus = ws; | 54 | seat_set_focus(seat, new_focus); |
55 | } else { | ||
56 | return cmd_results_new(CMD_FAILURE, "focus", | ||
57 | "Failed to find a %s container in workspace", | ||
58 | floating ? "floating" : "tiling"); | ||
55 | } | 59 | } |
56 | seat_set_focus(seat, new_focus); | ||
57 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 60 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
58 | } | 61 | } |
59 | 62 | ||
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 5ad06e40..a0661200 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c | |||
@@ -4,6 +4,7 @@ | |||
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/tree/layout.h" | 8 | #include "sway/tree/layout.h" |
8 | #include "util.h" | 9 | #include "util.h" |
9 | 10 | ||
@@ -21,7 +22,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
21 | if (container->type == C_WORKSPACE) { | 22 | if (container->type == C_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 | struct sway_container *workspace = container; |
24 | container = container_wrap_children(container); | 25 | container = workspace_wrap_children(container); |
25 | workspace->layout = L_HORIZ; | 26 | workspace->layout = L_HORIZ; |
26 | seat_set_focus(config->handler_context.seat, container); | 27 | seat_set_focus(config->handler_context.seat, container); |
27 | } | 28 | } |
diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c index bb390f5f..d59c9fdb 100644 --- a/sway/commands/hide_edge_borders.c +++ b/sway/commands/hide_edge_borders.c | |||
@@ -31,7 +31,7 @@ struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) { | |||
31 | "<none|vertical|horizontal|both|smart>'"); | 31 | "<none|vertical|horizontal|both|smart>'"); |
32 | } | 32 | } |
33 | 33 | ||
34 | container_for_each_descendant(&root_container, _configure_view, NULL); | 34 | root_for_each_container(_configure_view, NULL); |
35 | 35 | ||
36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
37 | } | 37 | } |
diff --git a/sway/commands/move.c b/sway/commands/move.c index de6b1b0a..c6dc0775 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <ctype.h> | ||
2 | #include <stdbool.h> | 3 | #include <stdbool.h> |
3 | #include <string.h> | 4 | #include <string.h> |
4 | #include <strings.h> | 5 | #include <strings.h> |
@@ -22,7 +23,7 @@ | |||
22 | static const char *expected_syntax = | 23 | static const char *expected_syntax = |
23 | "Expected 'move <left|right|up|down> <[px] px>' or " | 24 | "Expected 'move <left|right|up|down> <[px] px>' or " |
24 | "'move [--no-auto-back-and-forth] <container|window> [to] workspace <name>' or " | 25 | "'move [--no-auto-back-and-forth] <container|window> [to] workspace <name>' or " |
25 | "'move [--no-auto-back-and-forth] <container|window|workspace> [to] output <name|direction>' or " | 26 | "'move <container|window|workspace> [to] output <name|direction>' or " |
26 | "'move <container|window> [to] mark <mark>'"; | 27 | "'move <container|window> [to] mark <mark>'"; |
27 | 28 | ||
28 | static struct sway_container *output_in_direction(const char *direction, | 29 | static struct sway_container *output_in_direction(const char *direction, |
@@ -64,7 +65,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
64 | return cmd_results_new(CMD_FAILURE, "move", | 65 | return cmd_results_new(CMD_FAILURE, "move", |
65 | "Can't move an empty workspace"); | 66 | "Can't move an empty workspace"); |
66 | } | 67 | } |
67 | current = container_wrap_children(current); | 68 | current = workspace_wrap_children(current); |
68 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { | 69 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { |
69 | return cmd_results_new(CMD_FAILURE, "move", | 70 | return cmd_results_new(CMD_FAILURE, "move", |
70 | "Can only move containers and views."); | 71 | "Can only move containers and views."); |
@@ -124,7 +125,11 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
124 | return cmd_results_new(CMD_INVALID, "move", | 125 | return cmd_results_new(CMD_INVALID, "move", |
125 | expected_syntax); | 126 | expected_syntax); |
126 | } | 127 | } |
127 | ws_name = strdup(argv[3]); | 128 | if (!isdigit(argv[3][0])) { |
129 | return cmd_results_new(CMD_INVALID, "move", | ||
130 | "Invalid workspace number '%s'", argv[3]); | ||
131 | } | ||
132 | ws_name = join_args(argv + 3, argc - 3); | ||
128 | ws = workspace_by_number(ws_name); | 133 | ws = workspace_by_number(ws_name); |
129 | } else { | 134 | } else { |
130 | ws_name = join_args(argv + 2, argc - 2); | 135 | ws_name = join_args(argv + 2, argc - 2); |
@@ -231,7 +236,6 @@ static void workspace_move_to_output(struct sway_container *workspace, | |||
231 | seat_get_focus_inactive(seat, output); | 236 | seat_get_focus_inactive(seat, output); |
232 | 237 | ||
233 | container_add_child(output, workspace); | 238 | container_add_child(output, workspace); |
234 | wl_signal_emit(&workspace->events.reparent, old_output); | ||
235 | 239 | ||
236 | // If moving the last workspace from the old output, create a new workspace | 240 | // If moving the last workspace from the old output, create a new workspace |
237 | // on the old output | 241 | // on the old output |
@@ -245,7 +249,7 @@ static void workspace_move_to_output(struct sway_container *workspace, | |||
245 | // Try to remove an empty workspace from the destination output. | 249 | // Try to remove an empty workspace from the destination output. |
246 | container_reap_empty_recursive(new_output_focus); | 250 | container_reap_empty_recursive(new_output_focus); |
247 | 251 | ||
248 | container_sort_workspaces(output); | 252 | output_sort_workspaces(output); |
249 | seat_set_focus(seat, output); | 253 | seat_set_focus(seat, output); |
250 | workspace_output_raise_priority(workspace, old_output, output); | 254 | workspace_output_raise_priority(workspace, old_output, output); |
251 | ipc_event_workspace(NULL, workspace, "move"); | 255 | ipc_event_workspace(NULL, workspace, "move"); |
@@ -437,14 +441,14 @@ static struct cmd_results *move_to_scratchpad(struct sway_container *con) { | |||
437 | if (con->type == C_WORKSPACE) { | 441 | if (con->type == C_WORKSPACE) { |
438 | // Wrap the workspace's children in a container | 442 | // Wrap the workspace's children in a container |
439 | struct sway_container *workspace = con; | 443 | struct sway_container *workspace = con; |
440 | con = container_wrap_children(con); | 444 | con = workspace_wrap_children(con); |
441 | workspace->layout = L_HORIZ; | 445 | workspace->layout = L_HORIZ; |
442 | } | 446 | } |
443 | 447 | ||
444 | // If the container is in a floating split container, | 448 | // If the container is in a floating split container, |
445 | // operate on the split container instead of the child. | 449 | // operate on the split container instead of the child. |
446 | if (container_is_floating_or_child(con)) { | 450 | if (container_is_floating_or_child(con)) { |
447 | while (con->parent->layout != L_FLOATING) { | 451 | while (con->parent->type != C_WORKSPACE) { |
448 | con = con->parent; | 452 | con = con->parent; |
449 | } | 453 | } |
450 | } | 454 | } |
diff --git a/sway/commands/nop.c b/sway/commands/nop.c new file mode 100644 index 00000000..c12fe15a --- /dev/null +++ b/sway/commands/nop.c | |||
@@ -0,0 +1,5 @@ | |||
1 | #include "sway/commands.h" | ||
2 | |||
3 | struct cmd_results *cmd_nop(int argc, char **argv) { | ||
4 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
5 | } | ||
diff --git a/sway/commands/rename.c b/sway/commands/rename.c index c6952bbb..21d2aa64 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <ctype.h> | ||
2 | #include <string.h> | 3 | #include <string.h> |
3 | #include <strings.h> | 4 | #include <strings.h> |
4 | #include "log.h" | 5 | #include "log.h" |
@@ -6,6 +7,7 @@ | |||
6 | #include "sway/commands.h" | 7 | #include "sway/commands.h" |
7 | #include "sway/config.h" | 8 | #include "sway/config.h" |
8 | #include "sway/ipc-server.h" | 9 | #include "sway/ipc-server.h" |
10 | #include "sway/output.h" | ||
9 | #include "sway/tree/container.h" | 11 | #include "sway/tree/container.h" |
10 | #include "sway/tree/workspace.h" | 12 | #include "sway/tree/workspace.h" |
11 | 13 | ||
@@ -33,6 +35,10 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
33 | } | 35 | } |
34 | } else if (strcasecmp(argv[1], "number") == 0) { | 36 | } else if (strcasecmp(argv[1], "number") == 0) { |
35 | // 'rename workspace number x to new_name' | 37 | // 'rename workspace number x to new_name' |
38 | if (!isdigit(argv[2][0])) { | ||
39 | return cmd_results_new(CMD_INVALID, "rename", | ||
40 | "Invalid workspace number '%s'", argv[2]); | ||
41 | } | ||
36 | workspace = workspace_by_number(argv[2]); | 42 | workspace = workspace_by_number(argv[2]); |
37 | while (argn < argc && strcasecmp(argv[argn], "to") != 0) { | 43 | while (argn < argc && strcasecmp(argv[argn], "to") != 0) { |
38 | ++argn; | 44 | ++argn; |
@@ -66,7 +72,8 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
66 | strcasecmp(new_name, "next_on_output") == 0 || | 72 | strcasecmp(new_name, "next_on_output") == 0 || |
67 | strcasecmp(new_name, "prev_on_output") == 0 || | 73 | strcasecmp(new_name, "prev_on_output") == 0 || |
68 | strcasecmp(new_name, "back_and_forth") == 0 || | 74 | strcasecmp(new_name, "back_and_forth") == 0 || |
69 | strcasecmp(new_name, "current") == 0) { | 75 | strcasecmp(new_name, "current") == 0 || |
76 | strcasecmp(new_name, "number") == 0) { | ||
70 | free(new_name); | 77 | free(new_name); |
71 | return cmd_results_new(CMD_INVALID, "rename", | 78 | return cmd_results_new(CMD_INVALID, "rename", |
72 | "Cannot use special workspace name '%s'", argv[argn]); | 79 | "Cannot use special workspace name '%s'", argv[argn]); |
@@ -82,7 +89,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
82 | free(workspace->name); | 89 | free(workspace->name); |
83 | workspace->name = new_name; | 90 | workspace->name = new_name; |
84 | 91 | ||
85 | container_sort_workspaces(workspace->parent); | 92 | output_sort_workspaces(workspace->parent); |
86 | ipc_event_workspace(NULL, workspace, "rename"); | 93 | ipc_event_workspace(NULL, workspace, "rename"); |
87 | 94 | ||
88 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 95 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 0f3005f4..ea1e36ff 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <stdlib.h> | 5 | #include <stdlib.h> |
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <strings.h> | 7 | #include <strings.h> |
8 | #include <wlr/util/edges.h> | ||
8 | #include <wlr/util/log.h> | 9 | #include <wlr/util/log.h> |
9 | #include "sway/commands.h" | 10 | #include "sway/commands.h" |
10 | #include "sway/tree/arrange.h" | 11 | #include "sway/tree/arrange.h" |
@@ -250,10 +251,10 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
250 | } | 251 | } |
251 | } | 252 | } |
252 | 253 | ||
253 | enum resize_edge minor_edge = axis == RESIZE_AXIS_HORIZONTAL ? | 254 | enum wlr_edges minor_edge = axis == RESIZE_AXIS_HORIZONTAL ? |
254 | RESIZE_EDGE_LEFT : RESIZE_EDGE_TOP; | 255 | WLR_EDGE_LEFT : WLR_EDGE_TOP; |
255 | enum resize_edge major_edge = axis == RESIZE_AXIS_HORIZONTAL ? | 256 | enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? |
256 | RESIZE_EDGE_RIGHT : RESIZE_EDGE_BOTTOM; | 257 | WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; |
257 | 258 | ||
258 | for (int i = 0; i < parent->parent->children->length; i++) { | 259 | for (int i = 0; i < parent->parent->children->length; i++) { |
259 | struct sway_container *sibling = parent->parent->children->items[i]; | 260 | struct sway_container *sibling = parent->parent->children->items[i]; |
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index 0e573aeb..7da20015 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c | |||
@@ -16,7 +16,7 @@ static void scratchpad_toggle_auto(void) { | |||
16 | // If the focus is in a floating split container, | 16 | // If the focus is in a floating split container, |
17 | // operate on the split container instead of the child. | 17 | // operate on the split container instead of the child. |
18 | if (container_is_floating_or_child(focus)) { | 18 | if (container_is_floating_or_child(focus)) { |
19 | while (focus->parent->layout != L_FLOATING) { | 19 | while (focus->parent->type != C_WORKSPACE) { |
20 | focus = focus->parent; | 20 | focus = focus->parent; |
21 | } | 21 | } |
22 | } | 22 | } |
@@ -33,9 +33,8 @@ static void scratchpad_toggle_auto(void) { | |||
33 | 33 | ||
34 | // Check if there is an unfocused scratchpad window on the current workspace | 34 | // Check if there is an unfocused scratchpad window on the current workspace |
35 | // and focus it. | 35 | // and focus it. |
36 | for (int i = 0; i < ws->sway_workspace->floating->children->length; ++i) { | 36 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { |
37 | struct sway_container *floater = | 37 | struct sway_container *floater = ws->sway_workspace->floating->items[i]; |
38 | ws->sway_workspace->floating->children->items[i]; | ||
39 | if (floater->scratchpad && focus != floater) { | 38 | if (floater->scratchpad && focus != floater) { |
40 | wlr_log(WLR_DEBUG, | 39 | wlr_log(WLR_DEBUG, |
41 | "Focusing other scratchpad window (%s) in this workspace", | 40 | "Focusing other scratchpad window (%s) in this workspace", |
@@ -103,7 +102,7 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { | |||
103 | // If the container is in a floating split container, | 102 | // If the container is in a floating split container, |
104 | // operate on the split container instead of the child. | 103 | // operate on the split container instead of the child. |
105 | if (container_is_floating_or_child(con)) { | 104 | if (container_is_floating_or_child(con)) { |
106 | while (con->parent->layout != L_FLOATING) { | 105 | while (con->parent->type != C_WORKSPACE) { |
107 | con = con->parent; | 106 | con = con->parent; |
108 | } | 107 | } |
109 | } | 108 | } |
diff --git a/sway/commands/set.c b/sway/commands/set.c index ea388d3b..be51230b 100644 --- a/sway/commands/set.c +++ b/sway/commands/set.c | |||
@@ -25,23 +25,13 @@ void free_sway_variable(struct sway_variable *var) { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | struct cmd_results *cmd_set(int argc, char **argv) { | 27 | struct cmd_results *cmd_set(int argc, char **argv) { |
28 | char *tmp; | ||
29 | struct cmd_results *error = NULL; | 28 | struct cmd_results *error = NULL; |
30 | if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { | 29 | if ((error = checkarg(argc, "set", EXPECTED_AT_LEAST, 2))) { |
31 | return error; | 30 | return error; |
32 | } | 31 | } |
33 | 32 | ||
34 | if (argv[0][0] != '$') { | 33 | if (argv[0][0] != '$') { |
35 | wlr_log(WLR_INFO, "Warning: variable '%s' doesn't start with $", argv[0]); | 34 | return cmd_results_new(CMD_INVALID, "set", "variable '%s' must start with $", argv[0]); |
36 | |||
37 | size_t size = snprintf(NULL, 0, "$%s", argv[0]); | ||
38 | tmp = malloc(size + 1); | ||
39 | if (!tmp) { | ||
40 | return cmd_results_new(CMD_FAILURE, "set", "Not possible to create variable $'%s'", argv[0]); | ||
41 | } | ||
42 | snprintf(tmp, size+1, "$%s", argv[0]); | ||
43 | |||
44 | argv[0] = tmp; | ||
45 | } | 35 | } |
46 | 36 | ||
47 | struct sway_variable *var = NULL; | 37 | struct sway_variable *var = NULL; |
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index cf153a0a..dd7d170c 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c | |||
@@ -24,8 +24,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) { | |||
24 | config->show_marks = parse_boolean(argv[0], config->show_marks); | 24 | config->show_marks = parse_boolean(argv[0], config->show_marks); |
25 | 25 | ||
26 | if (config->show_marks) { | 26 | if (config->show_marks) { |
27 | container_for_each_descendant(&root_container, | 27 | root_for_each_container(rebuild_marks_iterator, NULL); |
28 | rebuild_marks_iterator, NULL); | ||
29 | } | 28 | } |
30 | 29 | ||
31 | for (int i = 0; i < root_container.children->length; ++i) { | 30 | for (int i = 0; i < root_container.children->length; ++i) { |
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 732ccb98..a0dd7215 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c | |||
@@ -36,5 +36,21 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { | |||
36 | 36 | ||
37 | container->is_sticky = wants_sticky; | 37 | container->is_sticky = wants_sticky; |
38 | 38 | ||
39 | if (wants_sticky) { | ||
40 | // move container to focused workspace | ||
41 | struct sway_container *output = container_parent(container, C_OUTPUT); | ||
42 | struct sway_seat *seat = input_manager_current_seat(input_manager); | ||
43 | struct sway_container *focus = seat_get_focus_inactive(seat, output); | ||
44 | struct sway_container *focused_workspace = container_parent(focus, C_WORKSPACE); | ||
45 | struct sway_container *current_workspace = container_parent(container, C_WORKSPACE); | ||
46 | if (current_workspace != focused_workspace) { | ||
47 | container_move_to(container, focused_workspace); | ||
48 | arrange_windows(focused_workspace); | ||
49 | if (!container_reap_empty(current_workspace)) { | ||
50 | arrange_windows(current_workspace); | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | |||
39 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 55 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
40 | } | 56 | } |
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index 4e3a9cce..f881a002 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -50,13 +50,13 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
50 | if (strcasecmp(argv[2], "id") == 0) { | 50 | if (strcasecmp(argv[2], "id") == 0) { |
51 | #ifdef HAVE_XWAYLAND | 51 | #ifdef HAVE_XWAYLAND |
52 | xcb_window_t id = strtol(value, NULL, 0); | 52 | xcb_window_t id = strtol(value, NULL, 0); |
53 | other = container_find(&root_container, test_id, (void *)&id); | 53 | other = root_find_container(test_id, (void *)&id); |
54 | #endif | 54 | #endif |
55 | } else if (strcasecmp(argv[2], "con_id") == 0) { | 55 | } else if (strcasecmp(argv[2], "con_id") == 0) { |
56 | size_t con_id = atoi(value); | 56 | size_t con_id = atoi(value); |
57 | other = container_find(&root_container, test_con_id, (void *)con_id); | 57 | other = root_find_container(test_con_id, (void *)con_id); |
58 | } else if (strcasecmp(argv[2], "mark") == 0) { | 58 | } else if (strcasecmp(argv[2], "mark") == 0) { |
59 | other = container_find(&root_container, test_mark, (void *)value); | 59 | other = root_find_container(test_mark, (void *)value); |
60 | } else { | 60 | } else { |
61 | free(value); | 61 | free(value); |
62 | return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); | 62 | return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); |
@@ -72,7 +72,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
72 | || container_has_ancestor(other, current)) { | 72 | || container_has_ancestor(other, current)) { |
73 | error = cmd_results_new(CMD_FAILURE, "swap", | 73 | error = cmd_results_new(CMD_FAILURE, "swap", |
74 | "Cannot swap ancestor and descendant"); | 74 | "Cannot swap ancestor and descendant"); |
75 | } else if (current->layout == L_FLOATING || other->layout == L_FLOATING) { | 75 | } else if (container_is_floating(current) || container_is_floating(other)) { |
76 | error = cmd_results_new(CMD_FAILURE, "swap", | 76 | error = cmd_results_new(CMD_FAILURE, "swap", |
77 | "Swapping with floating containers is not supported"); | 77 | "Swapping with floating containers is not supported"); |
78 | } | 78 | } |
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index 44ceccee..c183785b 100644 --- a/sway/commands/unmark.c +++ b/sway/commands/unmark.c | |||
@@ -52,8 +52,7 @@ struct cmd_results *cmd_unmark(int argc, char **argv) { | |||
52 | view_find_and_unmark(mark); | 52 | view_find_and_unmark(mark); |
53 | } else { | 53 | } else { |
54 | // Remove all marks from all views | 54 | // Remove all marks from all views |
55 | container_for_each_descendant(&root_container, | 55 | root_for_each_container(remove_all_marks_iterator, NULL); |
56 | remove_all_marks_iterator, NULL); | ||
57 | } | 56 | } |
58 | free(mark); | 57 | free(mark); |
59 | 58 | ||
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index f5558bb4..ceb4cd6e 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <ctype.h> | ||
2 | #include <string.h> | 3 | #include <string.h> |
3 | #include <strings.h> | 4 | #include <strings.h> |
4 | #include "sway/commands.h" | 5 | #include "sway/commands.h" |
@@ -60,9 +61,13 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
60 | struct sway_container *ws = NULL; | 61 | struct sway_container *ws = NULL; |
61 | if (strcasecmp(argv[0], "number") == 0) { | 62 | if (strcasecmp(argv[0], "number") == 0) { |
62 | if (argc < 2) { | 63 | if (argc < 2) { |
63 | cmd_results_new(CMD_INVALID, "workspace", | 64 | return cmd_results_new(CMD_INVALID, "workspace", |
64 | "Expected workspace number"); | 65 | "Expected workspace number"); |
65 | } | 66 | } |
67 | if (!isdigit(argv[1][0])) { | ||
68 | return cmd_results_new(CMD_INVALID, "workspace", | ||
69 | "Invalid workspace number '%s'", argv[1]); | ||
70 | } | ||
66 | if (!(ws = workspace_by_number(argv[1]))) { | 71 | if (!(ws = workspace_by_number(argv[1]))) { |
67 | char *name = join_args(argv + 1, argc - 1); | 72 | char *name = join_args(argv + 1, argc - 1); |
68 | ws = workspace_create(NULL, name); | 73 | ws = workspace_create(NULL, name); |
diff --git a/sway/config.c b/sway/config.c index bd14222a..642abbac 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -822,18 +822,7 @@ void config_update_font_height(bool recalculate) { | |||
822 | size_t prev_max_height = config->font_height; | 822 | size_t prev_max_height = config->font_height; |
823 | config->font_height = 0; | 823 | config->font_height = 0; |
824 | 824 | ||
825 | container_for_each_descendant(&root_container, | 825 | root_for_each_container(find_font_height_iterator, &recalculate); |
826 | find_font_height_iterator, &recalculate); | ||
827 | |||
828 | // Also consider floating views | ||
829 | for (int i = 0; i < root_container.children->length; ++i) { | ||
830 | struct sway_container *output = root_container.children->items[i]; | ||
831 | for (int j = 0; j < output->children->length; ++j) { | ||
832 | struct sway_container *ws = output->children->items[j]; | ||
833 | container_for_each_descendant(ws->sway_workspace->floating, | ||
834 | find_font_height_iterator, &recalculate); | ||
835 | } | ||
836 | } | ||
837 | 826 | ||
838 | if (config->font_height != prev_max_height) { | 827 | if (config->font_height != prev_max_height) { |
839 | arrange_windows(&root_container); | 828 | arrange_windows(&root_container); |
diff --git a/sway/criteria.c b/sway/criteria.c index a5df1eef..81c2325a 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -167,8 +167,7 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
167 | return false; | 167 | return false; |
168 | } | 168 | } |
169 | list_t *urgent_views = create_list(); | 169 | list_t *urgent_views = create_list(); |
170 | container_for_each_descendant(&root_container, | 170 | root_for_each_container(find_urgent_iterator, urgent_views); |
171 | find_urgent_iterator, urgent_views); | ||
172 | list_stable_sort(urgent_views, cmp_urgent); | 171 | list_stable_sort(urgent_views, cmp_urgent); |
173 | struct sway_view *target; | 172 | struct sway_view *target; |
174 | if (criteria->urgent == 'o') { // oldest | 173 | if (criteria->urgent == 'o') { // oldest |
@@ -228,17 +227,7 @@ list_t *criteria_get_views(struct criteria *criteria) { | |||
228 | .criteria = criteria, | 227 | .criteria = criteria, |
229 | .matches = matches, | 228 | .matches = matches, |
230 | }; | 229 | }; |
231 | container_for_each_descendant(&root_container, | 230 | root_for_each_container(criteria_get_views_iterator, &data); |
232 | criteria_get_views_iterator, &data); | ||
233 | |||
234 | // Scratchpad items which are hidden are not in the tree. | ||
235 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | ||
236 | struct sway_container *con = | ||
237 | root_container.sway_root->scratchpad->items[i]; | ||
238 | if (!con->parent) { | ||
239 | criteria_get_views_iterator(con, &data); | ||
240 | } | ||
241 | } | ||
242 | return matches; | 231 | return matches; |
243 | } | 232 | } |
244 | 233 | ||
diff --git a/sway/debug-tree.c b/sway/debug-tree.c index f3465afe..ea0826b9 100644 --- a/sway/debug-tree.c +++ b/sway/debug-tree.c | |||
@@ -3,8 +3,10 @@ | |||
3 | #include <wlr/render/wlr_texture.h> | 3 | #include <wlr/render/wlr_texture.h> |
4 | #include <wlr/util/log.h> | 4 | #include <wlr/util/log.h> |
5 | #include "config.h" | 5 | #include "config.h" |
6 | #include "sway/debug.h" | ||
6 | #include "sway/input/input-manager.h" | 7 | #include "sway/input/input-manager.h" |
7 | #include "sway/input/seat.h" | 8 | #include "sway/input/seat.h" |
9 | #include "sway/output.h" | ||
8 | #include "sway/server.h" | 10 | #include "sway/server.h" |
9 | #include "sway/tree/container.h" | 11 | #include "sway/tree/container.h" |
10 | #include "sway/tree/layout.h" | 12 | #include "sway/tree/layout.h" |
@@ -12,6 +14,8 @@ | |||
12 | #include "config.h" | 14 | #include "config.h" |
13 | #include "pango.h" | 15 | #include "pango.h" |
14 | 16 | ||
17 | struct sway_debug debug; | ||
18 | |||
15 | static const char *layout_to_str(enum sway_container_layout layout) { | 19 | static const char *layout_to_str(enum sway_container_layout layout) { |
16 | switch (layout) { | 20 | switch (layout) { |
17 | case L_HORIZ: | 21 | case L_HORIZ: |
@@ -22,8 +26,6 @@ static const char *layout_to_str(enum sway_container_layout layout) { | |||
22 | return "L_STACKED"; | 26 | return "L_STACKED"; |
23 | case L_TABBED: | 27 | case L_TABBED: |
24 | return "L_TABBED"; | 28 | return "L_TABBED"; |
25 | case L_FLOATING: | ||
26 | return "L_FLOATING"; | ||
27 | case L_NONE: | 29 | case L_NONE: |
28 | return "L_NONE"; | 30 | return "L_NONE"; |
29 | } | 31 | } |
@@ -69,10 +71,8 @@ static int draw_container(cairo_t *cairo, struct sway_container *container, | |||
69 | return height; | 71 | return height; |
70 | } | 72 | } |
71 | 73 | ||
72 | bool enable_debug_tree = false; | ||
73 | |||
74 | void update_debug_tree() { | 74 | void update_debug_tree() { |
75 | if (!enable_debug_tree) { | 75 | if (!debug.render_tree) { |
76 | return; | 76 | return; |
77 | } | 77 | } |
78 | 78 | ||
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index 6575519d..72650397 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c | |||
@@ -22,3 +22,21 @@ void desktop_damage_whole_container(struct sway_container *con) { | |||
22 | } | 22 | } |
23 | } | 23 | } |
24 | } | 24 | } |
25 | |||
26 | void desktop_damage_box(struct wlr_box *box) { | ||
27 | for (int i = 0; i < root_container.children->length; ++i) { | ||
28 | struct sway_container *cont = root_container.children->items[i]; | ||
29 | output_damage_box(cont->sway_output, box); | ||
30 | } | ||
31 | } | ||
32 | |||
33 | void desktop_damage_view(struct sway_view *view) { | ||
34 | desktop_damage_whole_container(view->swayc); | ||
35 | struct wlr_box box = { | ||
36 | .x = view->swayc->current.view_x - view->geometry.x, | ||
37 | .y = view->swayc->current.view_y - view->geometry.y, | ||
38 | .width = view->surface->current.width, | ||
39 | .height = view->surface->current.height, | ||
40 | }; | ||
41 | desktop_damage_box(&box); | ||
42 | } | ||
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 66747a3f..3d8bbff5 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -144,15 +144,16 @@ void output_view_for_each_surface(struct sway_output *output, | |||
144 | .user_iterator = iterator, | 144 | .user_iterator = iterator, |
145 | .user_data = user_data, | 145 | .user_data = user_data, |
146 | .output = output, | 146 | .output = output, |
147 | .ox = view->swayc->current.view_x - output->swayc->current.swayc_x, | 147 | .ox = view->swayc->current.view_x - output->swayc->current.swayc_x |
148 | .oy = view->swayc->current.view_y - output->swayc->current.swayc_y, | 148 | - view->geometry.x, |
149 | .oy = view->swayc->current.view_y - output->swayc->current.swayc_y | ||
150 | - view->geometry.y, | ||
149 | .width = view->swayc->current.view_width, | 151 | .width = view->swayc->current.view_width, |
150 | .height = view->swayc->current.view_height, | 152 | .height = view->swayc->current.view_height, |
151 | .rotation = 0, // TODO | 153 | .rotation = 0, // TODO |
152 | }; | 154 | }; |
153 | 155 | ||
154 | view_for_each_surface(view, | 156 | view_for_each_surface(view, output_for_each_surface_iterator, &data); |
155 | output_for_each_surface_iterator, &data); | ||
156 | } | 157 | } |
157 | 158 | ||
158 | void output_view_for_each_popup(struct sway_output *output, | 159 | void output_view_for_each_popup(struct sway_output *output, |
@@ -162,8 +163,10 @@ void output_view_for_each_popup(struct sway_output *output, | |||
162 | .user_iterator = iterator, | 163 | .user_iterator = iterator, |
163 | .user_data = user_data, | 164 | .user_data = user_data, |
164 | .output = output, | 165 | .output = output, |
165 | .ox = view->swayc->current.view_x - output->swayc->current.swayc_x, | 166 | .ox = view->swayc->current.view_x - output->swayc->current.swayc_x |
166 | .oy = view->swayc->current.view_y - output->swayc->current.swayc_y, | 167 | - view->geometry.x, |
168 | .oy = view->swayc->current.view_y - output->swayc->current.swayc_y | ||
169 | - view->geometry.y, | ||
167 | .width = view->swayc->current.view_width, | 170 | .width = view->swayc->current.view_width, |
168 | .height = view->swayc->current.view_height, | 171 | .height = view->swayc->current.view_height, |
169 | .rotation = 0, // TODO | 172 | .rotation = 0, // TODO |
@@ -303,44 +306,33 @@ struct send_frame_done_data { | |||
303 | 306 | ||
304 | static void send_frame_done_container_iterator(struct sway_container *con, | 307 | static void send_frame_done_container_iterator(struct sway_container *con, |
305 | void *_data) { | 308 | void *_data) { |
306 | struct send_frame_done_data *data = _data; | 309 | if (con->type != C_VIEW) { |
307 | if (!sway_assert(con->type == C_VIEW, "expected a view")) { | ||
308 | return; | 310 | return; |
309 | } | 311 | } |
310 | |||
311 | if (!view_is_visible(con->sway_view)) { | 312 | if (!view_is_visible(con->sway_view)) { |
312 | return; | 313 | return; |
313 | } | 314 | } |
314 | 315 | ||
316 | struct send_frame_done_data *data = _data; | ||
315 | output_view_for_each_surface(data->output, con->sway_view, | 317 | output_view_for_each_surface(data->output, con->sway_view, |
316 | send_frame_done_iterator, data->when); | 318 | send_frame_done_iterator, data->when); |
317 | } | 319 | } |
318 | 320 | ||
319 | static void send_frame_done_container(struct sway_output *output, | ||
320 | struct sway_container *con, struct timespec *when) { | ||
321 | struct send_frame_done_data data = { | ||
322 | .output = output, | ||
323 | .when = when, | ||
324 | }; | ||
325 | container_descendants(con, C_VIEW, | ||
326 | send_frame_done_container_iterator, &data); | ||
327 | } | ||
328 | |||
329 | static void send_frame_done(struct sway_output *output, struct timespec *when) { | 321 | static void send_frame_done(struct sway_output *output, struct timespec *when) { |
330 | if (output_has_opaque_overlay_layer_surface(output)) { | 322 | if (output_has_opaque_overlay_layer_surface(output)) { |
331 | goto send_frame_overlay; | 323 | goto send_frame_overlay; |
332 | } | 324 | } |
333 | 325 | ||
326 | struct send_frame_done_data data = { | ||
327 | .output = output, | ||
328 | .when = when, | ||
329 | }; | ||
334 | struct sway_container *workspace = output_get_active_workspace(output); | 330 | struct sway_container *workspace = output_get_active_workspace(output); |
335 | if (workspace->current.ws_fullscreen) { | 331 | if (workspace->current.ws_fullscreen) { |
336 | if (workspace->current.ws_fullscreen->type == C_VIEW) { | 332 | send_frame_done_container_iterator( |
337 | output_view_for_each_surface(output, | 333 | workspace->current.ws_fullscreen, &data); |
338 | workspace->current.ws_fullscreen->sway_view, | 334 | container_for_each_child(workspace->current.ws_fullscreen, |
339 | send_frame_done_iterator, when); | 335 | send_frame_done_container_iterator, &data); |
340 | } else { | ||
341 | send_frame_done_container(output, workspace->current.ws_fullscreen, | ||
342 | when); | ||
343 | } | ||
344 | #ifdef HAVE_XWAYLAND | 336 | #ifdef HAVE_XWAYLAND |
345 | send_frame_done_unmanaged(output, | 337 | send_frame_done_unmanaged(output, |
346 | &root_container.sway_root->xwayland_unmanaged, when); | 338 | &root_container.sway_root->xwayland_unmanaged, when); |
@@ -351,9 +343,8 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
351 | send_frame_done_layer(output, | 343 | send_frame_done_layer(output, |
352 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], when); | 344 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], when); |
353 | 345 | ||
354 | send_frame_done_container(output, workspace, when); | 346 | workspace_for_each_container(workspace, |
355 | send_frame_done_container(output, workspace->sway_workspace->floating, | 347 | send_frame_done_container_iterator, &data); |
356 | when); | ||
357 | 348 | ||
358 | #ifdef HAVE_XWAYLAND | 349 | #ifdef HAVE_XWAYLAND |
359 | send_frame_done_unmanaged(output, | 350 | send_frame_done_unmanaged(output, |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index cdac9c72..5cf8abc0 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -193,9 +193,11 @@ 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 | output_surface_for_each_surface(output, view->surface, | 196 | double ox = |
197 | view->swayc->current.view_x - output->wlr_output->lx, | 197 | view->swayc->current.view_x - output->wlr_output->lx - view->geometry.x; |
198 | view->swayc->current.view_y - output->wlr_output->ly, | 198 | double oy = |
199 | view->swayc->current.view_y - output->wlr_output->ly - view->geometry.y; | ||
200 | output_surface_for_each_surface(output, view->surface, ox, oy, | ||
199 | render_surface_iterator, &data); | 201 | render_surface_iterator, &data); |
200 | } | 202 | } |
201 | 203 | ||
@@ -227,8 +229,10 @@ static void render_saved_view(struct sway_view *view, | |||
227 | return; | 229 | return; |
228 | } | 230 | } |
229 | struct wlr_box box = { | 231 | struct wlr_box box = { |
230 | .x = view->swayc->current.view_x - output->swayc->current.swayc_x, | 232 | .x = view->swayc->current.view_x - output->swayc->current.swayc_x - |
231 | .y = view->swayc->current.view_y - output->swayc->current.swayc_y, | 233 | view->saved_geometry.x, |
234 | .y = view->swayc->current.view_y - output->swayc->current.swayc_y - | ||
235 | view->saved_geometry.y, | ||
232 | .width = view->saved_buffer_width, | 236 | .width = view->saved_buffer_width, |
233 | .height = view->saved_buffer_height, | 237 | .height = view->saved_buffer_height, |
234 | }; | 238 | }; |
@@ -266,7 +270,7 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
266 | render_view_toplevels(view, output, damage, view->swayc->alpha); | 270 | render_view_toplevels(view, output, damage, view->swayc->alpha); |
267 | } | 271 | } |
268 | 272 | ||
269 | if (view->using_csd) { | 273 | if (view->swayc->current.using_csd) { |
270 | return; | 274 | return; |
271 | } | 275 | } |
272 | 276 | ||
@@ -585,7 +589,7 @@ static void render_container_simple(struct sway_output *output, | |||
585 | marks_texture = view->marks_unfocused; | 589 | marks_texture = view->marks_unfocused; |
586 | } | 590 | } |
587 | 591 | ||
588 | if (!view->using_csd) { | 592 | if (!view->swayc->current.using_csd) { |
589 | if (state->border == B_NORMAL) { | 593 | if (state->border == B_NORMAL) { |
590 | render_titlebar(output, damage, child, state->swayc_x, | 594 | render_titlebar(output, damage, child, state->swayc_x, |
591 | state->swayc_y, state->swayc_width, colors, | 595 | state->swayc_y, state->swayc_width, colors, |
@@ -750,8 +754,6 @@ static void render_container(struct sway_output *output, | |||
750 | case L_TABBED: | 754 | case L_TABBED: |
751 | render_container_tabbed(output, damage, con, parent_focused); | 755 | render_container_tabbed(output, damage, con, parent_focused); |
752 | break; | 756 | break; |
753 | case L_FLOATING: | ||
754 | sway_assert(false, "Didn't expect to see floating here"); | ||
755 | } | 757 | } |
756 | } | 758 | } |
757 | 759 | ||
@@ -777,7 +779,7 @@ static void render_floating_container(struct sway_output *soutput, | |||
777 | marks_texture = view->marks_unfocused; | 779 | marks_texture = view->marks_unfocused; |
778 | } | 780 | } |
779 | 781 | ||
780 | if (!view->using_csd) { | 782 | if (!view->swayc->current.using_csd) { |
781 | if (con->current.border == B_NORMAL) { | 783 | if (con->current.border == B_NORMAL) { |
782 | render_titlebar(soutput, damage, con, con->current.swayc_x, | 784 | render_titlebar(soutput, damage, con, con->current.swayc_x, |
783 | con->current.swayc_y, con->current.swayc_width, colors, | 785 | con->current.swayc_y, con->current.swayc_width, colors, |
@@ -802,8 +804,7 @@ static void render_floating(struct sway_output *soutput, | |||
802 | if (!workspace_is_visible(ws)) { | 804 | if (!workspace_is_visible(ws)) { |
803 | continue; | 805 | continue; |
804 | } | 806 | } |
805 | list_t *floating = | 807 | list_t *floating = ws->current.ws_floating; |
806 | ws->current.ws_floating->current.children; | ||
807 | for (int k = 0; k < floating->length; ++k) { | 808 | for (int k = 0; k < floating->length; ++k) { |
808 | struct sway_container *floater = floating->items[k]; | 809 | struct sway_container *floater = floating->items[k]; |
809 | render_floating_container(soutput, damage, floater); | 810 | render_floating_container(soutput, damage, floater); |
@@ -812,8 +813,6 @@ static void render_floating(struct sway_output *soutput, | |||
812 | } | 813 | } |
813 | } | 814 | } |
814 | 815 | ||
815 | const char *damage_debug = NULL; | ||
816 | |||
817 | void output_render(struct sway_output *output, struct timespec *when, | 816 | void output_render(struct sway_output *output, struct timespec *when, |
818 | pixman_region32_t *damage) { | 817 | pixman_region32_t *damage) { |
819 | struct wlr_output *wlr_output = output->wlr_output; | 818 | struct wlr_output *wlr_output = output->wlr_output; |
@@ -827,21 +826,17 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
827 | 826 | ||
828 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | 827 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); |
829 | 828 | ||
830 | bool damage_whole_before_swap = false; | ||
831 | if (!pixman_region32_not_empty(damage)) { | 829 | if (!pixman_region32_not_empty(damage)) { |
832 | // Output isn't damaged but needs buffer swap | 830 | // Output isn't damaged but needs buffer swap |
833 | goto renderer_end; | 831 | goto renderer_end; |
834 | } | 832 | } |
835 | 833 | ||
836 | if (damage_debug != NULL) { | 834 | if (debug.damage == DAMAGE_HIGHLIGHT) { |
837 | if (strcmp(damage_debug, "highlight") == 0) { | 835 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); |
838 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | 836 | } else if (debug.damage == DAMAGE_RERENDER) { |
839 | damage_whole_before_swap = true; | 837 | int width, height; |
840 | } else if (strcmp(damage_debug, "rerender") == 0) { | 838 | wlr_output_transformed_resolution(wlr_output, &width, &height); |
841 | int width, height; | 839 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); |
842 | wlr_output_transformed_resolution(wlr_output, &width, &height); | ||
843 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | ||
844 | } | ||
845 | } | 840 | } |
846 | 841 | ||
847 | struct sway_container *workspace = output_get_active_workspace(output); | 842 | struct sway_container *workspace = output_get_active_workspace(output); |
@@ -915,12 +910,12 @@ render_overlay: | |||
915 | render_drag_icons(output, damage, &root_container.sway_root->drag_icons); | 910 | render_drag_icons(output, damage, &root_container.sway_root->drag_icons); |
916 | 911 | ||
917 | renderer_end: | 912 | renderer_end: |
918 | if (root_container.sway_root->debug_tree) { | 913 | if (debug.render_tree) { |
914 | wlr_renderer_scissor(renderer, NULL); | ||
919 | wlr_render_texture(renderer, root_container.sway_root->debug_tree, | 915 | wlr_render_texture(renderer, root_container.sway_root->debug_tree, |
920 | wlr_output->transform_matrix, 0, 0, 1); | 916 | wlr_output->transform_matrix, 0, 40, 1); |
921 | } | 917 | } |
922 | 918 | if (debug.damage == DAMAGE_HIGHLIGHT) { | |
923 | if (damage_whole_before_swap || root_container.sway_root->debug_tree) { | ||
924 | int width, height; | 919 | int width, height; |
925 | wlr_output_transformed_resolution(wlr_output, &width, &height); | 920 | wlr_output_transformed_resolution(wlr_output, &width, &height); |
926 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | 921 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index c08730ce..f82e5ef2 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -1,11 +1,13 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <errno.h> | 2 | #include <errno.h> |
3 | #include <limits.h> | ||
3 | #include <stdbool.h> | 4 | #include <stdbool.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <string.h> | 6 | #include <string.h> |
6 | #include <time.h> | 7 | #include <time.h> |
7 | #include <wlr/types/wlr_buffer.h> | 8 | #include <wlr/types/wlr_buffer.h> |
8 | #include "sway/debug.h" | 9 | #include "sway/debug.h" |
10 | #include "sway/desktop.h" | ||
9 | #include "sway/desktop/idle_inhibit_v1.h" | 11 | #include "sway/desktop/idle_inhibit_v1.h" |
10 | #include "sway/desktop/transaction.h" | 12 | #include "sway/desktop/transaction.h" |
11 | #include "sway/output.h" | 13 | #include "sway/output.h" |
@@ -15,26 +17,12 @@ | |||
15 | #include "list.h" | 17 | #include "list.h" |
16 | #include "log.h" | 18 | #include "log.h" |
17 | 19 | ||
18 | /** | ||
19 | * How long we should wait for views to respond to the configure before giving | ||
20 | * up and applying the transaction anyway. | ||
21 | */ | ||
22 | int txn_timeout_ms = 200; | ||
23 | |||
24 | /** | ||
25 | * If enabled, sway will always wait for the transaction timeout before | ||
26 | * applying it, rather than applying it when the views are ready. This allows us | ||
27 | * to observe the rendered state while a transaction is in progress. | ||
28 | */ | ||
29 | bool txn_debug = false; | ||
30 | |||
31 | struct sway_transaction { | 20 | struct sway_transaction { |
32 | struct wl_event_source *timer; | 21 | struct wl_event_source *timer; |
33 | list_t *instructions; // struct sway_transaction_instruction * | 22 | list_t *instructions; // struct sway_transaction_instruction * |
34 | size_t num_waiting; | 23 | size_t num_waiting; |
35 | size_t num_configures; | 24 | size_t num_configures; |
36 | uint32_t con_ids; // Bitwise XOR of view container IDs | 25 | uint32_t con_ids; // Bitwise XOR of view container IDs |
37 | struct timespec create_time; | ||
38 | struct timespec commit_time; | 26 | struct timespec commit_time; |
39 | }; | 27 | }; |
40 | 28 | ||
@@ -52,9 +40,6 @@ static struct sway_transaction *transaction_create() { | |||
52 | return NULL; | 40 | return NULL; |
53 | } | 41 | } |
54 | transaction->instructions = create_list(); | 42 | transaction->instructions = create_list(); |
55 | if (server.debug_txn_timings) { | ||
56 | clock_gettime(CLOCK_MONOTONIC, &transaction->create_time); | ||
57 | } | ||
58 | return transaction; | 43 | return transaction; |
59 | } | 44 | } |
60 | 45 | ||
@@ -107,10 +92,12 @@ static void copy_pending_state(struct sway_container *container, | |||
107 | state->border_left = view->border_left; | 92 | state->border_left = view->border_left; |
108 | state->border_right = view->border_right; | 93 | state->border_right = view->border_right; |
109 | state->border_bottom = view->border_bottom; | 94 | state->border_bottom = view->border_bottom; |
95 | state->using_csd = view->using_csd; | ||
110 | } else if (container->type == C_WORKSPACE) { | 96 | } else if (container->type == C_WORKSPACE) { |
111 | state->ws_fullscreen = container->sway_workspace->fullscreen; | 97 | state->ws_fullscreen = container->sway_workspace->fullscreen; |
112 | state->ws_floating = container->sway_workspace->floating; | 98 | state->ws_floating = create_list(); |
113 | state->children = create_list(); | 99 | state->children = create_list(); |
100 | list_cat(state->ws_floating, container->sway_workspace->floating); | ||
114 | list_cat(state->children, container->children); | 101 | list_cat(state->children, container->children); |
115 | } else { | 102 | } else { |
116 | state->children = create_list(); | 103 | state->children = create_list(); |
@@ -147,19 +134,14 @@ static void transaction_add_container(struct sway_transaction *transaction, | |||
147 | */ | 134 | */ |
148 | static void transaction_apply(struct sway_transaction *transaction) { | 135 | static void transaction_apply(struct sway_transaction *transaction) { |
149 | wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); | 136 | wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); |
150 | if (server.debug_txn_timings) { | 137 | if (debug.txn_timings) { |
151 | struct timespec now; | 138 | struct timespec now; |
152 | clock_gettime(CLOCK_MONOTONIC, &now); | 139 | clock_gettime(CLOCK_MONOTONIC, &now); |
153 | struct timespec *create = &transaction->create_time; | ||
154 | struct timespec *commit = &transaction->commit_time; | 140 | struct timespec *commit = &transaction->commit_time; |
155 | float ms_arranging = (commit->tv_sec - create->tv_sec) * 1000 + | 141 | float ms = (now.tv_sec - commit->tv_sec) * 1000 + |
156 | (commit->tv_nsec - create->tv_nsec) / 1000000.0; | ||
157 | float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 + | ||
158 | (now.tv_nsec - commit->tv_nsec) / 1000000.0; | 142 | (now.tv_nsec - commit->tv_nsec) / 1000000.0; |
159 | float ms_total = ms_arranging + ms_waiting; | 143 | wlr_log(WLR_DEBUG, "Transaction %p: %.1fms waiting " |
160 | wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " | 144 | "(%.1f frames if 60Hz)", transaction, ms, ms / (1000.0f / 60)); |
161 | "%.1fms total (%.1f frames if 60Hz)", transaction, | ||
162 | ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60)); | ||
163 | } | 145 | } |
164 | 146 | ||
165 | // Apply the instruction state to the container's current state | 147 | // Apply the instruction state to the container's current state |
@@ -168,25 +150,17 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
168 | transaction->instructions->items[i]; | 150 | transaction->instructions->items[i]; |
169 | struct sway_container *container = instruction->container; | 151 | struct sway_container *container = instruction->container; |
170 | 152 | ||
171 | // Damage the old and new locations | 153 | // Damage the old location |
172 | struct wlr_box old_box = { | 154 | desktop_damage_whole_container(container); |
173 | .x = container->current.swayc_x, | 155 | if (container->type == C_VIEW && container->sway_view->saved_buffer) { |
174 | .y = container->current.swayc_y, | 156 | struct sway_view *view = container->sway_view; |
175 | .width = container->current.swayc_width, | 157 | struct wlr_box box = { |
176 | .height = container->current.swayc_height, | 158 | .x = container->current.view_x - view->saved_geometry.x, |
177 | }; | 159 | .y = container->current.view_y - view->saved_geometry.y, |
178 | struct wlr_box new_box = { | 160 | .width = view->saved_buffer_width, |
179 | .x = instruction->state.swayc_x, | 161 | .height = view->saved_buffer_height, |
180 | .y = instruction->state.swayc_y, | 162 | }; |
181 | .width = instruction->state.swayc_width, | 163 | desktop_damage_box(&box); |
182 | .height = instruction->state.swayc_height, | ||
183 | }; | ||
184 | for (int j = 0; j < root_container.current.children->length; ++j) { | ||
185 | struct sway_container *output = root_container.current.children->items[j]; | ||
186 | if (output->sway_output) { | ||
187 | output_damage_box(output->sway_output, &old_box); | ||
188 | output_damage_box(output->sway_output, &new_box); | ||
189 | } | ||
190 | } | 164 | } |
191 | 165 | ||
192 | // There are separate children lists for each instruction state, the | 166 | // There are separate children lists for each instruction state, the |
@@ -195,15 +169,35 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
195 | // Any child containers which are being deleted will be cleaned up in | 169 | // Any child containers which are being deleted will be cleaned up in |
196 | // transaction_destroy(). | 170 | // transaction_destroy(). |
197 | list_free(container->current.children); | 171 | list_free(container->current.children); |
172 | list_free(container->current.ws_floating); | ||
198 | 173 | ||
199 | memcpy(&container->current, &instruction->state, | 174 | memcpy(&container->current, &instruction->state, |
200 | sizeof(struct sway_container_state)); | 175 | sizeof(struct sway_container_state)); |
201 | 176 | ||
202 | if (container->type == C_VIEW && container->sway_view->saved_buffer) { | 177 | if (container->type == C_VIEW && container->sway_view->saved_buffer) { |
203 | view_remove_saved_buffer(container->sway_view); | 178 | if (!container->destroying || container->ntxnrefs == 1) { |
179 | view_remove_saved_buffer(container->sway_view); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | // Damage the new location | ||
184 | desktop_damage_whole_container(container); | ||
185 | if (container->type == C_VIEW && container->sway_view->surface) { | ||
186 | struct sway_view *view = container->sway_view; | ||
187 | struct wlr_surface *surface = view->surface; | ||
188 | struct wlr_box box = { | ||
189 | .x = container->current.view_x - view->geometry.x, | ||
190 | .y = container->current.view_y - view->geometry.y, | ||
191 | .width = surface->current.width, | ||
192 | .height = surface->current.height, | ||
193 | }; | ||
194 | desktop_damage_box(&box); | ||
204 | } | 195 | } |
205 | 196 | ||
206 | container->instruction = NULL; | 197 | container->instruction = NULL; |
198 | if (container->type == C_CONTAINER || container->type == C_VIEW) { | ||
199 | container_discover_outputs(container); | ||
200 | } | ||
207 | } | 201 | } |
208 | } | 202 | } |
209 | 203 | ||
@@ -294,31 +288,38 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
294 | struct timespec when; | 288 | struct timespec when; |
295 | wlr_surface_send_frame_done(con->sway_view->surface, &when); | 289 | wlr_surface_send_frame_done(con->sway_view->surface, &when); |
296 | } | 290 | } |
297 | if (con->type == C_VIEW) { | 291 | if (con->type == C_VIEW && !con->sway_view->saved_buffer) { |
298 | view_save_buffer(con->sway_view); | 292 | view_save_buffer(con->sway_view); |
293 | memcpy(&con->sway_view->saved_geometry, &con->sway_view->geometry, | ||
294 | sizeof(struct wlr_box)); | ||
299 | } | 295 | } |
300 | con->instruction = instruction; | 296 | con->instruction = instruction; |
301 | } | 297 | } |
302 | transaction->num_configures = transaction->num_waiting; | 298 | transaction->num_configures = transaction->num_waiting; |
303 | if (server.debug_txn_timings) { | 299 | if (debug.txn_timings) { |
304 | clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); | 300 | clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); |
305 | } | 301 | } |
302 | if (debug.noatomic) { | ||
303 | transaction->num_waiting = 0; | ||
304 | } else if (debug.txn_wait) { | ||
305 | // Force the transaction to time out even if all views are ready. | ||
306 | // We do this by inflating the waiting counter. | ||
307 | transaction->num_waiting += 1000000; | ||
308 | } | ||
306 | 309 | ||
307 | if (transaction->num_waiting) { | 310 | if (transaction->num_waiting) { |
308 | // Set up a timer which the views must respond within | 311 | // Set up a timer which the views must respond within |
309 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, | 312 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, |
310 | handle_timeout, transaction); | 313 | handle_timeout, transaction); |
311 | if (transaction->timer) { | 314 | if (transaction->timer) { |
312 | wl_event_source_timer_update(transaction->timer, txn_timeout_ms); | 315 | wl_event_source_timer_update(transaction->timer, |
316 | server.txn_timeout_ms); | ||
313 | } else { | 317 | } else { |
314 | wlr_log(WLR_ERROR, "Unable to create transaction timer (%s). " | 318 | wlr_log(WLR_ERROR, "Unable to create transaction timer (%s). " |
315 | "Some imperfect frames might be rendered.", | 319 | "Some imperfect frames might be rendered.", |
316 | strerror(errno)); | 320 | strerror(errno)); |
317 | handle_timeout(transaction); | 321 | transaction->num_waiting = 0; |
318 | } | 322 | } |
319 | } else { | ||
320 | wlr_log(WLR_DEBUG, | ||
321 | "Transaction %p has nothing to wait for", transaction); | ||
322 | } | 323 | } |
323 | 324 | ||
324 | // The debug tree shows the pending/live tree. Here is a good place to | 325 | // The debug tree shows the pending/live tree. Here is a good place to |
@@ -331,7 +332,7 @@ static void set_instruction_ready( | |||
331 | struct sway_transaction_instruction *instruction) { | 332 | struct sway_transaction_instruction *instruction) { |
332 | struct sway_transaction *transaction = instruction->transaction; | 333 | struct sway_transaction *transaction = instruction->transaction; |
333 | 334 | ||
334 | if (server.debug_txn_timings) { | 335 | if (debug.txn_timings) { |
335 | struct timespec now; | 336 | struct timespec now; |
336 | clock_gettime(CLOCK_MONOTONIC, &now); | 337 | clock_gettime(CLOCK_MONOTONIC, &now); |
337 | struct timespec *start = &transaction->commit_time; | 338 | struct timespec *start = &transaction->commit_time; |
@@ -342,15 +343,12 @@ static void set_instruction_ready( | |||
342 | transaction->num_configures - transaction->num_waiting + 1, | 343 | transaction->num_configures - transaction->num_waiting + 1, |
343 | transaction->num_configures, ms, | 344 | transaction->num_configures, ms, |
344 | instruction->container->name); | 345 | instruction->container->name); |
345 | |||
346 | } | 346 | } |
347 | 347 | ||
348 | // If the transaction has timed out then its num_waiting will be 0 already. | 348 | // If the transaction has timed out then its num_waiting will be 0 already. |
349 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { | 349 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { |
350 | if (!txn_debug) { | 350 | wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); |
351 | wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); | 351 | wl_event_source_timer_update(transaction->timer, 0); |
352 | wl_event_source_timer_update(transaction->timer, 0); | ||
353 | } | ||
354 | } | 352 | } |
355 | 353 | ||
356 | instruction->container->instruction = NULL; | 354 | instruction->container->instruction = NULL; |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 6a7a3f7f..aae129bd 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <wlr/util/edges.h> | 7 | #include <wlr/util/edges.h> |
8 | #include "log.h" | 8 | #include "log.h" |
9 | #include "sway/decoration.h" | 9 | #include "sway/decoration.h" |
10 | #include "sway/desktop.h" | ||
10 | #include "sway/input/input-manager.h" | 11 | #include "sway/input/input-manager.h" |
11 | #include "sway/input/seat.h" | 12 | #include "sway/input/seat.h" |
12 | #include "sway/server.h" | 13 | #include "sway/server.h" |
@@ -107,7 +108,8 @@ static void get_constraints(struct sway_view *view, double *min_width, | |||
107 | *max_height = state->max_height > 0 ? state->max_height : DBL_MAX; | 108 | *max_height = state->max_height > 0 ? state->max_height : DBL_MAX; |
108 | } | 109 | } |
109 | 110 | ||
110 | static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { | 111 | static const char *get_string_prop(struct sway_view *view, |
112 | enum sway_view_prop prop) { | ||
111 | if (xdg_shell_view_from_view(view) == NULL) { | 113 | if (xdg_shell_view_from_view(view) == NULL) { |
112 | return NULL; | 114 | return NULL; |
113 | } | 115 | } |
@@ -255,8 +257,24 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
255 | } | 257 | } |
256 | 258 | ||
257 | if (view->swayc->instruction) { | 259 | if (view->swayc->instruction) { |
260 | wlr_xdg_surface_get_geometry(xdg_surface, &view->geometry); | ||
258 | transaction_notify_view_ready_by_serial(view, | 261 | transaction_notify_view_ready_by_serial(view, |
259 | xdg_surface->configure_serial); | 262 | xdg_surface->configure_serial); |
263 | } else { | ||
264 | struct wlr_box new_geo; | ||
265 | wlr_xdg_surface_get_geometry(xdg_surface, &new_geo); | ||
266 | |||
267 | if ((new_geo.width != view->width || new_geo.height != view->height) && | ||
268 | container_is_floating(view->swayc)) { | ||
269 | // A floating view has unexpectedly sent a new size | ||
270 | desktop_damage_view(view); | ||
271 | view_update_size(view, new_geo.width, new_geo.height); | ||
272 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
273 | desktop_damage_view(view); | ||
274 | transaction_commit_dirty(); | ||
275 | } else { | ||
276 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
277 | } | ||
260 | } | 278 | } |
261 | 279 | ||
262 | view_damage_from(view); | 280 | view_damage_from(view); |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 5b3c7b2b..277c53a3 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <wlr/types/wlr_xdg_shell_v6.h> | 6 | #include <wlr/types/wlr_xdg_shell_v6.h> |
7 | #include "log.h" | 7 | #include "log.h" |
8 | #include "sway/decoration.h" | 8 | #include "sway/decoration.h" |
9 | #include "sway/desktop.h" | ||
9 | #include "sway/input/input-manager.h" | 10 | #include "sway/input/input-manager.h" |
10 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
11 | #include "sway/server.h" | 12 | #include "sway/server.h" |
@@ -106,7 +107,8 @@ static void get_constraints(struct sway_view *view, double *min_width, | |||
106 | *max_height = state->max_height > 0 ? state->max_height : DBL_MAX; | 107 | *max_height = state->max_height > 0 ? state->max_height : DBL_MAX; |
107 | } | 108 | } |
108 | 109 | ||
109 | static const char *get_string_prop(struct sway_view *view, enum sway_view_prop prop) { | 110 | static const char *get_string_prop(struct sway_view *view, |
111 | enum sway_view_prop prop) { | ||
110 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 112 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
111 | return NULL; | 113 | return NULL; |
112 | } | 114 | } |
@@ -250,9 +252,26 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
250 | if (!view->swayc) { | 252 | if (!view->swayc) { |
251 | return; | 253 | return; |
252 | } | 254 | } |
255 | |||
253 | if (view->swayc->instruction) { | 256 | if (view->swayc->instruction) { |
257 | wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &view->geometry); | ||
254 | transaction_notify_view_ready_by_serial(view, | 258 | transaction_notify_view_ready_by_serial(view, |
255 | xdg_surface_v6->configure_serial); | 259 | xdg_surface_v6->configure_serial); |
260 | } else { | ||
261 | struct wlr_box new_geo; | ||
262 | wlr_xdg_surface_v6_get_geometry(xdg_surface_v6, &new_geo); | ||
263 | |||
264 | if ((new_geo.width != view->width || new_geo.height != view->height) && | ||
265 | container_is_floating(view->swayc)) { | ||
266 | // A floating view has unexpectedly sent a new size | ||
267 | desktop_damage_view(view); | ||
268 | view_update_size(view, new_geo.width, new_geo.height); | ||
269 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
270 | desktop_damage_view(view); | ||
271 | transaction_commit_dirty(); | ||
272 | } else { | ||
273 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
274 | } | ||
256 | } | 275 | } |
257 | 276 | ||
258 | view_damage_from(view); | 277 | view_damage_from(view); |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 14f59b9c..ce7235e4 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -277,18 +277,44 @@ static const struct sway_view_impl view_impl = { | |||
277 | .destroy = destroy, | 277 | .destroy = destroy, |
278 | }; | 278 | }; |
279 | 279 | ||
280 | static void get_geometry(struct sway_view *view, struct wlr_box *box) { | ||
281 | box->x = box->y = 0; | ||
282 | if (view->surface) { | ||
283 | box->width = view->surface->current.width; | ||
284 | box->height = view->surface->current.height; | ||
285 | } else { | ||
286 | box->width = 0; | ||
287 | box->height = 0; | ||
288 | } | ||
289 | } | ||
290 | |||
280 | static void handle_commit(struct wl_listener *listener, void *data) { | 291 | static void handle_commit(struct wl_listener *listener, void *data) { |
281 | struct sway_xwayland_view *xwayland_view = | 292 | struct sway_xwayland_view *xwayland_view = |
282 | wl_container_of(listener, xwayland_view, commit); | 293 | wl_container_of(listener, xwayland_view, commit); |
283 | struct sway_view *view = &xwayland_view->view; | 294 | struct sway_view *view = &xwayland_view->view; |
284 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 295 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
285 | struct wlr_surface_state *surface_state = &xsurface->surface->current; | 296 | struct wlr_surface_state *state = &xsurface->surface->current; |
286 | 297 | ||
287 | if (view->swayc->instruction) { | 298 | if (view->swayc->instruction) { |
299 | get_geometry(view, &view->geometry); | ||
288 | transaction_notify_view_ready_by_size(view, | 300 | transaction_notify_view_ready_by_size(view, |
289 | surface_state->width, surface_state->height); | 301 | state->width, state->height); |
290 | } else if (container_is_floating(view->swayc)) { | 302 | } else { |
291 | view_update_size(view, surface_state->width, surface_state->height); | 303 | struct wlr_box new_geo; |
304 | get_geometry(view, &new_geo); | ||
305 | |||
306 | if ((new_geo.width != view->width || new_geo.height != view->height) && | ||
307 | container_is_floating(view->swayc)) { | ||
308 | // A floating view has unexpectedly sent a new size | ||
309 | // eg. The Firefox "Save As" dialog when downloading a file | ||
310 | desktop_damage_view(view); | ||
311 | view_update_size(view, new_geo.width, new_geo.height); | ||
312 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
313 | desktop_damage_view(view); | ||
314 | transaction_commit_dirty(); | ||
315 | } else { | ||
316 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
317 | } | ||
292 | } | 318 | } |
293 | 319 | ||
294 | view_damage_from(view); | 320 | view_damage_from(view); |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 3b70b471..ba5e0400 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -215,6 +215,19 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont, | |||
215 | return edge; | 215 | return edge; |
216 | } | 216 | } |
217 | 217 | ||
218 | static void handle_down_motion(struct sway_seat *seat, | ||
219 | struct sway_cursor *cursor, uint32_t time_msec) { | ||
220 | struct sway_container *con = seat->op_container; | ||
221 | if (seat_is_input_allowed(seat, con->sway_view->surface)) { | ||
222 | double moved_x = cursor->cursor->x - seat->op_ref_lx; | ||
223 | double moved_y = cursor->cursor->y - seat->op_ref_ly; | ||
224 | double sx = seat->op_ref_con_lx + moved_x; | ||
225 | double sy = seat->op_ref_con_ly + moved_y; | ||
226 | wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy); | ||
227 | } | ||
228 | seat->op_moved = true; | ||
229 | } | ||
230 | |||
218 | static void handle_move_motion(struct sway_seat *seat, | 231 | static void handle_move_motion(struct sway_seat *seat, |
219 | struct sway_cursor *cursor) { | 232 | struct sway_cursor *cursor) { |
220 | struct sway_container *con = seat->op_container; | 233 | struct sway_container *con = seat->op_container; |
@@ -397,6 +410,9 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
397 | 410 | ||
398 | if (seat->operation != OP_NONE) { | 411 | if (seat->operation != OP_NONE) { |
399 | switch (seat->operation) { | 412 | switch (seat->operation) { |
413 | case OP_DOWN: | ||
414 | handle_down_motion(seat, cursor, time_msec); | ||
415 | break; | ||
400 | case OP_MOVE: | 416 | case OP_MOVE: |
401 | handle_move_motion(seat, cursor); | 417 | handle_move_motion(seat, cursor); |
402 | break; | 418 | break; |
@@ -708,7 +724,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
708 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; | 724 | uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT; |
709 | if (button == btn_move && state == WLR_BUTTON_PRESSED && | 725 | if (button == btn_move && state == WLR_BUTTON_PRESSED && |
710 | (mod_pressed || on_titlebar)) { | 726 | (mod_pressed || on_titlebar)) { |
711 | while (cont->parent->layout != L_FLOATING) { | 727 | while (cont->parent->type != C_WORKSPACE) { |
712 | cont = cont->parent; | 728 | cont = cont->parent; |
713 | } | 729 | } |
714 | seat_begin_move(seat, cont, button); | 730 | seat_begin_move(seat, cont, button); |
@@ -726,13 +742,13 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
726 | } | 742 | } |
727 | 743 | ||
728 | // Via mod+click | 744 | // Via mod+click |
729 | struct sway_container *floater = cont; | ||
730 | while (floater->parent->layout != L_FLOATING) { | ||
731 | floater = floater->parent; | ||
732 | } | ||
733 | uint32_t btn_resize = config->floating_mod_inverse ? | 745 | uint32_t btn_resize = config->floating_mod_inverse ? |
734 | BTN_LEFT : BTN_RIGHT; | 746 | BTN_LEFT : BTN_RIGHT; |
735 | if (button == btn_resize) { | 747 | if (mod_pressed && button == btn_resize) { |
748 | struct sway_container *floater = cont; | ||
749 | while (floater->parent->type != C_WORKSPACE) { | ||
750 | floater = floater->parent; | ||
751 | } | ||
736 | edge = 0; | 752 | edge = 0; |
737 | edge |= cursor->cursor->x > floater->x + floater->width / 2 ? | 753 | edge |= cursor->cursor->x > floater->x + floater->width / 2 ? |
738 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | 754 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; |
@@ -743,6 +759,14 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
743 | } | 759 | } |
744 | } | 760 | } |
745 | 761 | ||
762 | // Handle mousedown on a container surface | ||
763 | if (surface && cont && state == WLR_BUTTON_PRESSED) { | ||
764 | seat_set_focus(seat, cont); | ||
765 | seat_pointer_notify_button(seat, time_msec, button, state); | ||
766 | seat_begin_down(seat, cont, button, sx, sy); | ||
767 | return; | ||
768 | } | ||
769 | |||
746 | // Handle clicking a container surface | 770 | // Handle clicking a container surface |
747 | if (cont) { | 771 | if (cont) { |
748 | seat_set_focus(seat, cont); | 772 | seat_set_focus(seat, cont); |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 57cc65f6..4077a8dd 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -124,42 +124,6 @@ static void seat_send_focus(struct sway_container *con, | |||
124 | } | 124 | } |
125 | } | 125 | } |
126 | 126 | ||
127 | static struct sway_container *seat_get_focus_by_type(struct sway_seat *seat, | ||
128 | struct sway_container *container, enum sway_container_type type, | ||
129 | bool only_tiling) { | ||
130 | if (container->type == C_VIEW) { | ||
131 | return container; | ||
132 | } | ||
133 | |||
134 | struct sway_container *floating = | ||
135 | container->type == C_WORKSPACE && !only_tiling ? | ||
136 | container->sway_workspace->floating : NULL; | ||
137 | if (container->children->length == 0 && | ||
138 | (!floating || floating->children->length == 0)) { | ||
139 | return container; | ||
140 | } | ||
141 | |||
142 | struct sway_seat_container *current = NULL; | ||
143 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
144 | if (current->container->type != type && type != C_TYPES) { | ||
145 | continue; | ||
146 | } | ||
147 | |||
148 | if (container_has_ancestor(current->container, container)) { | ||
149 | if (only_tiling && | ||
150 | container_is_floating_or_child(current->container)) { | ||
151 | continue; | ||
152 | } | ||
153 | return current->container; | ||
154 | } | ||
155 | if (floating && container_has_ancestor(current->container, floating)) { | ||
156 | return current->container; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | void seat_focus_inactive_children_for_each(struct sway_seat *seat, | 127 | void seat_focus_inactive_children_for_each(struct sway_seat *seat, |
164 | struct sway_container *container, | 128 | struct sway_container *container, |
165 | void (*f)(struct sway_container *container, void *data), void *data) { | 129 | void (*f)(struct sway_container *container, void *data), void *data) { |
@@ -175,8 +139,18 @@ void seat_focus_inactive_children_for_each(struct sway_seat *seat, | |||
175 | } | 139 | } |
176 | 140 | ||
177 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, | 141 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, |
178 | struct sway_container *container) { | 142 | struct sway_container *ancestor) { |
179 | return seat_get_focus_by_type(seat, container, C_VIEW, false); | 143 | if (ancestor->type == C_VIEW) { |
144 | return ancestor; | ||
145 | } | ||
146 | struct sway_seat_container *current; | ||
147 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
148 | struct sway_container *con = current->container; | ||
149 | if (con->type == C_VIEW && container_has_ancestor(con, ancestor)) { | ||
150 | return con; | ||
151 | } | ||
152 | } | ||
153 | return NULL; | ||
180 | } | 154 | } |
181 | 155 | ||
182 | static void handle_seat_container_destroy(struct wl_listener *listener, | 156 | static void handle_seat_container_destroy(struct wl_listener *listener, |
@@ -198,7 +172,7 @@ static void handle_seat_container_destroy(struct wl_listener *listener, | |||
198 | if (set_focus) { | 172 | if (set_focus) { |
199 | struct sway_container *next_focus = NULL; | 173 | struct sway_container *next_focus = NULL; |
200 | while (next_focus == NULL) { | 174 | while (next_focus == NULL) { |
201 | next_focus = seat_get_focus_by_type(seat, parent, C_VIEW, false); | 175 | next_focus = seat_get_focus_inactive_view(seat, parent); |
202 | 176 | ||
203 | if (next_focus == NULL && parent->type == C_WORKSPACE) { | 177 | if (next_focus == NULL && parent->type == C_WORKSPACE) { |
204 | next_focus = parent; | 178 | next_focus = parent; |
@@ -339,9 +313,6 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) { | |||
339 | 313 | ||
340 | static void collect_focus_iter(struct sway_container *con, void *data) { | 314 | static void collect_focus_iter(struct sway_container *con, void *data) { |
341 | struct sway_seat *seat = data; | 315 | struct sway_seat *seat = data; |
342 | if (con->type > C_WORKSPACE) { | ||
343 | return; | ||
344 | } | ||
345 | struct sway_seat_container *seat_con = | 316 | struct sway_seat_container *seat_con = |
346 | seat_container_from_container(seat, con); | 317 | seat_container_from_container(seat, con); |
347 | if (!seat_con) { | 318 | if (!seat_con) { |
@@ -375,7 +346,8 @@ struct sway_seat *seat_create(struct sway_input_manager *input, | |||
375 | // init the focus stack | 346 | // init the focus stack |
376 | wl_list_init(&seat->focus_stack); | 347 | wl_list_init(&seat->focus_stack); |
377 | 348 | ||
378 | container_for_each_descendant(&root_container, collect_focus_iter, seat); | 349 | root_for_each_workspace(collect_focus_iter, seat); |
350 | root_for_each_container(collect_focus_iter, seat); | ||
379 | 351 | ||
380 | wl_signal_add(&root_container.sway_root->events.new_container, | 352 | wl_signal_add(&root_container.sway_root->events.new_container, |
381 | &seat->new_container); | 353 | &seat->new_container); |
@@ -653,8 +625,7 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
653 | // find new output's old workspace, which might have to be removed if empty | 625 | // find new output's old workspace, which might have to be removed if empty |
654 | struct sway_container *new_output_last_ws = NULL; | 626 | struct sway_container *new_output_last_ws = NULL; |
655 | if (last_output && new_output && last_output != new_output) { | 627 | if (last_output && new_output && last_output != new_output) { |
656 | new_output_last_ws = | 628 | new_output_last_ws = seat_get_active_child(seat, new_output); |
657 | seat_get_focus_by_type(seat, new_output, C_WORKSPACE, false); | ||
658 | } | 629 | } |
659 | 630 | ||
660 | if (container && container->parent) { | 631 | if (container && container->parent) { |
@@ -717,7 +688,8 @@ void seat_set_focus_warp(struct sway_seat *seat, | |||
717 | // If we've focused a floating container, bring it to the front. | 688 | // If we've focused a floating container, bring it to the front. |
718 | // We do this by putting it at the end of the floating list. | 689 | // We do this by putting it at the end of the floating list. |
719 | if (container && container_is_floating(container)) { | 690 | if (container && container_is_floating(container)) { |
720 | list_move_to_end(container->parent->children, container); | 691 | list_move_to_end( |
692 | container->parent->sway_workspace->floating, container); | ||
721 | } | 693 | } |
722 | 694 | ||
723 | // clean up unfocused empty workspace on new output | 695 | // clean up unfocused empty workspace on new output |
@@ -877,22 +849,66 @@ void seat_set_exclusive_client(struct sway_seat *seat, | |||
877 | } | 849 | } |
878 | 850 | ||
879 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, | 851 | struct sway_container *seat_get_focus_inactive(struct sway_seat *seat, |
880 | struct sway_container *container) { | 852 | struct sway_container *con) { |
881 | return seat_get_focus_by_type(seat, container, C_TYPES, false); | 853 | if (con->type == C_WORKSPACE && !con->children->length && |
854 | !con->sway_workspace->floating->length) { | ||
855 | return con; | ||
856 | } | ||
857 | if (con->type == C_VIEW) { | ||
858 | return con; | ||
859 | } | ||
860 | struct sway_seat_container *current; | ||
861 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
862 | if (container_has_ancestor(current->container, con)) { | ||
863 | return current->container; | ||
864 | } | ||
865 | } | ||
866 | return NULL; | ||
882 | } | 867 | } |
883 | 868 | ||
884 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, | 869 | struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, |
885 | struct sway_container *container) { | 870 | struct sway_container *ancestor) { |
886 | return seat_get_focus_by_type(seat, container, C_TYPES, true); | 871 | if (ancestor->type == C_WORKSPACE && !ancestor->children->length) { |
872 | return ancestor; | ||
873 | } | ||
874 | struct sway_seat_container *current; | ||
875 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
876 | struct sway_container *con = current->container; | ||
877 | if (!container_is_floating_or_child(con) && | ||
878 | container_has_ancestor(current->container, ancestor)) { | ||
879 | return con; | ||
880 | } | ||
881 | } | ||
882 | return NULL; | ||
883 | } | ||
884 | |||
885 | struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, | ||
886 | struct sway_container *ancestor) { | ||
887 | if (ancestor->type == C_WORKSPACE && | ||
888 | !ancestor->sway_workspace->floating->length) { | ||
889 | return NULL; | ||
890 | } | ||
891 | struct sway_seat_container *current; | ||
892 | wl_list_for_each(current, &seat->focus_stack, link) { | ||
893 | struct sway_container *con = current->container; | ||
894 | if (container_is_floating_or_child(con) && | ||
895 | container_has_ancestor(current->container, ancestor)) { | ||
896 | return con; | ||
897 | } | ||
898 | } | ||
899 | return NULL; | ||
887 | } | 900 | } |
888 | 901 | ||
889 | struct sway_container *seat_get_active_child(struct sway_seat *seat, | 902 | struct sway_container *seat_get_active_child(struct sway_seat *seat, |
890 | struct sway_container *container) { | 903 | struct sway_container *parent) { |
891 | struct sway_seat_container *current = NULL; | 904 | if (parent->type == C_VIEW) { |
905 | return parent; | ||
906 | } | ||
907 | struct sway_seat_container *current; | ||
892 | wl_list_for_each(current, &seat->focus_stack, link) { | 908 | wl_list_for_each(current, &seat->focus_stack, link) { |
893 | if (current->container->parent == container && | 909 | struct sway_container *con = current->container; |
894 | current->container->layout != L_FLOATING) { | 910 | if (con->parent == parent) { |
895 | return current->container; | 911 | return con; |
896 | } | 912 | } |
897 | } | 913 | } |
898 | return NULL; | 914 | return NULL; |
@@ -902,7 +918,9 @@ struct sway_container *seat_get_focus(struct sway_seat *seat) { | |||
902 | if (!seat->has_focus) { | 918 | if (!seat->has_focus) { |
903 | return NULL; | 919 | return NULL; |
904 | } | 920 | } |
905 | return seat_get_focus_inactive(seat, &root_container); | 921 | struct sway_seat_container *current = |
922 | wl_container_of(seat->focus_stack.next, current, link); | ||
923 | return current->container; | ||
906 | } | 924 | } |
907 | 925 | ||
908 | void seat_apply_config(struct sway_seat *seat, | 926 | void seat_apply_config(struct sway_seat *seat, |
@@ -930,6 +948,18 @@ struct seat_config *seat_get_config(struct sway_seat *seat) { | |||
930 | return NULL; | 948 | return NULL; |
931 | } | 949 | } |
932 | 950 | ||
951 | void seat_begin_down(struct sway_seat *seat, struct sway_container *con, | ||
952 | uint32_t button, double sx, double sy) { | ||
953 | seat->operation = OP_DOWN; | ||
954 | seat->op_container = con; | ||
955 | seat->op_button = button; | ||
956 | seat->op_ref_lx = seat->cursor->cursor->x; | ||
957 | seat->op_ref_ly = seat->cursor->cursor->y; | ||
958 | seat->op_ref_con_lx = sx; | ||
959 | seat->op_ref_con_ly = sy; | ||
960 | seat->op_moved = false; | ||
961 | } | ||
962 | |||
933 | void seat_begin_move(struct sway_seat *seat, struct sway_container *con, | 963 | void seat_begin_move(struct sway_seat *seat, struct sway_container *con, |
934 | uint32_t button) { | 964 | uint32_t button) { |
935 | if (!seat->cursor) { | 965 | if (!seat->cursor) { |
@@ -954,7 +984,7 @@ void seat_begin_resize_floating(struct sway_seat *seat, | |||
954 | seat->op_resize_preserve_ratio = keyboard && | 984 | seat->op_resize_preserve_ratio = keyboard && |
955 | (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); | 985 | (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT); |
956 | seat->op_resize_edge = edge == WLR_EDGE_NONE ? | 986 | seat->op_resize_edge = edge == WLR_EDGE_NONE ? |
957 | RESIZE_EDGE_BOTTOM | RESIZE_EDGE_RIGHT : edge; | 987 | WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; |
958 | seat->op_button = button; | 988 | seat->op_button = button; |
959 | seat->op_ref_lx = seat->cursor->cursor->x; | 989 | seat->op_ref_lx = seat->cursor->cursor->x; |
960 | seat->op_ref_ly = seat->cursor->cursor->y; | 990 | seat->op_ref_ly = seat->cursor->cursor->y; |
@@ -983,6 +1013,7 @@ void seat_begin_resize_tiling(struct sway_seat *seat, | |||
983 | } | 1013 | } |
984 | 1014 | ||
985 | void seat_end_mouse_operation(struct sway_seat *seat) { | 1015 | void seat_end_mouse_operation(struct sway_seat *seat) { |
1016 | enum sway_seat_operation operation = seat->operation; | ||
986 | if (seat->operation == OP_MOVE) { | 1017 | if (seat->operation == OP_MOVE) { |
987 | // We "move" the container to its own location so it discovers its | 1018 | // We "move" the container to its own location so it discovers its |
988 | // output again. | 1019 | // output again. |
@@ -991,7 +1022,19 @@ void seat_end_mouse_operation(struct sway_seat *seat) { | |||
991 | } | 1022 | } |
992 | seat->operation = OP_NONE; | 1023 | seat->operation = OP_NONE; |
993 | seat->op_container = NULL; | 1024 | seat->op_container = NULL; |
994 | cursor_set_image(seat->cursor, "left_ptr", NULL); | 1025 | if (operation == OP_DOWN) { |
1026 | // Set the cursor's previous coords to the x/y at the start of the | ||
1027 | // operation, so the container change will be detected if using | ||
1028 | // focus_follows_mouse and the cursor moved off the original container | ||
1029 | // during the operation. | ||
1030 | seat->cursor->previous.x = seat->op_ref_lx; | ||
1031 | seat->cursor->previous.y = seat->op_ref_ly; | ||
1032 | if (seat->op_moved) { | ||
1033 | cursor_send_pointer_motion(seat->cursor, 0, true); | ||
1034 | } | ||
1035 | } else { | ||
1036 | cursor_set_image(seat->cursor, "left_ptr", NULL); | ||
1037 | } | ||
995 | } | 1038 | } |
996 | 1039 | ||
997 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, | 1040 | void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec, |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 4c2bcc98..06cb7e11 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/config.h" | 5 | #include "sway/config.h" |
6 | #include "sway/ipc-json.h" | 6 | #include "sway/ipc-json.h" |
7 | #include "sway/tree/container.h" | 7 | #include "sway/tree/container.h" |
8 | #include "sway/tree/view.h" | ||
8 | #include "sway/tree/workspace.h" | 9 | #include "sway/tree/workspace.h" |
9 | #include "sway/output.h" | 10 | #include "sway/output.h" |
10 | #include "sway/input/input-manager.h" | 11 | #include "sway/input/input-manager.h" |
@@ -23,8 +24,6 @@ static const char *ipc_json_layout_description(enum sway_container_layout l) { | |||
23 | return "tabbed"; | 24 | return "tabbed"; |
24 | case L_STACKED: | 25 | case L_STACKED: |
25 | return "stacked"; | 26 | return "stacked"; |
26 | case L_FLOATING: | ||
27 | return "floating"; | ||
28 | case L_NONE: | 27 | case L_NONE: |
29 | break; | 28 | break; |
30 | } | 29 | } |
@@ -180,10 +179,11 @@ static void ipc_json_describe_workspace(struct sway_container *workspace, | |||
180 | 179 | ||
181 | // Floating | 180 | // Floating |
182 | json_object *floating_array = json_object_new_array(); | 181 | json_object *floating_array = json_object_new_array(); |
183 | struct sway_container *floating = workspace->sway_workspace->floating; | 182 | list_t *floating = workspace->sway_workspace->floating; |
184 | for (int i = 0; i < floating->children->length; ++i) { | 183 | for (int i = 0; i < floating->length; ++i) { |
185 | struct sway_container *floater = floating->children->items[i]; | 184 | struct sway_container *floater = floating->items[i]; |
186 | json_object_array_add(floating_array, ipc_json_describe_container_recursive(floater)); | 185 | json_object_array_add(floating_array, |
186 | ipc_json_describe_container_recursive(floater)); | ||
187 | } | 187 | } |
188 | json_object_object_add(object, "floating_nodes", floating_array); | 188 | json_object_object_add(object, "floating_nodes", floating_array); |
189 | } | 189 | } |
@@ -193,6 +193,16 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
193 | c->name ? json_object_new_string(c->name) : NULL); | 193 | c->name ? json_object_new_string(c->name) : NULL); |
194 | json_object_object_add(object, "type", json_object_new_string("con")); | 194 | json_object_object_add(object, "type", json_object_new_string("con")); |
195 | 195 | ||
196 | if (c->type == C_VIEW) { | ||
197 | const char *app_id = view_get_app_id(c->sway_view); | ||
198 | json_object_object_add(object, "app_id", | ||
199 | app_id ? json_object_new_string(app_id) : NULL); | ||
200 | |||
201 | const char *class = view_get_class(c->sway_view); | ||
202 | json_object_object_add(object, "class", | ||
203 | class ? json_object_new_string(class) : NULL); | ||
204 | } | ||
205 | |||
196 | if (c->parent) { | 206 | if (c->parent) { |
197 | json_object_object_add(object, "layout", | 207 | json_object_object_add(object, "layout", |
198 | json_object_new_string(ipc_json_layout_description(c->layout))); | 208 | json_object_new_string(ipc_json_layout_description(c->layout))); |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index dad1f310..34e940ad 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -522,7 +522,7 @@ void ipc_client_disconnect(struct ipc_client *client) { | |||
522 | 522 | ||
523 | static void ipc_get_workspaces_callback(struct sway_container *workspace, | 523 | static void ipc_get_workspaces_callback(struct sway_container *workspace, |
524 | void *data) { | 524 | void *data) { |
525 | if (workspace->type != C_WORKSPACE) { | 525 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { |
526 | return; | 526 | return; |
527 | } | 527 | } |
528 | json_object *workspace_json = ipc_json_describe_container(workspace); | 528 | json_object *workspace_json = ipc_json_describe_container(workspace); |
@@ -631,8 +631,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
631 | case IPC_GET_WORKSPACES: | 631 | case IPC_GET_WORKSPACES: |
632 | { | 632 | { |
633 | json_object *workspaces = json_object_new_array(); | 633 | json_object *workspaces = json_object_new_array(); |
634 | container_for_each_descendant(&root_container, | 634 | root_for_each_workspace(ipc_get_workspaces_callback, workspaces); |
635 | ipc_get_workspaces_callback, workspaces); | ||
636 | const char *json_string = json_object_to_json_string(workspaces); | 635 | const char *json_string = json_object_to_json_string(workspaces); |
637 | client_valid = | 636 | client_valid = |
638 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 637 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); |
@@ -729,8 +728,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
729 | case IPC_GET_MARKS: | 728 | case IPC_GET_MARKS: |
730 | { | 729 | { |
731 | json_object *marks = json_object_new_array(); | 730 | json_object *marks = json_object_new_array(); |
732 | container_descendants(&root_container, C_VIEW, ipc_get_marks_callback, | 731 | root_for_each_container(ipc_get_marks_callback, marks); |
733 | marks); | ||
734 | const char *json_string = json_object_to_json_string(marks); | 732 | const char *json_string = json_object_to_json_string(marks); |
735 | client_valid = | 733 | client_valid = |
736 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); | 734 | ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); |
diff --git a/sway/main.c b/sway/main.c index 54f48340..3ba4ba75 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -235,14 +235,20 @@ static void drop_permissions(bool keep_caps) { | |||
235 | } | 235 | } |
236 | 236 | ||
237 | void enable_debug_flag(const char *flag) { | 237 | void enable_debug_flag(const char *flag) { |
238 | if (strcmp(flag, "render-tree") == 0) { | 238 | if (strcmp(flag, "damage=highlight") == 0) { |
239 | enable_debug_tree = true; | 239 | debug.damage = DAMAGE_HIGHLIGHT; |
240 | } else if (strncmp(flag, "damage=", 7) == 0) { | 240 | } else if (strcmp(flag, "damage=rerender") == 0) { |
241 | damage_debug = &flag[7]; | 241 | debug.damage = DAMAGE_RERENDER; |
242 | } else if (strcmp(flag, "txn-debug") == 0) { | 242 | } else if (strcmp(flag, "noatomic") == 0) { |
243 | txn_debug = true; | 243 | debug.noatomic = true; |
244 | } else if (strcmp(flag, "render-tree") == 0) { | ||
245 | debug.render_tree = true; | ||
246 | } else if (strcmp(flag, "txn-wait") == 0) { | ||
247 | debug.txn_wait = true; | ||
248 | } else if (strcmp(flag, "txn-timings") == 0) { | ||
249 | debug.txn_timings = true; | ||
244 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { | 250 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { |
245 | txn_timeout_ms = atoi(&flag[12]); | 251 | server.txn_timeout_ms = atoi(&flag[12]); |
246 | } | 252 | } |
247 | } | 253 | } |
248 | 254 | ||
diff --git a/sway/meson.build b/sway/meson.build index 2a457270..676422d0 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -64,6 +64,7 @@ sway_sources = files( | |||
64 | 'commands/mouse_warping.c', | 64 | 'commands/mouse_warping.c', |
65 | 'commands/move.c', | 65 | 'commands/move.c', |
66 | 'commands/no_focus.c', | 66 | 'commands/no_focus.c', |
67 | 'commands/nop.c', | ||
67 | 'commands/output.c', | 68 | 'commands/output.c', |
68 | 'commands/reload.c', | 69 | 'commands/reload.c', |
69 | 'commands/rename.c', | 70 | 'commands/rename.c', |
diff --git a/sway/server.c b/sway/server.c index e8dc63be..00acaa01 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -128,10 +128,11 @@ bool server_init(struct sway_server *server) { | |||
128 | return false; | 128 | return false; |
129 | } | 129 | } |
130 | 130 | ||
131 | const char *debug = getenv("SWAY_DEBUG"); | 131 | // This may have been set already via -Dtxn-timeout |
132 | if (debug != NULL && strcmp(debug, "txn_timings") == 0) { | 132 | if (!server->txn_timeout_ms) { |
133 | server->debug_txn_timings = true; | 133 | server->txn_timeout_ms = 200; |
134 | } | 134 | } |
135 | |||
135 | server->dirty_containers = create_list(); | 136 | server->dirty_containers = create_list(); |
136 | server->transactions = create_list(); | 137 | server->transactions = create_list(); |
137 | 138 | ||
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 70b74a45..83188067 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -51,7 +51,7 @@ The following commands may only be used in the configuration file. | |||
51 | *wordexp*(3) for details). The same include file can only be included once; | 51 | *wordexp*(3) for details). The same include file can only be included once; |
52 | subsequent attempts will be ignored. | 52 | subsequent attempts will be ignored. |
53 | 53 | ||
54 | *set* <name> <value> | 54 | *set* $<name> <value> |
55 | Sets variable $_name_ to _value_. You can use the new variable in the | 55 | Sets variable $_name_ to _value_. You can use the new variable in the |
56 | arguments of future commands. | 56 | arguments of future commands. |
57 | 57 | ||
@@ -132,7 +132,7 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
132 | If unspecified, the default is 10 pixels. Pixels are ignored when moving | 132 | If unspecified, the default is 10 pixels. Pixels are ignored when moving |
133 | tiled containers. | 133 | tiled containers. |
134 | 134 | ||
135 | *move* [absolute] position <pos_x> [px] <pos_y> [px] | 135 | *move* [absolute] position <pos\_x> [px] <pos\_y> [px] |
136 | Moves the focused container to the specified position. | 136 | Moves the focused container to the specified position. |
137 | 137 | ||
138 | *move* [absolute] position center|mouse | 138 | *move* [absolute] position center|mouse |
@@ -154,7 +154,7 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
154 | Moves the focused container to the previous or next workspace on this | 154 | Moves the focused container to the previous or next workspace on this |
155 | output, wrapping around if already at the first or last workspace. | 155 | output, wrapping around if already at the first or last workspace. |
156 | 156 | ||
157 | *move* container|window [to] workspace back_and_forth | 157 | *move* container|window [to] workspace back\_and\_forth |
158 | Moves the focused container to previously focused workspace. | 158 | Moves the focused container to previously focused workspace. |
159 | 159 | ||
160 | *move* container|window|workspace [to] output <name> | 160 | *move* container|window|workspace [to] output <name> |
@@ -167,6 +167,10 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
167 | *move* [to] scratchpad | 167 | *move* [to] scratchpad |
168 | Moves the focused window to the scratchpad. | 168 | Moves the focused window to the scratchpad. |
169 | 169 | ||
170 | *nop* <comment> | ||
171 | A no operation command that can be used to override default behaviour. The | ||
172 | optional comment argument is ignored, but logged for debugging purposes. | ||
173 | |||
170 | *reload* | 174 | *reload* |
171 | Reloads the sway config file and applies any changes. | 175 | Reloads the sway config file and applies any changes. |
172 | 176 | ||
@@ -215,13 +219,20 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
215 | The following commands may be used either in the configuration file or at | 219 | The following commands may be used either in the configuration file or at |
216 | runtime. | 220 | runtime. |
217 | 221 | ||
218 | *assign* <criteria> [→] <workspace> | 222 | *assign* <criteria> [→] [workspace] [number] <workspace> |
219 | Assigns views matching _criteria_ (see *CRITERIA* for details) to | 223 | Assigns views matching _criteria_ (see *CRITERIA* for details) to |
220 | _workspace_. The → (U+2192) is optional and cosmetic. This command is | 224 | _workspace_. The → (U+2192) is optional and cosmetic. This command is |
221 | equivalent to: | 225 | equivalent to: |
222 | 226 | ||
223 | for\_window <criteria> move container to workspace <workspace> | 227 | for\_window <criteria> move container to workspace <workspace> |
224 | 228 | ||
229 | *assign* <criteria> [→] output left|right|up|down|<name> | ||
230 | Assigns views matching _criteria_ (see *CRITERIA* for details) to the | ||
231 | specified output. The → (U+2192) is optional and cosmetic. This command is | ||
232 | equivalent to: | ||
233 | |||
234 | for\_window <criteria> move container to output <output> | ||
235 | |||
225 | *bindsym* [--release|--locked] <key combo> <command> | 236 | *bindsym* [--release|--locked] <key combo> <command> |
226 | Binds _key combo_ to execute the sway command _command_ when pressed. You | 237 | Binds _key combo_ to execute the sway command _command_ when pressed. You |
227 | may use XKB key names here (*xev*(1) is a good tool for discovering these). | 238 | may use XKB key names here (*xev*(1) is a good tool for discovering these). |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 494a8461..a4b058f3 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -144,9 +144,9 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { | |||
144 | 144 | ||
145 | static void arrange_children_of(struct sway_container *parent); | 145 | static void arrange_children_of(struct sway_container *parent); |
146 | 146 | ||
147 | static void arrange_floating(struct sway_container *floating) { | 147 | static void arrange_floating(list_t *floating) { |
148 | for (int i = 0; i < floating->children->length; ++i) { | 148 | for (int i = 0; i < floating->length; ++i) { |
149 | struct sway_container *floater = floating->children->items[i]; | 149 | struct sway_container *floater = floating->items[i]; |
150 | if (floater->type == C_VIEW) { | 150 | if (floater->type == C_VIEW) { |
151 | view_autoconfigure(floater->sway_view); | 151 | view_autoconfigure(floater->sway_view); |
152 | } else { | 152 | } else { |
@@ -154,7 +154,6 @@ static void arrange_floating(struct sway_container *floating) { | |||
154 | } | 154 | } |
155 | container_set_dirty(floater); | 155 | container_set_dirty(floater); |
156 | } | 156 | } |
157 | container_set_dirty(floating); | ||
158 | } | 157 | } |
159 | 158 | ||
160 | static void arrange_children_of(struct sway_container *parent) { | 159 | static void arrange_children_of(struct sway_container *parent) { |
@@ -179,9 +178,6 @@ static void arrange_children_of(struct sway_container *parent) { | |||
179 | case L_NONE: | 178 | case L_NONE: |
180 | apply_horiz_layout(parent); | 179 | apply_horiz_layout(parent); |
181 | break; | 180 | break; |
182 | case L_FLOATING: | ||
183 | arrange_floating(parent); | ||
184 | break; | ||
185 | } | 181 | } |
186 | 182 | ||
187 | // Recurse into child containers | 183 | // Recurse into child containers |
@@ -210,10 +206,30 @@ static void arrange_workspace(struct sway_container *workspace) { | |||
210 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", | 206 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", |
211 | area->width, area->height, area->x, area->y); | 207 | area->width, area->height, area->x, area->y); |
212 | remove_gaps(workspace); | 208 | remove_gaps(workspace); |
209 | |||
210 | double prev_x = workspace->x; | ||
211 | double prev_y = workspace->y; | ||
213 | workspace->width = area->width; | 212 | workspace->width = area->width; |
214 | workspace->height = area->height; | 213 | workspace->height = area->height; |
215 | workspace->x = output->x + area->x; | 214 | workspace->x = output->x + area->x; |
216 | workspace->y = output->y + area->y; | 215 | workspace->y = output->y + area->y; |
216 | |||
217 | // Adjust any floating containers | ||
218 | double diff_x = workspace->x - prev_x; | ||
219 | double diff_y = workspace->y - prev_y; | ||
220 | for (int i = 0; i < workspace->sway_workspace->floating->length; ++i) { | ||
221 | struct sway_container *floater = | ||
222 | workspace->sway_workspace->floating->items[i]; | ||
223 | container_floating_translate(floater, diff_x, diff_y); | ||
224 | double center_x = floater->x + floater->width / 2; | ||
225 | double center_y = floater->y + floater->height / 2; | ||
226 | struct wlr_box workspace_box; | ||
227 | container_get_box(workspace, &workspace_box); | ||
228 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { | ||
229 | container_floating_move_to_center(floater); | ||
230 | } | ||
231 | } | ||
232 | |||
217 | add_gaps(workspace); | 233 | add_gaps(workspace); |
218 | container_set_dirty(workspace); | 234 | container_set_dirty(workspace); |
219 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, | 235 | wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, |
diff --git a/sway/tree/container.c b/sway/tree/container.c index eb06edc2..a8c6e667 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -67,32 +67,11 @@ void container_update_textures_recursive(struct sway_container *con) { | |||
67 | } | 67 | } |
68 | 68 | ||
69 | if (con->type == C_WORKSPACE) { | 69 | if (con->type == C_WORKSPACE) { |
70 | container_update_textures_recursive(con->sway_workspace->floating); | 70 | for (int i = 0; i < con->sway_workspace->floating->length; ++i) { |
71 | } | 71 | struct sway_container *floater = |
72 | } | 72 | con->sway_workspace->floating->items[i]; |
73 | } | 73 | container_update_textures_recursive(floater); |
74 | 74 | } | |
75 | static void handle_reparent(struct wl_listener *listener, | ||
76 | void *data) { | ||
77 | struct sway_container *container = | ||
78 | wl_container_of(listener, container, reparent); | ||
79 | struct sway_container *old_parent = data; | ||
80 | |||
81 | struct sway_container *old_output = old_parent; | ||
82 | if (old_output != NULL && old_output->type != C_OUTPUT) { | ||
83 | old_output = container_parent(old_output, C_OUTPUT); | ||
84 | } | ||
85 | |||
86 | struct sway_container *new_output = container->parent; | ||
87 | if (new_output != NULL && new_output->type != C_OUTPUT) { | ||
88 | new_output = container_parent(new_output, C_OUTPUT); | ||
89 | } | ||
90 | |||
91 | if (old_output && new_output) { | ||
92 | float old_scale = old_output->sway_output->wlr_output->scale; | ||
93 | float new_scale = new_output->sway_output->wlr_output->scale; | ||
94 | if (old_scale != new_scale) { | ||
95 | container_update_textures_recursive(container); | ||
96 | } | 75 | } |
97 | } | 76 | } |
98 | } | 77 | } |
@@ -113,12 +92,9 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
113 | c->children = create_list(); | 92 | c->children = create_list(); |
114 | c->current.children = create_list(); | 93 | c->current.children = create_list(); |
115 | } | 94 | } |
95 | c->outputs = create_list(); | ||
116 | 96 | ||
117 | wl_signal_init(&c->events.destroy); | 97 | wl_signal_init(&c->events.destroy); |
118 | wl_signal_init(&c->events.reparent); | ||
119 | |||
120 | wl_signal_add(&c->events.reparent, &c->reparent); | ||
121 | c->reparent.notify = handle_reparent; | ||
122 | 98 | ||
123 | c->has_gaps = false; | 99 | c->has_gaps = false; |
124 | c->gaps_inner = 0; | 100 | c->gaps_inner = 0; |
@@ -131,6 +107,7 @@ struct sway_container *container_create(enum sway_container_type type) { | |||
131 | static void container_workspace_free(struct sway_workspace *ws) { | 107 | static void container_workspace_free(struct sway_workspace *ws) { |
132 | list_foreach(ws->output_priority, free); | 108 | list_foreach(ws->output_priority, free); |
133 | list_free(ws->output_priority); | 109 | list_free(ws->output_priority); |
110 | list_free(ws->floating); | ||
134 | free(ws); | 111 | free(ws); |
135 | } | 112 | } |
136 | 113 | ||
@@ -151,6 +128,7 @@ void container_free(struct sway_container *cont) { | |||
151 | wlr_texture_destroy(cont->title_urgent); | 128 | wlr_texture_destroy(cont->title_urgent); |
152 | list_free(cont->children); | 129 | list_free(cont->children); |
153 | list_free(cont->current.children); | 130 | list_free(cont->current.children); |
131 | list_free(cont->outputs); | ||
154 | 132 | ||
155 | switch (cont->type) { | 133 | switch (cont->type) { |
156 | case C_ROOT: | 134 | case C_ROOT: |
@@ -222,18 +200,25 @@ static struct sway_container *container_workspace_destroy( | |||
222 | for (int i = 0; i < workspace->children->length; i++) { | 200 | for (int i = 0; i < workspace->children->length; i++) { |
223 | container_move_to(workspace->children->items[i], new_workspace); | 201 | container_move_to(workspace->children->items[i], new_workspace); |
224 | } | 202 | } |
225 | struct sway_container *floating = workspace->sway_workspace->floating; | 203 | list_t *floating = workspace->sway_workspace->floating; |
226 | for (int i = 0; i < floating->children->length; i++) { | 204 | for (int i = 0; i < floating->length; i++) { |
227 | container_move_to(floating->children->items[i], | 205 | struct sway_container *floater = floating->items[i]; |
228 | new_workspace->sway_workspace->floating); | 206 | container_remove_child(floater); |
207 | workspace_add_floating(new_workspace, floater); | ||
229 | } | 208 | } |
230 | } | 209 | } |
231 | 210 | ||
232 | container_destroy_noreaping(workspace->sway_workspace->floating); | ||
233 | |||
234 | return output; | 211 | return output; |
235 | } | 212 | } |
236 | 213 | ||
214 | static void untrack_output(struct sway_container *con, void *data) { | ||
215 | struct sway_output *output = data; | ||
216 | int index = list_find(con->outputs, output); | ||
217 | if (index != -1) { | ||
218 | list_del(con->outputs, index); | ||
219 | } | ||
220 | } | ||
221 | |||
237 | static struct sway_container *container_output_destroy( | 222 | static struct sway_container *container_output_destroy( |
238 | struct sway_container *output) { | 223 | struct sway_container *output) { |
239 | if (!sway_assert(output, "cannot destroy null output")) { | 224 | if (!sway_assert(output, "cannot destroy null output")) { |
@@ -270,11 +255,13 @@ static struct sway_container *container_output_destroy( | |||
270 | container_destroy(workspace); | 255 | container_destroy(workspace); |
271 | } | 256 | } |
272 | 257 | ||
273 | container_sort_workspaces(new_output); | 258 | output_sort_workspaces(new_output); |
274 | } | 259 | } |
275 | } | 260 | } |
276 | } | 261 | } |
277 | 262 | ||
263 | root_for_each_container(untrack_output, output->sway_output); | ||
264 | |||
278 | wl_list_remove(&output->sway_output->mode.link); | 265 | wl_list_remove(&output->sway_output->mode.link); |
279 | wl_list_remove(&output->sway_output->transform.link); | 266 | wl_list_remove(&output->sway_output->transform.link); |
280 | wl_list_remove(&output->sway_output->scale.link); | 267 | wl_list_remove(&output->sway_output->scale.link); |
@@ -339,10 +326,6 @@ static struct sway_container *container_destroy_noreaping( | |||
339 | } | 326 | } |
340 | 327 | ||
341 | bool container_reap_empty(struct sway_container *con) { | 328 | bool container_reap_empty(struct sway_container *con) { |
342 | if (con->layout == L_FLOATING) { | ||
343 | // Don't reap the magical floating container that each workspace has | ||
344 | return false; | ||
345 | } | ||
346 | switch (con->type) { | 329 | switch (con->type) { |
347 | case C_ROOT: | 330 | case C_ROOT: |
348 | case C_OUTPUT: | 331 | case C_OUTPUT: |
@@ -432,8 +415,10 @@ struct sway_container *container_close(struct sway_container *con) { | |||
432 | 415 | ||
433 | if (con->type == C_VIEW) { | 416 | if (con->type == C_VIEW) { |
434 | view_close(con->sway_view); | 417 | view_close(con->sway_view); |
435 | } else { | 418 | } else if (con->type == C_CONTAINER) { |
436 | container_for_each_descendant(con, container_close_func, NULL); | 419 | container_for_each_child(con, container_close_func, NULL); |
420 | } else if (con->type == C_WORKSPACE) { | ||
421 | workspace_for_each_container(con, container_close_func, NULL); | ||
437 | } | 422 | } |
438 | 423 | ||
439 | return parent; | 424 | return parent; |
@@ -465,23 +450,12 @@ struct sway_container *container_view_create(struct sway_container *sibling, | |||
465 | return swayc; | 450 | return swayc; |
466 | } | 451 | } |
467 | 452 | ||
468 | void container_descendants(struct sway_container *root, | 453 | struct sway_container *container_find_child(struct sway_container *container, |
469 | enum sway_container_type type, | ||
470 | void (*func)(struct sway_container *item, void *data), void *data) { | ||
471 | if (!root->children || !root->children->length) { | ||
472 | return; | ||
473 | } | ||
474 | for (int i = 0; i < root->children->length; ++i) { | ||
475 | struct sway_container *item = root->children->items[i]; | ||
476 | if (item->type == type) { | ||
477 | func(item, data); | ||
478 | } | ||
479 | container_descendants(item, type, func, data); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | struct sway_container *container_find(struct sway_container *container, | ||
484 | bool (*test)(struct sway_container *view, void *data), void *data) { | 454 | bool (*test)(struct sway_container *view, void *data), void *data) { |
455 | if (!sway_assert(container->type == C_CONTAINER || | ||
456 | container->type == C_VIEW, "Expected a container or view")) { | ||
457 | return NULL; | ||
458 | } | ||
485 | if (!container->children) { | 459 | if (!container->children) { |
486 | return NULL; | 460 | return NULL; |
487 | } | 461 | } |
@@ -489,15 +463,11 @@ struct sway_container *container_find(struct sway_container *container, | |||
489 | struct sway_container *child = container->children->items[i]; | 463 | struct sway_container *child = container->children->items[i]; |
490 | if (test(child, data)) { | 464 | if (test(child, data)) { |
491 | return child; | 465 | return child; |
492 | } else { | ||
493 | struct sway_container *res = container_find(child, test, data); | ||
494 | if (res) { | ||
495 | return res; | ||
496 | } | ||
497 | } | 466 | } |
498 | } | 467 | struct sway_container *res = container_find_child(child, test, data); |
499 | if (container->type == C_WORKSPACE) { | 468 | if (res) { |
500 | return container_find(container->sway_workspace->floating, test, data); | 469 | return res; |
470 | } | ||
501 | } | 471 | } |
502 | return NULL; | 472 | return NULL; |
503 | } | 473 | } |
@@ -522,8 +492,8 @@ static void surface_at_view(struct sway_container *swayc, double lx, double ly, | |||
522 | return; | 492 | return; |
523 | } | 493 | } |
524 | struct sway_view *sview = swayc->sway_view; | 494 | struct sway_view *sview = swayc->sway_view; |
525 | double view_sx = lx - sview->x; | 495 | double view_sx = lx - sview->x + sview->geometry.x; |
526 | double view_sy = ly - sview->y; | 496 | double view_sy = ly - sview->y + sview->geometry.y; |
527 | 497 | ||
528 | double _sx, _sy; | 498 | double _sx, _sy; |
529 | struct wlr_surface *_surface = NULL; | 499 | struct wlr_surface *_surface = NULL; |
@@ -639,9 +609,8 @@ static struct sway_container *floating_container_at(double lx, double ly, | |||
639 | } | 609 | } |
640 | // Items at the end of the list are on top, so iterate the list in | 610 | // Items at the end of the list are on top, so iterate the list in |
641 | // reverse. | 611 | // reverse. |
642 | for (int k = ws->floating->children->length - 1; k >= 0; --k) { | 612 | for (int k = ws->floating->length - 1; k >= 0; --k) { |
643 | struct sway_container *floater = | 613 | struct sway_container *floater = ws->floating->items[k]; |
644 | ws->floating->children->items[k]; | ||
645 | struct wlr_box box = { | 614 | struct wlr_box box = { |
646 | .x = floater->x, | 615 | .x = floater->x, |
647 | .y = floater->y, | 616 | .y = floater->y, |
@@ -677,9 +646,6 @@ struct sway_container *tiling_container_at( | |||
677 | return container_at_tabbed(con, lx, ly, surface, sx, sy); | 646 | return container_at_tabbed(con, lx, ly, surface, sx, sy); |
678 | case L_STACKED: | 647 | case L_STACKED: |
679 | return container_at_stacked(con, lx, ly, surface, sx, sy); | 648 | return container_at_stacked(con, lx, ly, surface, sx, sy); |
680 | case L_FLOATING: | ||
681 | sway_assert(false, "Didn't expect to see floating here"); | ||
682 | return NULL; | ||
683 | case L_NONE: | 649 | case L_NONE: |
684 | return NULL; | 650 | return NULL; |
685 | } | 651 | } |
@@ -743,26 +709,20 @@ struct sway_container *container_at(struct sway_container *workspace, | |||
743 | return NULL; | 709 | return NULL; |
744 | } | 710 | } |
745 | 711 | ||
746 | void container_for_each_descendant(struct sway_container *container, | 712 | void container_for_each_child(struct sway_container *container, |
747 | void (*f)(struct sway_container *container, void *data), | 713 | void (*f)(struct sway_container *container, void *data), |
748 | void *data) { | 714 | void *data) { |
749 | if (!container) { | 715 | if (!sway_assert(container->type == C_CONTAINER || |
716 | container->type == C_VIEW, "Expected a container or view")) { | ||
750 | return; | 717 | return; |
751 | } | 718 | } |
752 | if (container->children) { | 719 | if (container->children) { |
753 | for (int i = 0; i < container->children->length; ++i) { | 720 | for (int i = 0; i < container->children->length; ++i) { |
754 | struct sway_container *child = container->children->items[i]; | 721 | struct sway_container *child = container->children->items[i]; |
755 | container_for_each_descendant(child, f, data); | 722 | f(child, data); |
756 | } | 723 | container_for_each_child(child, f, data); |
757 | } | ||
758 | if (container->type == C_WORKSPACE) { | ||
759 | struct sway_container *floating = container->sway_workspace->floating; | ||
760 | for (int i = 0; i < floating->children->length; ++i) { | ||
761 | struct sway_container *child = floating->children->items[i]; | ||
762 | container_for_each_descendant(child, f, data); | ||
763 | } | 724 | } |
764 | } | 725 | } |
765 | f(container, data); | ||
766 | } | 726 | } |
767 | 727 | ||
768 | bool container_has_ancestor(struct sway_container *descendant, | 728 | bool container_has_ancestor(struct sway_container *descendant, |
@@ -800,13 +760,24 @@ void container_damage_whole(struct sway_container *container) { | |||
800 | } | 760 | } |
801 | } | 761 | } |
802 | 762 | ||
763 | /** | ||
764 | * Return the output which will be used for scale purposes. | ||
765 | * This is the most recently entered output. | ||
766 | */ | ||
767 | struct sway_output *container_get_effective_output(struct sway_container *con) { | ||
768 | if (con->outputs->length == 0) { | ||
769 | return NULL; | ||
770 | } | ||
771 | return con->outputs->items[con->outputs->length - 1]; | ||
772 | } | ||
773 | |||
803 | static void update_title_texture(struct sway_container *con, | 774 | static void update_title_texture(struct sway_container *con, |
804 | struct wlr_texture **texture, struct border_colors *class) { | 775 | struct wlr_texture **texture, struct border_colors *class) { |
805 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, | 776 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, |
806 | "Unexpected type %s", container_type_to_str(con->type))) { | 777 | "Unexpected type %s", container_type_to_str(con->type))) { |
807 | return; | 778 | return; |
808 | } | 779 | } |
809 | struct sway_container *output = container_parent(con, C_OUTPUT); | 780 | struct sway_output *output = container_get_effective_output(con); |
810 | if (!output) { | 781 | if (!output) { |
811 | return; | 782 | return; |
812 | } | 783 | } |
@@ -818,7 +789,7 @@ static void update_title_texture(struct sway_container *con, | |||
818 | return; | 789 | return; |
819 | } | 790 | } |
820 | 791 | ||
821 | double scale = output->sway_output->wlr_output->scale; | 792 | double scale = output->wlr_output->scale; |
822 | int width = 0; | 793 | int width = 0; |
823 | int height = con->title_height * scale; | 794 | int height = con->title_height * scale; |
824 | 795 | ||
@@ -846,7 +817,7 @@ static void update_title_texture(struct sway_container *con, | |||
846 | unsigned char *data = cairo_image_surface_get_data(surface); | 817 | unsigned char *data = cairo_image_surface_get_data(surface); |
847 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); | 818 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); |
848 | struct wlr_renderer *renderer = wlr_backend_get_renderer( | 819 | struct wlr_renderer *renderer = wlr_backend_get_renderer( |
849 | output->sway_output->wlr_output->backend); | 820 | output->wlr_output->backend); |
850 | *texture = wlr_texture_from_pixels( | 821 | *texture = wlr_texture_from_pixels( |
851 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); | 822 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); |
852 | cairo_surface_destroy(surface); | 823 | cairo_surface_destroy(surface); |
@@ -899,9 +870,6 @@ static size_t get_tree_representation(struct sway_container *parent, char *buffe | |||
899 | case L_STACKED: | 870 | case L_STACKED: |
900 | lenient_strcat(buffer, "S["); | 871 | lenient_strcat(buffer, "S["); |
901 | break; | 872 | break; |
902 | case L_FLOATING: | ||
903 | lenient_strcat(buffer, "F["); | ||
904 | break; | ||
905 | case L_NONE: | 873 | case L_NONE: |
906 | lenient_strcat(buffer, "D["); | 874 | lenient_strcat(buffer, "D["); |
907 | break; | 875 | break; |
@@ -1030,12 +998,13 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
1030 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | 998 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); |
1031 | 999 | ||
1032 | if (enable) { | 1000 | if (enable) { |
1033 | container_remove_child(container); | 1001 | struct sway_container *old_parent = container_remove_child(container); |
1034 | container_add_child(workspace->sway_workspace->floating, container); | 1002 | workspace_add_floating(workspace, container); |
1035 | container_init_floating(container); | 1003 | container_init_floating(container); |
1036 | if (container->type == C_VIEW) { | 1004 | if (container->type == C_VIEW) { |
1037 | view_set_tiled(container->sway_view, false); | 1005 | view_set_tiled(container->sway_view, false); |
1038 | } | 1006 | } |
1007 | container_reap_empty(old_parent); | ||
1039 | } else { | 1008 | } else { |
1040 | // Returning to tiled | 1009 | // Returning to tiled |
1041 | if (container->scratchpad) { | 1010 | if (container->scratchpad) { |
@@ -1083,14 +1052,12 @@ void container_set_geometry_from_floating_view(struct sway_container *con) { | |||
1083 | con->y = view->y - top; | 1052 | con->y = view->y - top; |
1084 | con->width = view->width + border_width * 2; | 1053 | con->width = view->width + border_width * 2; |
1085 | con->height = top + view->height + border_width; | 1054 | con->height = top + view->height + border_width; |
1055 | container_set_dirty(con); | ||
1086 | } | 1056 | } |
1087 | 1057 | ||
1088 | bool container_is_floating(struct sway_container *container) { | 1058 | bool container_is_floating(struct sway_container *container) { |
1089 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | 1059 | return container->parent && container->parent->type == C_WORKSPACE && |
1090 | if (!workspace) { | 1060 | list_find(container->parent->sway_workspace->floating, container) != -1; |
1091 | return false; | ||
1092 | } | ||
1093 | return container->parent == workspace->sway_workspace->floating; | ||
1094 | } | 1061 | } |
1095 | 1062 | ||
1096 | void container_get_box(struct sway_container *container, struct wlr_box *box) { | 1063 | void container_get_box(struct sway_container *container, struct wlr_box *box) { |
@@ -1170,7 +1137,7 @@ void container_floating_move_to(struct sway_container *con, | |||
1170 | output_get_active_workspace(new_output->sway_output); | 1137 | output_get_active_workspace(new_output->sway_output); |
1171 | if (old_workspace != new_workspace) { | 1138 | if (old_workspace != new_workspace) { |
1172 | container_remove_child(con); | 1139 | container_remove_child(con); |
1173 | container_add_child(new_workspace->sway_workspace->floating, con); | 1140 | workspace_add_floating(new_workspace, con); |
1174 | arrange_windows(old_workspace); | 1141 | arrange_windows(old_workspace); |
1175 | arrange_windows(new_workspace); | 1142 | arrange_windows(new_workspace); |
1176 | workspace_detect_urgent(old_workspace); | 1143 | workspace_detect_urgent(old_workspace); |
@@ -1197,13 +1164,12 @@ void container_set_dirty(struct sway_container *container) { | |||
1197 | list_add(server.dirty_containers, container); | 1164 | list_add(server.dirty_containers, container); |
1198 | } | 1165 | } |
1199 | 1166 | ||
1200 | static bool find_urgent_iterator(struct sway_container *con, | 1167 | static bool find_urgent_iterator(struct sway_container *con, void *data) { |
1201 | void *data) { | ||
1202 | return con->type == C_VIEW && view_is_urgent(con->sway_view); | 1168 | return con->type == C_VIEW && view_is_urgent(con->sway_view); |
1203 | } | 1169 | } |
1204 | 1170 | ||
1205 | bool container_has_urgent_child(struct sway_container *container) { | 1171 | bool container_has_urgent_child(struct sway_container *container) { |
1206 | return container_find(container, find_urgent_iterator, NULL); | 1172 | return container_find_child(container, find_urgent_iterator, NULL); |
1207 | } | 1173 | } |
1208 | 1174 | ||
1209 | void container_end_mouse_operation(struct sway_container *container) { | 1175 | void container_end_mouse_operation(struct sway_container *container) { |
@@ -1235,7 +1201,8 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { | |||
1235 | container_set_fullscreen(workspace->sway_workspace->fullscreen, false); | 1201 | container_set_fullscreen(workspace->sway_workspace->fullscreen, false); |
1236 | } | 1202 | } |
1237 | 1203 | ||
1238 | container_for_each_descendant(container, set_fullscreen_iterator, &enable); | 1204 | set_fullscreen_iterator(container, &enable); |
1205 | container_for_each_child(container, set_fullscreen_iterator, &enable); | ||
1239 | 1206 | ||
1240 | container->is_fullscreen = enable; | 1207 | container->is_fullscreen = enable; |
1241 | 1208 | ||
@@ -1284,14 +1251,10 @@ void container_set_fullscreen(struct sway_container *container, bool enable) { | |||
1284 | } | 1251 | } |
1285 | 1252 | ||
1286 | bool container_is_floating_or_child(struct sway_container *container) { | 1253 | bool container_is_floating_or_child(struct sway_container *container) { |
1287 | do { | 1254 | while (container->parent && container->parent->type != C_WORKSPACE) { |
1288 | if (container->parent && container->parent->layout == L_FLOATING) { | ||
1289 | return true; | ||
1290 | } | ||
1291 | container = container->parent; | 1255 | container = container->parent; |
1292 | } while (container && container->type != C_WORKSPACE); | 1256 | } |
1293 | 1257 | return container_is_floating(container); | |
1294 | return false; | ||
1295 | } | 1258 | } |
1296 | 1259 | ||
1297 | bool container_is_fullscreen_or_child(struct sway_container *container) { | 1260 | bool container_is_fullscreen_or_child(struct sway_container *container) { |
@@ -1305,14 +1268,66 @@ bool container_is_fullscreen_or_child(struct sway_container *container) { | |||
1305 | return false; | 1268 | return false; |
1306 | } | 1269 | } |
1307 | 1270 | ||
1308 | struct sway_container *container_wrap_children(struct sway_container *parent) { | 1271 | static void surface_send_enter_iterator(struct wlr_surface *surface, |
1309 | struct sway_container *middle = container_create(C_CONTAINER); | 1272 | int x, int y, void *data) { |
1310 | middle->layout = parent->layout; | 1273 | struct wlr_output *wlr_output = data; |
1311 | while (parent->children->length) { | 1274 | wlr_surface_send_enter(surface, wlr_output); |
1312 | struct sway_container *child = parent->children->items[0]; | 1275 | } |
1313 | container_remove_child(child); | 1276 | |
1314 | container_add_child(middle, child); | 1277 | static void surface_send_leave_iterator(struct wlr_surface *surface, |
1278 | int x, int y, void *data) { | ||
1279 | struct wlr_output *wlr_output = data; | ||
1280 | wlr_surface_send_leave(surface, wlr_output); | ||
1281 | } | ||
1282 | |||
1283 | void container_discover_outputs(struct sway_container *con) { | ||
1284 | if (!sway_assert(con->type == C_CONTAINER || con->type == C_VIEW, | ||
1285 | "Expected a container or view")) { | ||
1286 | return; | ||
1287 | } | ||
1288 | struct wlr_box con_box = { | ||
1289 | .x = con->current.swayc_x, | ||
1290 | .y = con->current.swayc_y, | ||
1291 | .width = con->current.swayc_width, | ||
1292 | .height = con->current.swayc_height, | ||
1293 | }; | ||
1294 | struct sway_output *old_output = container_get_effective_output(con); | ||
1295 | |||
1296 | for (int i = 0; i < root_container.children->length; ++i) { | ||
1297 | struct sway_container *output = root_container.children->items[i]; | ||
1298 | struct sway_output *sway_output = output->sway_output; | ||
1299 | struct wlr_box output_box; | ||
1300 | container_get_box(output, &output_box); | ||
1301 | struct wlr_box intersection; | ||
1302 | bool intersects = | ||
1303 | wlr_box_intersection(&con_box, &output_box, &intersection); | ||
1304 | int index = list_find(con->outputs, sway_output); | ||
1305 | |||
1306 | if (intersects && index == -1) { | ||
1307 | // Send enter | ||
1308 | wlr_log(WLR_DEBUG, "Con %p entered output %p", con, sway_output); | ||
1309 | if (con->type == C_VIEW) { | ||
1310 | view_for_each_surface(con->sway_view, | ||
1311 | surface_send_enter_iterator, sway_output->wlr_output); | ||
1312 | } | ||
1313 | list_add(con->outputs, sway_output); | ||
1314 | } else if (!intersects && index != -1) { | ||
1315 | // Send leave | ||
1316 | wlr_log(WLR_DEBUG, "Con %p left output %p", con, sway_output); | ||
1317 | if (con->type == C_VIEW) { | ||
1318 | view_for_each_surface(con->sway_view, | ||
1319 | surface_send_leave_iterator, sway_output->wlr_output); | ||
1320 | } | ||
1321 | list_del(con->outputs, index); | ||
1322 | } | ||
1323 | } | ||
1324 | struct sway_output *new_output = container_get_effective_output(con); | ||
1325 | double old_scale = old_output ? old_output->wlr_output->scale : -1; | ||
1326 | double new_scale = new_output ? new_output->wlr_output->scale : -1; | ||
1327 | if (old_scale != new_scale) { | ||
1328 | container_update_title_textures(con); | ||
1329 | if (con->type == C_VIEW) { | ||
1330 | view_update_marks_textures(con->sway_view); | ||
1331 | } | ||
1315 | } | 1332 | } |
1316 | container_add_child(parent, middle); | ||
1317 | return middle; | ||
1318 | } | 1333 | } |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 2b710403..a3de44ce 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <ctype.h> | ||
3 | #include <math.h> | 2 | #include <math.h> |
4 | #include <stdbool.h> | 3 | #include <stdbool.h> |
5 | #include <stdlib.h> | 4 | #include <stdlib.h> |
@@ -76,7 +75,6 @@ void container_insert_child(struct sway_container *parent, | |||
76 | list_insert(parent->children, i, child); | 75 | list_insert(parent->children, i, child); |
77 | child->parent = parent; | 76 | child->parent = parent; |
78 | container_handle_fullscreen_reparent(child, old_parent); | 77 | container_handle_fullscreen_reparent(child, old_parent); |
79 | wl_signal_emit(&child->events.reparent, old_parent); | ||
80 | } | 78 | } |
81 | 79 | ||
82 | struct sway_container *container_add_sibling(struct sway_container *fixed, | 80 | struct sway_container *container_add_sibling(struct sway_container *fixed, |
@@ -92,7 +90,6 @@ struct sway_container *container_add_sibling(struct sway_container *fixed, | |||
92 | list_insert(parent->children, i + 1, active); | 90 | list_insert(parent->children, i + 1, active); |
93 | active->parent = parent; | 91 | active->parent = parent; |
94 | container_handle_fullscreen_reparent(active, old_parent); | 92 | container_handle_fullscreen_reparent(active, old_parent); |
95 | wl_signal_emit(&active->events.reparent, old_parent); | ||
96 | return active->parent; | 93 | return active->parent; |
97 | } | 94 | } |
98 | 95 | ||
@@ -118,9 +115,11 @@ struct sway_container *container_remove_child(struct sway_container *child) { | |||
118 | } | 115 | } |
119 | 116 | ||
120 | struct sway_container *parent = child->parent; | 117 | struct sway_container *parent = child->parent; |
121 | int index = index_child(child); | 118 | list_t *list = container_is_floating(child) ? |
119 | parent->sway_workspace->floating : parent->children; | ||
120 | int index = list_find(list, child); | ||
122 | if (index != -1) { | 121 | if (index != -1) { |
123 | list_del(parent->children, index); | 122 | list_del(list, index); |
124 | } | 123 | } |
125 | child->parent = NULL; | 124 | child->parent = NULL; |
126 | container_notify_subtree_changed(parent); | 125 | container_notify_subtree_changed(parent); |
@@ -161,7 +160,8 @@ void container_move_to(struct sway_container *container, | |||
161 | struct sway_container *old_output = | 160 | struct sway_container *old_output = |
162 | container_parent(container, C_OUTPUT); | 161 | container_parent(container, C_OUTPUT); |
163 | old_parent = container_remove_child(container); | 162 | old_parent = container_remove_child(container); |
164 | container_add_child(new_ws->sway_workspace->floating, container); | 163 | workspace_add_floating(new_ws, container); |
164 | container_handle_fullscreen_reparent(container, old_parent); | ||
165 | // If changing output, center it within the workspace | 165 | // If changing output, center it within the workspace |
166 | if (old_output != new_ws->parent && !container->is_fullscreen) { | 166 | if (old_output != new_ws->parent && !container->is_fullscreen) { |
167 | container_floating_move_to_center(container); | 167 | container_floating_move_to_center(container); |
@@ -179,8 +179,6 @@ void container_move_to(struct sway_container *container, | |||
179 | } | 179 | } |
180 | } | 180 | } |
181 | 181 | ||
182 | wl_signal_emit(&container->events.reparent, old_parent); | ||
183 | |||
184 | if (container->type == C_VIEW) { | 182 | if (container->type == C_VIEW) { |
185 | ipc_event_window(container, "move"); | 183 | ipc_event_window(container, "move"); |
186 | } | 184 | } |
@@ -305,7 +303,6 @@ static void workspace_rejigger(struct sway_container *ws, | |||
305 | 303 | ||
306 | container_flatten(ws); | 304 | container_flatten(ws); |
307 | container_reap_empty_recursive(original_parent); | 305 | container_reap_empty_recursive(original_parent); |
308 | wl_signal_emit(&child->events.reparent, original_parent); | ||
309 | container_create_notify(new_parent); | 306 | container_create_notify(new_parent); |
310 | } | 307 | } |
311 | 308 | ||
@@ -432,9 +429,6 @@ void container_move(struct sway_container *container, | |||
432 | if ((index == parent->children->length - 1 && offs > 0) | 429 | if ((index == parent->children->length - 1 && offs > 0) |
433 | || (index == 0 && offs < 0)) { | 430 | || (index == 0 && offs < 0)) { |
434 | if (current->parent == container->parent) { | 431 | if (current->parent == container->parent) { |
435 | if (parent->parent->layout == L_FLOATING) { | ||
436 | return; | ||
437 | } | ||
438 | if (!parent->is_fullscreen && | 432 | if (!parent->is_fullscreen && |
439 | (parent->layout == L_TABBED || | 433 | (parent->layout == L_TABBED || |
440 | parent->layout == L_STACKED)) { | 434 | parent->layout == L_STACKED)) { |
@@ -458,14 +452,10 @@ void container_move(struct sway_container *container, | |||
458 | sibling = parent->children->items[index + offs]; | 452 | sibling = parent->children->items[index + offs]; |
459 | wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); | 453 | wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); |
460 | } | 454 | } |
461 | } else if (!parent->is_fullscreen && | 455 | } else if (!parent->is_fullscreen && (parent->layout == L_TABBED || |
462 | parent->parent->layout != L_FLOATING && | ||
463 | (parent->layout == L_TABBED || | ||
464 | parent->layout == L_STACKED)) { | 456 | parent->layout == L_STACKED)) { |
465 | move_out_of_tabs_stacks(container, current, move_dir, offs); | 457 | move_out_of_tabs_stacks(container, current, move_dir, offs); |
466 | return; | 458 | return; |
467 | } else if (parent->parent->layout == L_FLOATING) { | ||
468 | return; | ||
469 | } else { | 459 | } else { |
470 | wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); | 460 | wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); |
471 | current = current->parent; | 461 | current = current->parent; |
@@ -591,28 +581,6 @@ enum sway_container_layout container_get_default_layout( | |||
591 | } | 581 | } |
592 | } | 582 | } |
593 | 583 | ||
594 | static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | ||
595 | struct sway_container *a = *(void **)_a; | ||
596 | struct sway_container *b = *(void **)_b; | ||
597 | int retval = 0; | ||
598 | |||
599 | if (isdigit(a->name[0]) && isdigit(b->name[0])) { | ||
600 | int a_num = strtol(a->name, NULL, 10); | ||
601 | int b_num = strtol(b->name, NULL, 10); | ||
602 | retval = (a_num < b_num) ? -1 : (a_num > b_num); | ||
603 | } else if (isdigit(a->name[0])) { | ||
604 | retval = -1; | ||
605 | } else if (isdigit(b->name[0])) { | ||
606 | retval = 1; | ||
607 | } | ||
608 | |||
609 | return retval; | ||
610 | } | ||
611 | |||
612 | void container_sort_workspaces(struct sway_container *output) { | ||
613 | list_stable_sort(output->children, sort_workspace_cmp_qsort); | ||
614 | } | ||
615 | |||
616 | /** | 584 | /** |
617 | * Get swayc in the direction of newly entered output. | 585 | * Get swayc in the direction of newly entered output. |
618 | */ | 586 | */ |
@@ -825,13 +793,15 @@ struct sway_container *container_replace_child(struct sway_container *child, | |||
825 | if (parent == NULL) { | 793 | if (parent == NULL) { |
826 | return NULL; | 794 | return NULL; |
827 | } | 795 | } |
828 | int i = index_child(child); | ||
829 | 796 | ||
830 | // TODO floating | 797 | list_t *list = container_is_floating(child) ? |
798 | parent->sway_workspace->floating : parent->children; | ||
799 | int i = list_find(list, child); | ||
800 | |||
831 | if (new_child->parent) { | 801 | if (new_child->parent) { |
832 | container_remove_child(new_child); | 802 | container_remove_child(new_child); |
833 | } | 803 | } |
834 | parent->children->items[i] = new_child; | 804 | list->items[i] = new_child; |
835 | new_child->parent = parent; | 805 | new_child->parent = parent; |
836 | child->parent = NULL; | 806 | child->parent = NULL; |
837 | 807 | ||
@@ -884,7 +854,6 @@ struct sway_container *container_split(struct sway_container *child, | |||
884 | struct sway_container *ws_child = workspace->children->items[0]; | 854 | struct sway_container *ws_child = workspace->children->items[0]; |
885 | container_remove_child(ws_child); | 855 | container_remove_child(ws_child); |
886 | container_add_child(cont, ws_child); | 856 | container_add_child(cont, ws_child); |
887 | wl_signal_emit(&ws_child->events.reparent, workspace); | ||
888 | } | 857 | } |
889 | 858 | ||
890 | container_add_child(workspace, cont); | 859 | container_add_child(workspace, cont); |
@@ -892,11 +861,9 @@ struct sway_container *container_split(struct sway_container *child, | |||
892 | workspace->layout = layout; | 861 | workspace->layout = layout; |
893 | cont->layout = old_layout; | 862 | cont->layout = old_layout; |
894 | } else { | 863 | } else { |
895 | struct sway_container *old_parent = child->parent; | ||
896 | cont->layout = layout; | 864 | cont->layout = layout; |
897 | container_replace_child(child, cont); | 865 | container_replace_child(child, cont); |
898 | container_add_child(cont, child); | 866 | container_add_child(cont, child); |
899 | wl_signal_emit(&child->events.reparent, old_parent); | ||
900 | } | 867 | } |
901 | 868 | ||
902 | if (set_focus) { | 869 | if (set_focus) { |
@@ -909,13 +876,13 @@ struct sway_container *container_split(struct sway_container *child, | |||
909 | } | 876 | } |
910 | 877 | ||
911 | void container_recursive_resize(struct sway_container *container, | 878 | void container_recursive_resize(struct sway_container *container, |
912 | double amount, enum resize_edge edge) { | 879 | double amount, enum wlr_edges edge) { |
913 | bool layout_match = true; | 880 | bool layout_match = true; |
914 | wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount); | 881 | wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount); |
915 | if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { | 882 | if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) { |
916 | container->width += amount; | 883 | container->width += amount; |
917 | layout_match = container->layout == L_HORIZ; | 884 | layout_match = container->layout == L_HORIZ; |
918 | } else if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { | 885 | } else if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) { |
919 | container->height += amount; | 886 | container->height += amount; |
920 | layout_match = container->layout == L_VERT; | 887 | layout_match = container->layout == L_VERT; |
921 | } | 888 | } |
@@ -996,7 +963,8 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) { | |||
996 | "Cannot swap ancestor and descendant")) { | 963 | "Cannot swap ancestor and descendant")) { |
997 | return; | 964 | return; |
998 | } | 965 | } |
999 | if (!sway_assert(con1->layout != L_FLOATING && con2->layout != L_FLOATING, | 966 | if (!sway_assert(!container_is_floating(con1) |
967 | && !container_is_floating(con2), | ||
1000 | "Swapping with floating containers is not supported")) { | 968 | "Swapping with floating containers is not supported")) { |
1001 | return; | 969 | return; |
1002 | } | 970 | } |
diff --git a/sway/tree/output.c b/sway/tree/output.c index 31e3bf9b..6da63064 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <ctype.h> | ||
2 | #include <string.h> | 3 | #include <string.h> |
3 | #include <strings.h> | 4 | #include <strings.h> |
4 | #include "sway/ipc-server.h" | 5 | #include "sway/ipc-server.h" |
@@ -28,7 +29,7 @@ static void restore_workspaces(struct sway_container *output) { | |||
28 | } | 29 | } |
29 | } | 30 | } |
30 | 31 | ||
31 | container_sort_workspaces(output); | 32 | output_sort_workspaces(output); |
32 | } | 33 | } |
33 | 34 | ||
34 | struct sway_container *output_create( | 35 | struct sway_container *output_create( |
@@ -102,3 +103,73 @@ struct sway_container *output_create( | |||
102 | return output; | 103 | return output; |
103 | } | 104 | } |
104 | 105 | ||
106 | void output_for_each_workspace(struct sway_container *output, | ||
107 | void (*f)(struct sway_container *con, void *data), void *data) { | ||
108 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
109 | return; | ||
110 | } | ||
111 | for (int i = 0; i < output->children->length; ++i) { | ||
112 | struct sway_container *workspace = output->children->items[i]; | ||
113 | f(workspace, data); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | void output_for_each_container(struct sway_container *output, | ||
118 | void (*f)(struct sway_container *con, void *data), void *data) { | ||
119 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
120 | return; | ||
121 | } | ||
122 | for (int i = 0; i < output->children->length; ++i) { | ||
123 | struct sway_container *workspace = output->children->items[i]; | ||
124 | workspace_for_each_container(workspace, f, data); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | struct sway_container *output_find_workspace(struct sway_container *output, | ||
129 | bool (*test)(struct sway_container *con, void *data), void *data) { | ||
130 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
131 | return NULL; | ||
132 | } | ||
133 | for (int i = 0; i < output->children->length; ++i) { | ||
134 | struct sway_container *workspace = output->children->items[i]; | ||
135 | if (test(workspace, data)) { | ||
136 | return workspace; | ||
137 | } | ||
138 | } | ||
139 | return NULL; | ||
140 | } | ||
141 | |||
142 | struct sway_container *output_find_container(struct sway_container *output, | ||
143 | bool (*test)(struct sway_container *con, void *data), void *data) { | ||
144 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | ||
145 | return NULL; | ||
146 | } | ||
147 | struct sway_container *result = NULL; | ||
148 | for (int i = 0; i < output->children->length; ++i) { | ||
149 | struct sway_container *workspace = output->children->items[i]; | ||
150 | if ((result = workspace_find_container(workspace, test, data))) { | ||
151 | return result; | ||
152 | } | ||
153 | } | ||
154 | return NULL; | ||
155 | } | ||
156 | |||
157 | static int sort_workspace_cmp_qsort(const void *_a, const void *_b) { | ||
158 | struct sway_container *a = *(void **)_a; | ||
159 | struct sway_container *b = *(void **)_b; | ||
160 | |||
161 | if (isdigit(a->name[0]) && isdigit(b->name[0])) { | ||
162 | int a_num = strtol(a->name, NULL, 10); | ||
163 | int b_num = strtol(b->name, NULL, 10); | ||
164 | return (a_num < b_num) ? -1 : (a_num > b_num); | ||
165 | } else if (isdigit(a->name[0])) { | ||
166 | return -1; | ||
167 | } else if (isdigit(b->name[0])) { | ||
168 | return 1; | ||
169 | } | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | void output_sort_workspaces(struct sway_container *output) { | ||
174 | list_stable_sort(output->children, sort_workspace_cmp_qsort); | ||
175 | } | ||
diff --git a/sway/tree/root.c b/sway/tree/root.c index fc908cc1..c27ff2c3 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c | |||
@@ -105,7 +105,7 @@ void root_scratchpad_show(struct sway_container *con) { | |||
105 | if (con->parent) { | 105 | if (con->parent) { |
106 | container_remove_child(con); | 106 | container_remove_child(con); |
107 | } | 107 | } |
108 | container_add_child(ws->sway_workspace->floating, con); | 108 | workspace_add_floating(ws, con); |
109 | 109 | ||
110 | // Make sure the container's center point overlaps this workspace | 110 | // Make sure the container's center point overlaps this workspace |
111 | double center_lx = con->x + con->width / 2; | 111 | double center_lx = con->x + con->width / 2; |
@@ -256,3 +256,81 @@ void root_record_workspace_pid(pid_t pid) { | |||
256 | &pw->output_destroy); | 256 | &pw->output_destroy); |
257 | wl_list_insert(&pid_workspaces, &pw->link); | 257 | wl_list_insert(&pid_workspaces, &pw->link); |
258 | } | 258 | } |
259 | |||
260 | void root_for_each_workspace(void (*f)(struct sway_container *con, void *data), | ||
261 | void *data) { | ||
262 | for (int i = 0; i < root_container.children->length; ++i) { | ||
263 | struct sway_container *output = root_container.children->items[i]; | ||
264 | output_for_each_workspace(output, f, data); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | void root_for_each_container(void (*f)(struct sway_container *con, void *data), | ||
269 | void *data) { | ||
270 | for (int i = 0; i < root_container.children->length; ++i) { | ||
271 | struct sway_container *output = root_container.children->items[i]; | ||
272 | output_for_each_container(output, f, data); | ||
273 | } | ||
274 | |||
275 | // Scratchpad | ||
276 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | ||
277 | struct sway_container *container = | ||
278 | root_container.sway_root->scratchpad->items[i]; | ||
279 | // If the container has a parent then it's visible on a workspace | ||
280 | // and will have been iterated in the previous for loop. So we only | ||
281 | // iterate the hidden scratchpad containers here. | ||
282 | if (!container->parent) { | ||
283 | f(container, data); | ||
284 | container_for_each_child(container, f, data); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | struct sway_container *root_find_output( | ||
290 | bool (*test)(struct sway_container *con, void *data), void *data) { | ||
291 | for (int i = 0; i < root_container.children->length; ++i) { | ||
292 | struct sway_container *output = root_container.children->items[i]; | ||
293 | if (test(output, data)) { | ||
294 | return output; | ||
295 | } | ||
296 | } | ||
297 | return NULL; | ||
298 | } | ||
299 | |||
300 | struct sway_container *root_find_workspace( | ||
301 | bool (*test)(struct sway_container *con, void *data), void *data) { | ||
302 | struct sway_container *result = NULL; | ||
303 | for (int i = 0; i < root_container.children->length; ++i) { | ||
304 | struct sway_container *output = root_container.children->items[i]; | ||
305 | if ((result = output_find_workspace(output, test, data))) { | ||
306 | return result; | ||
307 | } | ||
308 | } | ||
309 | return NULL; | ||
310 | } | ||
311 | |||
312 | struct sway_container *root_find_container( | ||
313 | bool (*test)(struct sway_container *con, void *data), void *data) { | ||
314 | struct sway_container *result = NULL; | ||
315 | for (int i = 0; i < root_container.children->length; ++i) { | ||
316 | struct sway_container *output = root_container.children->items[i]; | ||
317 | if ((result = output_find_container(output, test, data))) { | ||
318 | return result; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | // Scratchpad | ||
323 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | ||
324 | struct sway_container *container = | ||
325 | root_container.sway_root->scratchpad->items[i]; | ||
326 | if (!container->parent) { | ||
327 | if (test(container, data)) { | ||
328 | return container; | ||
329 | } | ||
330 | if ((result = container_find_child(container, test, data))) { | ||
331 | return result; | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | return NULL; | ||
336 | } | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index 950494d8..7bf7325a 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -236,7 +236,12 @@ void view_autoconfigure(struct sway_view *view) { | |||
236 | view->border_top = false; | 236 | view->border_top = false; |
237 | } | 237 | } |
238 | 238 | ||
239 | switch (view->border) { | 239 | enum sway_container_border border = view->border; |
240 | if (view->using_csd) { | ||
241 | border = B_NONE; | ||
242 | } | ||
243 | |||
244 | switch (border) { | ||
240 | case B_NONE: | 245 | case B_NONE: |
241 | x = con->x; | 246 | x = con->x; |
242 | y = con->y + y_offset; | 247 | y = con->y + y_offset; |
@@ -364,48 +369,6 @@ static void view_handle_surface_new_subsurface(struct wl_listener *listener, | |||
364 | view_subsurface_create(view, subsurface); | 369 | view_subsurface_create(view, subsurface); |
365 | } | 370 | } |
366 | 371 | ||
367 | static void surface_send_enter_iterator(struct wlr_surface *surface, | ||
368 | int x, int y, void *data) { | ||
369 | struct wlr_output *wlr_output = data; | ||
370 | wlr_surface_send_enter(surface, wlr_output); | ||
371 | } | ||
372 | |||
373 | static void surface_send_leave_iterator(struct wlr_surface *surface, | ||
374 | int x, int y, void *data) { | ||
375 | struct wlr_output *wlr_output = data; | ||
376 | wlr_surface_send_leave(surface, wlr_output); | ||
377 | } | ||
378 | |||
379 | static void view_handle_container_reparent(struct wl_listener *listener, | ||
380 | void *data) { | ||
381 | struct sway_view *view = | ||
382 | wl_container_of(listener, view, container_reparent); | ||
383 | struct sway_container *old_parent = data; | ||
384 | |||
385 | struct sway_container *old_output = old_parent; | ||
386 | if (old_output != NULL && old_output->type != C_OUTPUT) { | ||
387 | old_output = container_parent(old_output, C_OUTPUT); | ||
388 | } | ||
389 | |||
390 | struct sway_container *new_output = view->swayc->parent; | ||
391 | if (new_output != NULL && new_output->type != C_OUTPUT) { | ||
392 | new_output = container_parent(new_output, C_OUTPUT); | ||
393 | } | ||
394 | |||
395 | if (old_output == new_output) { | ||
396 | return; | ||
397 | } | ||
398 | |||
399 | if (old_output != NULL) { | ||
400 | view_for_each_surface(view, surface_send_leave_iterator, | ||
401 | old_output->sway_output->wlr_output); | ||
402 | } | ||
403 | if (new_output != NULL) { | ||
404 | view_for_each_surface(view, surface_send_enter_iterator, | ||
405 | new_output->sway_output->wlr_output); | ||
406 | } | ||
407 | } | ||
408 | |||
409 | static bool view_has_executed_criteria(struct sway_view *view, | 372 | static bool view_has_executed_criteria(struct sway_view *view, |
410 | struct criteria *criteria) { | 373 | struct criteria *criteria) { |
411 | for (int i = 0; i < view->executed_criteria->length; ++i) { | 374 | for (int i = 0; i < view->executed_criteria->length; ++i) { |
@@ -450,12 +413,22 @@ static struct sway_container *select_workspace(struct sway_view *view) { | |||
450 | 413 | ||
451 | // Check if there's any `assign` criteria for the view | 414 | // Check if there's any `assign` criteria for the view |
452 | list_t *criterias = criteria_for_view(view, | 415 | list_t *criterias = criteria_for_view(view, |
453 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_OUTPUT); | 416 | CT_ASSIGN_WORKSPACE | CT_ASSIGN_WORKSPACE_NUMBER | CT_ASSIGN_OUTPUT); |
454 | struct sway_container *ws = NULL; | 417 | struct sway_container *ws = NULL; |
455 | for (int i = 0; i < criterias->length; ++i) { | 418 | for (int i = 0; i < criterias->length; ++i) { |
456 | struct criteria *criteria = criterias->items[i]; | 419 | struct criteria *criteria = criterias->items[i]; |
457 | if (criteria->type == CT_ASSIGN_WORKSPACE) { | 420 | if (criteria->type == CT_ASSIGN_OUTPUT) { |
458 | ws = workspace_by_name(criteria->target); | 421 | struct sway_container *output = output_by_name(criteria->target); |
422 | if (output) { | ||
423 | ws = seat_get_active_child(seat, output); | ||
424 | break; | ||
425 | } | ||
426 | } else { | ||
427 | // CT_ASSIGN_WORKSPACE(_NUMBER) | ||
428 | ws = criteria->type == CT_ASSIGN_WORKSPACE_NUMBER ? | ||
429 | workspace_by_number(criteria->target) : | ||
430 | workspace_by_name(criteria->target); | ||
431 | |||
459 | if (!ws) { | 432 | if (!ws) { |
460 | if (strcasecmp(criteria->target, "back_and_forth") == 0) { | 433 | if (strcasecmp(criteria->target, "back_and_forth") == 0) { |
461 | if (prev_workspace_name) { | 434 | if (prev_workspace_name) { |
@@ -466,13 +439,6 @@ static struct sway_container *select_workspace(struct sway_view *view) { | |||
466 | } | 439 | } |
467 | } | 440 | } |
468 | break; | 441 | break; |
469 | } else { | ||
470 | // CT_ASSIGN_OUTPUT | ||
471 | struct sway_container *output = output_by_name(criteria->target); | ||
472 | if (output) { | ||
473 | ws = seat_get_active_child(seat, output); | ||
474 | break; | ||
475 | } | ||
476 | } | 442 | } |
477 | } | 443 | } |
478 | list_free(criterias); | 444 | list_free(criterias); |
@@ -528,7 +494,7 @@ static bool should_focus(struct sway_view *view) { | |||
528 | struct sway_container *parent = view->swayc->parent; | 494 | struct sway_container *parent = view->swayc->parent; |
529 | if (parent->type == C_WORKSPACE && prev_focus == parent) { | 495 | if (parent->type == C_WORKSPACE && prev_focus == parent) { |
530 | size_t num_children = parent->children->length + | 496 | size_t num_children = parent->children->length + |
531 | parent->sway_workspace->floating->children->length; | 497 | parent->sway_workspace->floating->length; |
532 | if (num_children == 1) { | 498 | if (num_children == 1) { |
533 | return true; | 499 | return true; |
534 | } | 500 | } |
@@ -554,7 +520,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
554 | // If we're about to launch the view into the floating container, then | 520 | // If we're about to launch the view into the floating container, then |
555 | // launch it as a tiled view in the root of the workspace instead. | 521 | // launch it as a tiled view in the root of the workspace instead. |
556 | if (container_is_floating(target_sibling)) { | 522 | if (container_is_floating(target_sibling)) { |
557 | target_sibling = target_sibling->parent->parent; | 523 | target_sibling = target_sibling->parent; |
558 | } | 524 | } |
559 | 525 | ||
560 | view->swayc = container_view_create(target_sibling, view); | 526 | view->swayc = container_view_create(target_sibling, view); |
@@ -564,9 +530,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
564 | &view->surface_new_subsurface); | 530 | &view->surface_new_subsurface); |
565 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; | 531 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; |
566 | 532 | ||
567 | wl_signal_add(&view->swayc->events.reparent, &view->container_reparent); | ||
568 | view->container_reparent.notify = view_handle_container_reparent; | ||
569 | |||
570 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { | 533 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { |
571 | view->border = config->floating_border; | 534 | view->border = config->floating_border; |
572 | view->border_thickness = config->floating_border_thickness; | 535 | view->border_thickness = config->floating_border_thickness; |
@@ -584,15 +547,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
584 | view_update_title(view, false); | 547 | view_update_title(view, false); |
585 | container_notify_subtree_changed(view->swayc->parent); | 548 | container_notify_subtree_changed(view->swayc->parent); |
586 | view_execute_criteria(view); | 549 | view_execute_criteria(view); |
587 | |||
588 | view_handle_container_reparent(&view->container_reparent, NULL); | ||
589 | } | 550 | } |
590 | 551 | ||
591 | void view_unmap(struct sway_view *view) { | 552 | void view_unmap(struct sway_view *view) { |
592 | wl_signal_emit(&view->events.unmap, view); | 553 | wl_signal_emit(&view->events.unmap, view); |
593 | 554 | ||
594 | wl_list_remove(&view->surface_new_subsurface.link); | 555 | wl_list_remove(&view->surface_new_subsurface.link); |
595 | wl_list_remove(&view->container_reparent.link); | ||
596 | 556 | ||
597 | if (view->urgent_timer) { | 557 | if (view->urgent_timer) { |
598 | wl_event_source_remove(view->urgent_timer); | 558 | wl_event_source_remove(view->urgent_timer); |
@@ -615,34 +575,16 @@ void view_unmap(struct sway_view *view) { | |||
615 | view->surface = NULL; | 575 | view->surface = NULL; |
616 | } | 576 | } |
617 | 577 | ||
618 | void view_update_position(struct sway_view *view, double lx, double ly) { | ||
619 | if (view->x == lx && view->y == ly) { | ||
620 | return; | ||
621 | } | ||
622 | container_damage_whole(view->swayc); | ||
623 | view->x = lx; | ||
624 | view->y = ly; | ||
625 | view->swayc->current.view_x = lx; | ||
626 | view->swayc->current.view_y = ly; | ||
627 | if (container_is_floating(view->swayc)) { | ||
628 | container_set_geometry_from_floating_view(view->swayc); | ||
629 | } | ||
630 | container_damage_whole(view->swayc); | ||
631 | } | ||
632 | |||
633 | void view_update_size(struct sway_view *view, int width, int height) { | 578 | void view_update_size(struct sway_view *view, int width, int height) { |
634 | if (view->width == width && view->height == height) { | 579 | if (!sway_assert(container_is_floating(view->swayc), |
580 | "Expected a floating container")) { | ||
635 | return; | 581 | return; |
636 | } | 582 | } |
637 | container_damage_whole(view->swayc); | ||
638 | view->width = width; | 583 | view->width = width; |
639 | view->height = height; | 584 | view->height = height; |
640 | view->swayc->current.view_width = width; | 585 | view->swayc->current.view_width = width; |
641 | view->swayc->current.view_height = height; | 586 | view->swayc->current.view_height = height; |
642 | if (container_is_floating(view->swayc)) { | 587 | container_set_geometry_from_floating_view(view->swayc); |
643 | container_set_geometry_from_floating_view(view->swayc); | ||
644 | } | ||
645 | container_damage_whole(view->swayc); | ||
646 | } | 588 | } |
647 | 589 | ||
648 | static void view_subsurface_create(struct sway_view *view, | 590 | static void view_subsurface_create(struct sway_view *view, |
@@ -899,8 +841,8 @@ static bool find_by_mark_iterator(struct sway_container *con, | |||
899 | } | 841 | } |
900 | 842 | ||
901 | struct sway_view *view_find_mark(char *mark) { | 843 | struct sway_view *view_find_mark(char *mark) { |
902 | struct sway_container *container = container_find(&root_container, | 844 | struct sway_container *container = root_find_container( |
903 | find_by_mark_iterator, mark); | 845 | find_by_mark_iterator, mark); |
904 | if (!container) { | 846 | if (!container) { |
905 | return NULL; | 847 | return NULL; |
906 | } | 848 | } |
@@ -908,7 +850,7 @@ struct sway_view *view_find_mark(char *mark) { | |||
908 | } | 850 | } |
909 | 851 | ||
910 | bool view_find_and_unmark(char *mark) { | 852 | bool view_find_and_unmark(char *mark) { |
911 | struct sway_container *container = container_find(&root_container, | 853 | struct sway_container *container = root_find_container( |
912 | find_by_mark_iterator, mark); | 854 | find_by_mark_iterator, mark); |
913 | if (!container) { | 855 | if (!container) { |
914 | return false; | 856 | return false; |
@@ -952,7 +894,7 @@ void view_add_mark(struct sway_view *view, char *mark) { | |||
952 | 894 | ||
953 | static void update_marks_texture(struct sway_view *view, | 895 | static void update_marks_texture(struct sway_view *view, |
954 | struct wlr_texture **texture, struct border_colors *class) { | 896 | struct wlr_texture **texture, struct border_colors *class) { |
955 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); | 897 | struct sway_output *output = container_get_effective_output(view->swayc); |
956 | if (!output) { | 898 | if (!output) { |
957 | return; | 899 | return; |
958 | } | 900 | } |
@@ -988,7 +930,7 @@ static void update_marks_texture(struct sway_view *view, | |||
988 | } | 930 | } |
989 | free(part); | 931 | free(part); |
990 | 932 | ||
991 | double scale = output->sway_output->wlr_output->scale; | 933 | double scale = output->wlr_output->scale; |
992 | int width = 0; | 934 | int width = 0; |
993 | int height = view->swayc->title_height * scale; | 935 | int height = view->swayc->title_height * scale; |
994 | 936 | ||
@@ -1014,7 +956,7 @@ static void update_marks_texture(struct sway_view *view, | |||
1014 | unsigned char *data = cairo_image_surface_get_data(surface); | 956 | unsigned char *data = cairo_image_surface_get_data(surface); |
1015 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); | 957 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); |
1016 | struct wlr_renderer *renderer = wlr_backend_get_renderer( | 958 | struct wlr_renderer *renderer = wlr_backend_get_renderer( |
1017 | output->sway_output->wlr_output->backend); | 959 | output->wlr_output->backend); |
1018 | *texture = wlr_texture_from_pixels( | 960 | *texture = wlr_texture_from_pixels( |
1019 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); | 961 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); |
1020 | cairo_surface_destroy(surface); | 962 | cairo_surface_destroy(surface); |
@@ -1061,7 +1003,7 @@ bool view_is_visible(struct sway_view *view) { | |||
1061 | // Check view isn't in a tabbed or stacked container on an inactive tab | 1003 | // Check view isn't in a tabbed or stacked container on an inactive tab |
1062 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 1004 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
1063 | struct sway_container *container = view->swayc; | 1005 | struct sway_container *container = view->swayc; |
1064 | while (container->type != C_WORKSPACE && container->layout != L_FLOATING) { | 1006 | while (container->type != C_WORKSPACE) { |
1065 | if (container->parent->layout == L_TABBED || | 1007 | if (container->parent->layout == L_TABBED || |
1066 | container->parent->layout == L_STACKED) { | 1008 | container->parent->layout == L_STACKED) { |
1067 | if (seat_get_active_child(seat, container->parent) != container) { | 1009 | if (seat_get_active_child(seat, container->parent) != container) { |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index cd2a7a04..cf50ee09 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -67,26 +67,19 @@ struct sway_container *workspace_create(struct sway_container *output, | |||
67 | return NULL; | 67 | return NULL; |
68 | } | 68 | } |
69 | swayws->swayc = workspace; | 69 | swayws->swayc = workspace; |
70 | swayws->floating = container_create(C_CONTAINER); | 70 | swayws->floating = create_list(); |
71 | swayws->floating->parent = swayws->swayc; | ||
72 | swayws->floating->layout = L_FLOATING; | ||
73 | swayws->output_priority = create_list(); | 71 | swayws->output_priority = create_list(); |
74 | workspace->sway_workspace = swayws; | 72 | workspace->sway_workspace = swayws; |
75 | workspace_output_add_priority(workspace, output); | 73 | workspace_output_add_priority(workspace, output); |
76 | 74 | ||
77 | container_add_child(output, workspace); | 75 | container_add_child(output, workspace); |
78 | container_sort_workspaces(output); | 76 | output_sort_workspaces(output); |
79 | container_create_notify(workspace); | 77 | container_create_notify(workspace); |
80 | 78 | ||
81 | return workspace; | 79 | return workspace; |
82 | } | 80 | } |
83 | 81 | ||
84 | char *prev_workspace_name = NULL; | 82 | char *prev_workspace_name = NULL; |
85 | struct workspace_by_number_data { | ||
86 | int len; | ||
87 | const char *cset; | ||
88 | const char *name; | ||
89 | }; | ||
90 | 83 | ||
91 | void next_name_map(struct sway_container *ws, void *data) { | 84 | void next_name_map(struct sway_container *ws, void *data) { |
92 | int *count = data; | 85 | int *count = data; |
@@ -154,7 +147,7 @@ static void workspace_name_from_binding(const struct sway_binding * binding, | |||
154 | wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); | 147 | wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); |
155 | 148 | ||
156 | // Make sure the workspace number doesn't already exist | 149 | // Make sure the workspace number doesn't already exist |
157 | if (workspace_by_number(_target)) { | 150 | if (isdigit(_target[0]) && workspace_by_number(_target)) { |
158 | free(_target); | 151 | free(_target); |
159 | free(dup); | 152 | free(dup); |
160 | return; | 153 | return; |
@@ -212,6 +205,7 @@ char *workspace_next_name(const char *output_name) { | |||
212 | && workspace_by_name(wso->workspace) == NULL) { | 205 | && workspace_by_name(wso->workspace) == NULL) { |
213 | free(target); | 206 | free(target); |
214 | target = strdup(wso->workspace); | 207 | target = strdup(wso->workspace); |
208 | break; | ||
215 | } | 209 | } |
216 | } | 210 | } |
217 | if (target != NULL) { | 211 | if (target != NULL) { |
@@ -233,19 +227,18 @@ static bool _workspace_by_number(struct sway_container *view, void *data) { | |||
233 | if (view->type != C_WORKSPACE) { | 227 | if (view->type != C_WORKSPACE) { |
234 | return false; | 228 | return false; |
235 | } | 229 | } |
236 | struct workspace_by_number_data *wbnd = data; | 230 | char *name = data; |
237 | int a = strspn(view->name, wbnd->cset); | 231 | char *view_name = view->name; |
238 | return a == wbnd->len && strncmp(view->name, wbnd->name, a) == 0; | 232 | while (isdigit(*name)) { |
233 | if (*name++ != *view_name++) { | ||
234 | return false; | ||
235 | } | ||
236 | } | ||
237 | return !isdigit(*view_name); | ||
239 | } | 238 | } |
240 | 239 | ||
241 | struct sway_container *workspace_by_number(const char* name) { | 240 | struct sway_container *workspace_by_number(const char* name) { |
242 | struct workspace_by_number_data wbnd = {0, "1234567890", name}; | 241 | return root_find_workspace(_workspace_by_number, (void *) name); |
243 | wbnd.len = strspn(name, wbnd.cset); | ||
244 | if (wbnd.len <= 0) { | ||
245 | return NULL; | ||
246 | } | ||
247 | return container_find(&root_container, | ||
248 | _workspace_by_number, (void *) &wbnd); | ||
249 | } | 242 | } |
250 | 243 | ||
251 | static bool _workspace_by_name(struct sway_container *view, void *data) { | 244 | static bool _workspace_by_name(struct sway_container *view, void *data) { |
@@ -258,7 +251,8 @@ struct sway_container *workspace_by_name(const char *name) { | |||
258 | struct sway_container *current_workspace = NULL, *current_output = NULL; | 251 | struct sway_container *current_workspace = NULL, *current_output = NULL; |
259 | struct sway_container *focus = seat_get_focus(seat); | 252 | struct sway_container *focus = seat_get_focus(seat); |
260 | if (focus) { | 253 | if (focus) { |
261 | current_workspace = container_parent(focus, C_WORKSPACE); | 254 | current_workspace = focus->type == C_WORKSPACE ? |
255 | focus : container_parent(focus, C_WORKSPACE); | ||
262 | current_output = container_parent(focus, C_OUTPUT); | 256 | current_output = container_parent(focus, C_OUTPUT); |
263 | } | 257 | } |
264 | 258 | ||
@@ -273,11 +267,11 @@ struct sway_container *workspace_by_name(const char *name) { | |||
273 | } else if (strcmp(name, "current") == 0) { | 267 | } else if (strcmp(name, "current") == 0) { |
274 | return current_workspace; | 268 | return current_workspace; |
275 | } else if (strcasecmp(name, "back_and_forth") == 0) { | 269 | } else if (strcasecmp(name, "back_and_forth") == 0) { |
276 | return prev_workspace_name ? container_find(&root_container, | 270 | return prev_workspace_name ? |
277 | _workspace_by_name, (void *)prev_workspace_name) : NULL; | 271 | root_find_workspace(_workspace_by_name, (void*)prev_workspace_name) |
272 | : NULL; | ||
278 | } else { | 273 | } else { |
279 | return container_find(&root_container, _workspace_by_name, | 274 | return root_find_workspace(_workspace_by_name, (void*)name); |
280 | (void *)name); | ||
281 | } | 275 | } |
282 | } | 276 | } |
283 | 277 | ||
@@ -397,17 +391,15 @@ bool workspace_switch(struct sway_container *workspace, | |||
397 | struct sway_container *next_output = workspace->parent; | 391 | struct sway_container *next_output = workspace->parent; |
398 | struct sway_container *next_output_prev_ws = | 392 | struct sway_container *next_output_prev_ws = |
399 | seat_get_active_child(seat, next_output); | 393 | seat_get_active_child(seat, next_output); |
400 | struct sway_container *floating = | 394 | list_t *floating = next_output_prev_ws->sway_workspace->floating; |
401 | next_output_prev_ws->sway_workspace->floating; | ||
402 | bool has_sticky = false; | 395 | bool has_sticky = false; |
403 | if (workspace != next_output_prev_ws) { | 396 | if (workspace != next_output_prev_ws) { |
404 | for (int i = 0; i < floating->children->length; ++i) { | 397 | for (int i = 0; i < floating->length; ++i) { |
405 | struct sway_container *floater = floating->children->items[i]; | 398 | struct sway_container *floater = floating->items[i]; |
406 | if (floater->is_sticky) { | 399 | if (floater->is_sticky) { |
407 | has_sticky = true; | 400 | has_sticky = true; |
408 | container_remove_child(floater); | 401 | container_remove_child(floater); |
409 | container_add_child(workspace->sway_workspace->floating, | 402 | workspace_add_floating(workspace, floater); |
410 | floater); | ||
411 | if (floater == focus) { | 403 | if (floater == focus) { |
412 | seat_set_focus(seat, NULL); | 404 | seat_set_focus(seat, NULL); |
413 | seat_set_focus(seat, floater); | 405 | seat_set_focus(seat, floater); |
@@ -460,9 +452,9 @@ bool workspace_is_empty(struct sway_container *ws) { | |||
460 | return false; | 452 | return false; |
461 | } | 453 | } |
462 | // Sticky views are not considered to be part of this workspace | 454 | // Sticky views are not considered to be part of this workspace |
463 | struct sway_container *floating = ws->sway_workspace->floating; | 455 | list_t *floating = ws->sway_workspace->floating; |
464 | for (int i = 0; i < floating->children->length; ++i) { | 456 | for (int i = 0; i < floating->length; ++i) { |
465 | struct sway_container *floater = floating->children->items[i]; | 457 | struct sway_container *floater = floating->items[i]; |
466 | if (!floater->is_sticky) { | 458 | if (!floater->is_sticky) { |
467 | return false; | 459 | return false; |
468 | } | 460 | } |
@@ -517,8 +509,7 @@ struct sway_container *workspace_output_get_highest_available( | |||
517 | continue; | 509 | continue; |
518 | } | 510 | } |
519 | 511 | ||
520 | struct sway_container *output = container_find(&root_container, | 512 | struct sway_container *output = root_find_output(_output_by_name, name); |
521 | _output_by_name, name); | ||
522 | if (output) { | 513 | if (output) { |
523 | return output; | 514 | return output; |
524 | } | 515 | } |
@@ -527,8 +518,13 @@ struct sway_container *workspace_output_get_highest_available( | |||
527 | return NULL; | 518 | return NULL; |
528 | } | 519 | } |
529 | 520 | ||
521 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | ||
522 | return con->type == C_VIEW && view_is_urgent(con->sway_view); | ||
523 | } | ||
524 | |||
530 | void workspace_detect_urgent(struct sway_container *workspace) { | 525 | void workspace_detect_urgent(struct sway_container *workspace) { |
531 | bool new_urgent = container_has_urgent_child(workspace); | 526 | bool new_urgent = (bool)workspace_find_container(workspace, |
527 | find_urgent_iterator, NULL); | ||
532 | 528 | ||
533 | if (workspace->sway_workspace->urgent != new_urgent) { | 529 | if (workspace->sway_workspace->urgent != new_urgent) { |
534 | workspace->sway_workspace->urgent = new_urgent; | 530 | workspace->sway_workspace->urgent = new_urgent; |
@@ -536,3 +532,79 @@ void workspace_detect_urgent(struct sway_container *workspace) { | |||
536 | container_damage_whole(workspace); | 532 | container_damage_whole(workspace); |
537 | } | 533 | } |
538 | } | 534 | } |
535 | |||
536 | void workspace_for_each_container(struct sway_container *ws, | ||
537 | void (*f)(struct sway_container *con, void *data), void *data) { | ||
538 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
539 | return; | ||
540 | } | ||
541 | // Tiling | ||
542 | for (int i = 0; i < ws->children->length; ++i) { | ||
543 | struct sway_container *container = ws->children->items[i]; | ||
544 | f(container, data); | ||
545 | container_for_each_child(container, f, data); | ||
546 | } | ||
547 | // Floating | ||
548 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | ||
549 | struct sway_container *container = | ||
550 | ws->sway_workspace->floating->items[i]; | ||
551 | f(container, data); | ||
552 | container_for_each_child(container, f, data); | ||
553 | } | ||
554 | } | ||
555 | |||
556 | struct sway_container *workspace_find_container(struct sway_container *ws, | ||
557 | bool (*test)(struct sway_container *con, void *data), void *data) { | ||
558 | if (!sway_assert(ws->type == C_WORKSPACE, "Expected a workspace")) { | ||
559 | return NULL; | ||
560 | } | ||
561 | struct sway_container *result = NULL; | ||
562 | // Tiling | ||
563 | for (int i = 0; i < ws->children->length; ++i) { | ||
564 | struct sway_container *child = ws->children->items[i]; | ||
565 | if (test(child, data)) { | ||
566 | return child; | ||
567 | } | ||
568 | if ((result = container_find_child(child, test, data))) { | ||
569 | return result; | ||
570 | } | ||
571 | } | ||
572 | // Floating | ||
573 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | ||
574 | struct sway_container *child = ws->sway_workspace->floating->items[i]; | ||
575 | if (test(child, data)) { | ||
576 | return child; | ||
577 | } | ||
578 | if ((result = container_find_child(child, test, data))) { | ||
579 | return result; | ||
580 | } | ||
581 | } | ||
582 | return NULL; | ||
583 | } | ||
584 | |||
585 | struct sway_container *workspace_wrap_children(struct sway_container *ws) { | ||
586 | struct sway_container *middle = container_create(C_CONTAINER); | ||
587 | middle->layout = ws->layout; | ||
588 | while (ws->children->length) { | ||
589 | struct sway_container *child = ws->children->items[0]; | ||
590 | container_remove_child(child); | ||
591 | container_add_child(middle, child); | ||
592 | } | ||
593 | container_add_child(ws, middle); | ||
594 | return middle; | ||
595 | } | ||
596 | |||
597 | void workspace_add_floating(struct sway_container *workspace, | ||
598 | struct sway_container *con) { | ||
599 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | ||
600 | return; | ||
601 | } | ||
602 | if (!sway_assert(con->parent == NULL, "Expected an orphan container")) { | ||
603 | return; | ||
604 | } | ||
605 | |||
606 | list_add(workspace->sway_workspace->floating, con); | ||
607 | con->parent = workspace; | ||
608 | container_set_dirty(workspace); | ||
609 | container_set_dirty(con); | ||
610 | } | ||
diff --git a/swaynag/config.c b/swaynag/config.c index d6c5739d..4d0824c9 100644 --- a/swaynag/config.c +++ b/swaynag/config.c | |||
@@ -180,8 +180,8 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
180 | break; | 180 | break; |
181 | case 'L': // Detailed Button Text | 181 | case 'L': // Detailed Button Text |
182 | if (swaynag) { | 182 | if (swaynag) { |
183 | free(swaynag->details.button_details.text); | 183 | free(swaynag->details.button_details->text); |
184 | swaynag->details.button_details.text = strdup(optarg); | 184 | swaynag->details.button_details->text = strdup(optarg); |
185 | } | 185 | } |
186 | break; | 186 | break; |
187 | case 'm': // Message | 187 | case 'm': // Message |
diff --git a/swaynag/main.c b/swaynag/main.c index 6b0b5236..d1a0d236 100644 --- a/swaynag/main.c +++ b/swaynag/main.c | |||
@@ -34,9 +34,10 @@ int main(int argc, char **argv) { | |||
34 | button_close->type = SWAYNAG_ACTION_DISMISS; | 34 | button_close->type = SWAYNAG_ACTION_DISMISS; |
35 | list_add(swaynag.buttons, button_close); | 35 | list_add(swaynag.buttons, button_close); |
36 | 36 | ||
37 | swaynag.details.button_details.text = strdup("Toggle Details"); | 37 | swaynag.details.button_details = |
38 | swaynag.details.button_details.type = SWAYNAG_ACTION_EXPAND; | 38 | calloc(sizeof(struct swaynag_button), 1); |
39 | 39 | swaynag.details.button_details->text = strdup("Toggle Details"); | |
40 | swaynag.details.button_details->type = SWAYNAG_ACTION_EXPAND; | ||
40 | 41 | ||
41 | char *config_path = NULL; | 42 | char *config_path = NULL; |
42 | bool debug = false; | 43 | bool debug = false; |
@@ -99,9 +100,10 @@ int main(int argc, char **argv) { | |||
99 | swaynag_types_free(types); | 100 | swaynag_types_free(types); |
100 | 101 | ||
101 | if (swaynag.details.message) { | 102 | if (swaynag.details.message) { |
102 | list_add(swaynag.buttons, &swaynag.details.button_details); | 103 | list_add(swaynag.buttons, swaynag.details.button_details); |
103 | } else { | 104 | } else { |
104 | free(swaynag.details.button_details.text); | 105 | free(swaynag.details.button_details->text); |
106 | free(swaynag.details.button_details); | ||
105 | } | 107 | } |
106 | 108 | ||
107 | wlr_log(WLR_DEBUG, "Output: %s", swaynag.type->output); | 109 | wlr_log(WLR_DEBUG, "Output: %s", swaynag.type->output); |
@@ -123,7 +125,8 @@ int main(int argc, char **argv) { | |||
123 | 125 | ||
124 | cleanup: | 126 | cleanup: |
125 | swaynag_types_free(types); | 127 | swaynag_types_free(types); |
126 | free(swaynag.details.button_details.text); | 128 | free(swaynag.details.button_details->text); |
129 | free(swaynag.details.button_details); | ||
127 | swaynag_destroy(&swaynag); | 130 | swaynag_destroy(&swaynag); |
128 | return exit_code; | 131 | return exit_code; |
129 | } | 132 | } |