summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-03-30 19:04:06 -0400
committerLibravatar emersion <contact@emersion.fr>2018-03-30 19:04:06 -0400
commit96656427656118f2e4d725359cc880270b0e51be (patch)
treee2596e9cfa113efa43f2a411176c31e6208a58b1
parentHandle set_cursor requests from clients (diff)
parentMerge pull request #1665 from emersion/damage-tracking-lite (diff)
downloadsway-96656427656118f2e4d725359cc880270b0e51be.tar.gz
sway-96656427656118f2e4d725359cc880270b0e51be.tar.zst
sway-96656427656118f2e4d725359cc880270b0e51be.zip
Merge branch 'wlroots' into client-cursors
-rw-r--r--include/sway/commands.h2
-rw-r--r--include/sway/output.h14
-rw-r--r--include/sway/server.h2
-rw-r--r--include/sway/tree/container.h8
-rw-r--r--include/sway/tree/layout.h5
-rw-r--r--include/sway/tree/view.h10
-rw-r--r--include/sway/tree/workspace.h2
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/default_orientation.c21
-rw-r--r--sway/desktop/layer_shell.c26
-rw-r--r--sway/desktop/output.c167
-rw-r--r--sway/desktop/wl_shell.c1
-rw-r--r--sway/desktop/xdg_shell_v6.c52
-rw-r--r--sway/desktop/xwayland.c92
-rw-r--r--sway/input/cursor.c99
-rw-r--r--sway/input/seat.c4
-rw-r--r--sway/ipc-json.c69
-rw-r--r--sway/ipc-server.c10
-rw-r--r--sway/meson.build2
-rw-r--r--sway/server.c18
-rw-r--r--sway/tree/container.c78
-rw-r--r--sway/tree/layout.c58
-rw-r--r--sway/tree/output.c39
-rw-r--r--sway/tree/view.c27
-rw-r--r--sway/tree/workspace.c56
-rw-r--r--swaybg/main.c1
26 files changed, 576 insertions, 288 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 1291d5fb..66f097ea 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -95,6 +95,7 @@ sway_cmd cmd_commands;
95sway_cmd cmd_debuglog; 95sway_cmd cmd_debuglog;
96sway_cmd cmd_default_border; 96sway_cmd cmd_default_border;
97sway_cmd cmd_default_floating_border; 97sway_cmd cmd_default_floating_border;
98sway_cmd cmd_default_orientation;
98sway_cmd cmd_exec; 99sway_cmd cmd_exec;
99sway_cmd cmd_exec_always; 100sway_cmd cmd_exec_always;
100sway_cmd cmd_exit; 101sway_cmd cmd_exit;
@@ -125,7 +126,6 @@ sway_cmd cmd_move;
125sway_cmd cmd_new_float; 126sway_cmd cmd_new_float;
126sway_cmd cmd_new_window; 127sway_cmd cmd_new_window;
127sway_cmd cmd_no_focus; 128sway_cmd cmd_no_focus;
128sway_cmd cmd_orientation;
129sway_cmd cmd_output; 129sway_cmd cmd_output;
130sway_cmd cmd_permit; 130sway_cmd cmd_permit;
131sway_cmd cmd_reject; 131sway_cmd cmd_reject;
diff --git a/include/sway/output.h b/include/sway/output.h
index 6fb79987..b4980cd8 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -5,6 +5,7 @@
5#include <wayland-server.h> 5#include <wayland-server.h>
6#include <wlr/types/wlr_box.h> 6#include <wlr/types/wlr_box.h>
7#include <wlr/types/wlr_output.h> 7#include <wlr/types/wlr_output.h>
8#include "sway/tree/view.h"
8 9
9struct sway_server; 10struct sway_server;
10struct sway_container; 11struct sway_container;
@@ -13,17 +14,26 @@ struct sway_output {
13 struct wlr_output *wlr_output; 14 struct wlr_output *wlr_output;
14 struct sway_container *swayc; 15 struct sway_container *swayc;
15 struct sway_server *server; 16 struct sway_server *server;
16 struct timespec last_frame;
17 17
18 struct wl_list layers[4]; // sway_layer_surface::link 18 struct wl_list layers[4]; // sway_layer_surface::link
19 struct wlr_box usable_area; 19 struct wlr_box usable_area;
20 20
21 struct wl_listener frame; 21 struct timespec last_frame;
22 struct wlr_output_damage *damage;
23
22 struct wl_listener destroy; 24 struct wl_listener destroy;
23 struct wl_listener mode; 25 struct wl_listener mode;
24 struct wl_listener transform; 26 struct wl_listener transform;
25 27
28 struct wl_listener damage_destroy;
29 struct wl_listener damage_frame;
30
26 pid_t bg_pid; 31 pid_t bg_pid;
27}; 32};
28 33
34void output_damage_whole(struct sway_output *output);
35
36void output_damage_whole_view(struct sway_output *output,
37 struct sway_view *view);
38
29#endif 39#endif
diff --git a/include/sway/server.h b/include/sway/server.h
index 25eb64fe..61f21cdb 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -18,7 +18,6 @@ struct sway_server {
18 const char *socket; 18 const char *socket;
19 19
20 struct wlr_backend *backend; 20 struct wlr_backend *backend;
21 struct wlr_renderer *renderer;
22 21
23 struct wlr_compositor *compositor; 22 struct wlr_compositor *compositor;
24 struct wlr_data_device_manager *data_device_manager; 23 struct wlr_data_device_manager *data_device_manager;
@@ -26,7 +25,6 @@ struct sway_server {
26 struct sway_input_manager *input; 25 struct sway_input_manager *input;
27 26
28 struct wl_listener new_output; 27 struct wl_listener new_output;
29 struct wl_listener output_frame;
30 28
31 struct wlr_layer_shell *layer_shell; 29 struct wlr_layer_shell *layer_shell;
32 struct wl_listener layer_shell_surface; 30 struct wl_listener layer_shell_surface;
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 3bb497db..6aa66da0 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -99,8 +99,13 @@ struct sway_container *container_view_create(
99 99
100struct sway_container *container_output_destroy(struct sway_container *output); 100struct sway_container *container_output_destroy(struct sway_container *output);
101 101
102struct sway_container *container_workspace_destroy(
103 struct sway_container *workspace);
104
102struct sway_container *container_view_destroy(struct sway_container *view); 105struct sway_container *container_view_destroy(struct sway_container *view);
103 106
107struct sway_container *container_destroy(struct sway_container *cont);
108
104struct sway_container *container_set_layout(struct sway_container *container, 109struct sway_container *container_set_layout(struct sway_container *container,
105 enum sway_container_layout layout); 110 enum sway_container_layout layout);
106 111
@@ -140,4 +145,7 @@ void container_for_each_descendant_bfs(struct sway_container *container,
140void container_for_each_descendant_dfs(struct sway_container *container, 145void container_for_each_descendant_dfs(struct sway_container *container,
141 void (*f)(struct sway_container *container, void *data), void *data); 146 void (*f)(struct sway_container *container, void *data), void *data);
142 147
148bool container_has_anscestor(struct sway_container *descendant,
149 struct sway_container *anscestor);
150
143#endif 151#endif
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h
index ad52bdb0..0a904c4b 100644
--- a/include/sway/tree/layout.h
+++ b/include/sway/tree/layout.h
@@ -39,6 +39,11 @@ struct sway_container *container_add_sibling(struct sway_container *parent,
39 39
40struct sway_container *container_remove_child(struct sway_container *child); 40struct sway_container *container_remove_child(struct sway_container *child);
41 41
42struct sway_container *container_reap_empty(struct sway_container *container);
43
44void container_move_to(struct sway_container* container,
45 struct sway_container* destination);
46
42enum sway_container_layout container_get_default_layout(struct sway_container *output); 47enum sway_container_layout container_get_default_layout(struct sway_container *output);
43 48
44void container_sort_workspaces(struct sway_container *output); 49void container_sort_workspaces(struct sway_container *output);
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index e5f53f4e..3965d2b7 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -15,6 +15,8 @@ struct sway_xdg_surface_v6 {
15 struct wl_listener request_move; 15 struct wl_listener request_move;
16 struct wl_listener request_resize; 16 struct wl_listener request_resize;
17 struct wl_listener request_maximize; 17 struct wl_listener request_maximize;
18 struct wl_listener map;
19 struct wl_listener unmap;
18 struct wl_listener destroy; 20 struct wl_listener destroy;
19 21
20 int pending_width, pending_height; 22 int pending_width, pending_height;
@@ -28,8 +30,8 @@ struct sway_xwayland_surface {
28 struct wl_listener request_resize; 30 struct wl_listener request_resize;
29 struct wl_listener request_maximize; 31 struct wl_listener request_maximize;
30 struct wl_listener request_configure; 32 struct wl_listener request_configure;
31 struct wl_listener unmap_notify; 33 struct wl_listener map;
32 struct wl_listener map_notify; 34 struct wl_listener unmap;
33 struct wl_listener destroy; 35 struct wl_listener destroy;
34 36
35 int pending_width, pending_height; 37 int pending_width, pending_height;
@@ -113,4 +115,8 @@ void view_close(struct sway_view *view);
113 115
114void view_update_outputs(struct sway_view *view, const struct wlr_box *before); 116void view_update_outputs(struct sway_view *view, const struct wlr_box *before);
115 117
118void view_damage_whole(struct sway_view *view);
119
120void view_damage_from(struct sway_view *view);
121
116#endif 122#endif
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h
index d73b29c1..4e4c3450 100644
--- a/include/sway/tree/workspace.h
+++ b/include/sway/tree/workspace.h
@@ -23,4 +23,6 @@ struct sway_container *workspace_output_prev(struct sway_container *current);
23 23
24struct sway_container *workspace_prev(struct sway_container *current); 24struct sway_container *workspace_prev(struct sway_container *current);
25 25
26bool workspace_is_visible(struct sway_container *ws);
27
26#endif 28#endif
diff --git a/sway/commands.c b/sway/commands.c
index bcc777ed..eee7f254 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -149,6 +149,7 @@ static struct cmd_handler bar_colors_handlers[] = {
149 149
150/* Config-time only commands. Keep alphabetized */ 150/* Config-time only commands. Keep alphabetized */
151static struct cmd_handler config_handlers[] = { 151static struct cmd_handler config_handlers[] = {
152 { "default_orientation", cmd_default_orientation },
152 { "set", cmd_set }, 153 { "set", cmd_set },
153 { "swaybg_command", cmd_swaybg_command }, 154 { "swaybg_command", cmd_swaybg_command },
154}; 155};
diff --git a/sway/commands/default_orientation.c b/sway/commands/default_orientation.c
new file mode 100644
index 00000000..a5347ce2
--- /dev/null
+++ b/sway/commands/default_orientation.c
@@ -0,0 +1,21 @@
1#include <string.h>
2#include <strings.h>
3#include "sway/commands.h"
4
5struct cmd_results *cmd_default_orientation(int argc, char **argv) {
6 struct cmd_results *error = NULL;
7 if ((error = checkarg(argc, "default_orientation", EXPECTED_EQUAL_TO, 1))) {
8 return error;
9 }
10 if (strcasecmp(argv[0], "horizontal") == 0) {
11 config->default_orientation = L_HORIZ;
12 } else if (strcasecmp(argv[0], "vertical") == 0) {
13 config->default_orientation = L_VERT;
14 } else if (strcasecmp(argv[0], "auto") == 0) {
15 // Do nothing
16 } else {
17 return cmd_results_new(CMD_INVALID, "default_orientation",
18 "Expected 'orientation <horizontal|vertical|auto>'");
19 }
20 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
21}
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index f7e5d19c..5c96659a 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -4,12 +4,13 @@
4#include <wayland-server.h> 4#include <wayland-server.h>
5#include <wlr/types/wlr_box.h> 5#include <wlr/types/wlr_box.h>
6#include <wlr/types/wlr_layer_shell.h> 6#include <wlr/types/wlr_layer_shell.h>
7#include <wlr/types/wlr_output_damage.h>
7#include <wlr/types/wlr_output.h> 8#include <wlr/types/wlr_output.h>
8#include <wlr/util/log.h> 9#include <wlr/util/log.h>
9#include "sway/layers.h" 10#include "sway/layers.h"
10#include "sway/tree/layout.h"
11#include "sway/output.h" 11#include "sway/output.h"
12#include "sway/server.h" 12#include "sway/server.h"
13#include "sway/tree/layout.h"
13 14
14static void apply_exclusive(struct wlr_box *usable_area, 15static void apply_exclusive(struct wlr_box *usable_area,
15 uint32_t anchor, int32_t exclusive, 16 uint32_t anchor, int32_t exclusive,
@@ -210,20 +211,26 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
210 } else { 211 } else {
211 // TODO DAMAGE from surface damage 212 // TODO DAMAGE from surface damage
212 } 213 }
214 wlr_output_damage_add_box(output->damage, &old_geo);
215 wlr_output_damage_add_box(output->damage, &layer->geo);
213 } 216 }
214} 217}
215 218
216static void unmap(struct wlr_layer_surface *layer_surface) { 219static void unmap(struct sway_layer_surface *sway_layer) {
217 // TODO DAMAGE 220 struct wlr_output *wlr_output = sway_layer->layer_surface->output;
221 if (wlr_output != NULL) {
222 struct sway_output *output = wlr_output->data;
223 wlr_output_damage_add_box(output->damage, &sway_layer->geo);
224 }
218} 225}
219 226
220static void handle_destroy(struct wl_listener *listener, void *data) { 227static void handle_destroy(struct wl_listener *listener, void *data) {
221 struct sway_layer_surface *sway_layer = wl_container_of( 228 struct sway_layer_surface *sway_layer = wl_container_of(listener,
222 listener, sway_layer, destroy); 229 sway_layer, destroy);
223 wlr_log(L_DEBUG, "Layer surface destroyed (%s)", 230 wlr_log(L_DEBUG, "Layer surface destroyed (%s)",
224 sway_layer->layer_surface->namespace); 231 sway_layer->layer_surface->namespace);
225 if (sway_layer->layer_surface->mapped) { 232 if (sway_layer->layer_surface->mapped) {
226 unmap(sway_layer->layer_surface); 233 unmap(sway_layer);
227 } 234 }
228 wl_list_remove(&sway_layer->link); 235 wl_list_remove(&sway_layer->link);
229 wl_list_remove(&sway_layer->destroy.link); 236 wl_list_remove(&sway_layer->destroy.link);
@@ -239,13 +246,16 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
239} 246}
240 247
241static void handle_map(struct wl_listener *listener, void *data) { 248static void handle_map(struct wl_listener *listener, void *data) {
242 // TODO DAMAGE 249 struct sway_layer_surface *sway_layer = wl_container_of(listener,
250 sway_layer, map);
251 struct sway_output *output = sway_layer->layer_surface->output->data;
252 wlr_output_damage_add_box(output->damage, &sway_layer->geo);
243} 253}
244 254
245static void handle_unmap(struct wl_listener *listener, void *data) { 255static void handle_unmap(struct wl_listener *listener, void *data) {
246 struct sway_layer_surface *sway_layer = wl_container_of( 256 struct sway_layer_surface *sway_layer = wl_container_of(
247 listener, sway_layer, unmap); 257 listener, sway_layer, unmap);
248 unmap(sway_layer->layer_surface); 258 unmap(sway_layer);
249} 259}
250 260
251void handle_layer_shell_surface(struct wl_listener *listener, void *data) { 261void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index 87eb80fe..c248b29e 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -6,18 +6,19 @@
6#include <wlr/render/wlr_renderer.h> 6#include <wlr/render/wlr_renderer.h>
7#include <wlr/types/wlr_box.h> 7#include <wlr/types/wlr_box.h>
8#include <wlr/types/wlr_matrix.h> 8#include <wlr/types/wlr_matrix.h>
9#include <wlr/types/wlr_output.h> 9#include <wlr/types/wlr_output_damage.h>
10#include <wlr/types/wlr_output_layout.h> 10#include <wlr/types/wlr_output_layout.h>
11#include <wlr/types/wlr_output.h>
11#include <wlr/types/wlr_surface.h> 12#include <wlr/types/wlr_surface.h>
12#include <wlr/types/wlr_wl_shell.h> 13#include <wlr/types/wlr_wl_shell.h>
13#include "log.h" 14#include "log.h"
14#include "sway/tree/container.h"
15#include "sway/input/input-manager.h" 15#include "sway/input/input-manager.h"
16#include "sway/input/seat.h" 16#include "sway/input/seat.h"
17#include "sway/layers.h" 17#include "sway/layers.h"
18#include "sway/tree/layout.h"
19#include "sway/output.h" 18#include "sway/output.h"
20#include "sway/server.h" 19#include "sway/server.h"
20#include "sway/tree/container.h"
21#include "sway/tree/layout.h"
21#include "sway/tree/view.h" 22#include "sway/tree/view.h"
22 23
23/** 24/**
@@ -41,6 +42,9 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh,
41static void render_surface(struct wlr_surface *surface, 42static void render_surface(struct wlr_surface *surface,
42 struct wlr_output *wlr_output, struct timespec *when, 43 struct wlr_output *wlr_output, struct timespec *when,
43 double lx, double ly, float rotation) { 44 double lx, double ly, float rotation) {
45 struct wlr_renderer *renderer =
46 wlr_backend_get_renderer(wlr_output->backend);
47
44 if (!wlr_surface_has_buffer(surface)) { 48 if (!wlr_surface_has_buffer(surface)) {
45 return; 49 return;
46 } 50 }
@@ -65,8 +69,8 @@ static void render_surface(struct wlr_surface *surface,
65 float matrix[9]; 69 float matrix[9];
66 wlr_matrix_project_box(matrix, &render_box, surface->current->transform, 70 wlr_matrix_project_box(matrix, &render_box, surface->current->transform,
67 0, wlr_output->transform_matrix); 71 0, wlr_output->transform_matrix);
68 wlr_render_texture_with_matrix(server.renderer, surface->texture, 72 wlr_render_texture_with_matrix(renderer, surface->texture, matrix,
69 matrix, 1.0f); // TODO: configurable alpha 73 1.0f); // TODO: configurable alpha
70 74
71 wlr_surface_send_frame_done(surface, when); 75 wlr_surface_send_frame_done(surface, when);
72 } 76 }
@@ -142,13 +146,13 @@ static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface,
142 146
143struct render_data { 147struct render_data {
144 struct sway_output *output; 148 struct sway_output *output;
145 struct timespec *now; 149 struct timespec *when;
146}; 150};
147 151
148static void output_frame_view(struct sway_container *view, void *data) { 152static void render_view(struct sway_container *view, void *data) {
149 struct render_data *rdata = data; 153 struct render_data *rdata = data;
150 struct sway_output *output = rdata->output; 154 struct sway_output *output = rdata->output;
151 struct timespec *now = rdata->now; 155 struct timespec *when = rdata->when;
152 struct wlr_output *wlr_output = output->wlr_output; 156 struct wlr_output *wlr_output = output->wlr_output;
153 struct sway_view *sway_view = view->sway_view; 157 struct sway_view *sway_view = view->sway_view;
154 struct wlr_surface *surface = sway_view->surface; 158 struct wlr_surface *surface = sway_view->surface;
@@ -161,18 +165,18 @@ static void output_frame_view(struct sway_container *view, void *data) {
161 case SWAY_XDG_SHELL_V6_VIEW: { 165 case SWAY_XDG_SHELL_V6_VIEW: {
162 int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x; 166 int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x;
163 int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y; 167 int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y;
164 render_surface(surface, wlr_output, now, 168 render_surface(surface, wlr_output, when,
165 view->x - window_offset_x, view->y - window_offset_y, 0); 169 view->x - window_offset_x, view->y - window_offset_y, 0);
166 render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output, 170 render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output,
167 now, view->x - window_offset_x, view->y - window_offset_y, 0); 171 when, view->x - window_offset_x, view->y - window_offset_y, 0);
168 break; 172 break;
169 } 173 }
170 case SWAY_WL_SHELL_VIEW: 174 case SWAY_WL_SHELL_VIEW:
171 render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output, 175 render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output,
172 now, view->x, view->y, 0, false); 176 when, view->x, view->y, 0, false);
173 break; 177 break;
174 case SWAY_XWAYLAND_VIEW: 178 case SWAY_XWAYLAND_VIEW:
175 render_surface(surface, wlr_output, now, view->x, view->y, 0); 179 render_surface(surface, wlr_output, when, view->x, view->y, 0);
176 break; 180 break;
177 default: 181 default:
178 break; 182 break;
@@ -192,82 +196,132 @@ static void render_layer(struct sway_output *output,
192 } 196 }
193} 197}
194 198
195static void output_frame_notify(struct wl_listener *listener, void *data) { 199static void render_output(struct sway_output *output, struct timespec *when,
196 struct sway_output *soutput = wl_container_of(listener, soutput, frame); 200 pixman_region32_t *damage) {
197 struct wlr_output *wlr_output = data; 201 struct wlr_output *wlr_output = output->wlr_output;
198 struct sway_server *server = soutput->server; 202 struct wlr_renderer *renderer =
199 struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); 203 wlr_backend_get_renderer(wlr_output->backend);
204
205 wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
206
207 if (!pixman_region32_not_empty(damage)) {
208 // Output isn't damaged but needs buffer swap
209 goto renderer_end;
210 }
200 211
201 int buffer_age = -1; 212 // TODO: don't damage the whole output here
202 wlr_output_make_current(wlr_output, &buffer_age); 213 int width, height;
203 wlr_renderer_begin(server->renderer, wlr_output->width, wlr_output->height); 214 wlr_output_transformed_resolution(wlr_output, &width, &height);
215 pixman_region32_union_rect(damage, damage, 0, 0, width, height);
204 216
205 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; 217 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
206 wlr_renderer_clear(renderer, clear_color); 218 wlr_renderer_clear(renderer, clear_color);
207 219
208 struct timespec now;
209 clock_gettime(CLOCK_MONOTONIC, &now);
210
211 struct wlr_output_layout *layout = root_container.sway_root->output_layout; 220 struct wlr_output_layout *layout = root_container.sway_root->output_layout;
212 const struct wlr_box *output_box = wlr_output_layout_get_box( 221 const struct wlr_box *output_box =
213 layout, wlr_output); 222 wlr_output_layout_get_box(layout, wlr_output);
214 223
215 render_layer(soutput, output_box, &now, 224 render_layer(output, output_box, when,
216 &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); 225 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
217 render_layer(soutput, output_box, &now, 226 render_layer(output, output_box, when,
218 &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); 227 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
219 228
220 struct sway_seat *seat = input_manager_current_seat(input_manager); 229 struct sway_seat *seat = input_manager_current_seat(input_manager);
221 struct sway_container *focus = sway_seat_get_focus_inactive(seat, soutput->swayc); 230 struct sway_container *focus =
231 sway_seat_get_focus_inactive(seat, output->swayc);
222 struct sway_container *workspace = (focus->type == C_WORKSPACE ? 232 struct sway_container *workspace = (focus->type == C_WORKSPACE ?
223 focus : 233 focus :
224 container_parent(focus, C_WORKSPACE)); 234 container_parent(focus, C_WORKSPACE));
225 235
226 struct render_data rdata = { 236 struct render_data rdata = {
227 .output = soutput, 237 .output = output,
228 .now = &now, 238 .when = when,
229 }; 239 };
230 container_descendants(workspace, C_VIEW, output_frame_view, &rdata); 240 container_descendants(workspace, C_VIEW, render_view, &rdata);
231 241
232 // render unmanaged views on top 242 // render unmanaged views on top
233 struct sway_view *view; 243 struct sway_view *view;
234 wl_list_for_each(view, &root_container.sway_root->unmanaged_views, 244 wl_list_for_each(view, &root_container.sway_root->unmanaged_views,
235 unmanaged_view_link) { 245 unmanaged_view_link) {
236 if (view->type == SWAY_XWAYLAND_VIEW) { 246 if (view->type == SWAY_XWAYLAND_VIEW) {
237 // the only kind of unamanged view right now is xwayland override redirect 247 // the only kind of unamanged view right now is xwayland override
248 // redirect
238 int view_x = view->wlr_xwayland_surface->x; 249 int view_x = view->wlr_xwayland_surface->x;
239 int view_y = view->wlr_xwayland_surface->y; 250 int view_y = view->wlr_xwayland_surface->y;
240 render_surface(view->surface, wlr_output, &soutput->last_frame, 251 render_surface(view->surface, wlr_output, &output->last_frame,
241 view_x, view_y, 0); 252 view_x, view_y, 0);
242 } 253 }
243 } 254 }
244 255
245 // TODO: Consider revising this when fullscreen windows are supported 256 // TODO: Consider revising this when fullscreen windows are supported
246 render_layer(soutput, output_box, &now, 257 render_layer(output, output_box, when,
247 &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); 258 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
248 render_layer(soutput, output_box, &now, 259 render_layer(output, output_box, when,
249 &soutput->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); 260 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]);
250 261
251 wlr_renderer_end(server->renderer); 262renderer_end:
252 wlr_output_swap_buffers(wlr_output, &now, NULL); 263 wlr_renderer_end(renderer);
253 soutput->last_frame = now; 264 if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) {
265 return;
266 }
267 output->last_frame = *when;
254} 268}
255 269
256static void handle_output_destroy(struct wl_listener *listener, void *data) { 270static void damage_handle_frame(struct wl_listener *listener, void *data) {
257 struct sway_output *output = wl_container_of(listener, output, destroy); 271 struct sway_output *output =
258 struct wlr_output *wlr_output = data; 272 wl_container_of(listener, output, damage_frame);
259 wlr_log(L_DEBUG, "Output %p %s removed", wlr_output, wlr_output->name); 273
274 if (!output->wlr_output->enabled) {
275 return;
276 }
260 277
278 struct timespec now;
279 clock_gettime(CLOCK_MONOTONIC, &now);
280
281 bool needs_swap;
282 pixman_region32_t damage;
283 pixman_region32_init(&damage);
284 if (!wlr_output_damage_make_current(output->damage, &needs_swap, &damage)) {
285 return;
286 }
287
288 if (needs_swap) {
289 render_output(output, &now, &damage);
290 }
291
292 pixman_region32_fini(&damage);
293
294 // TODO: send frame done events here instead of inside render_surface
295}
296
297void output_damage_whole(struct sway_output *output) {
298 wlr_output_damage_add_whole(output->damage);
299}
300
301void output_damage_whole_view(struct sway_output *output,
302 struct sway_view *view) {
303 // TODO
304 output_damage_whole(output);
305}
306
307static void damage_handle_destroy(struct wl_listener *listener, void *data) {
308 struct sway_output *output =
309 wl_container_of(listener, output, damage_destroy);
310 container_output_destroy(output->swayc);
311}
312
313static void handle_destroy(struct wl_listener *listener, void *data) {
314 struct sway_output *output = wl_container_of(listener, output, destroy);
261 container_output_destroy(output->swayc); 315 container_output_destroy(output->swayc);
262} 316}
263 317
264static void handle_output_mode(struct wl_listener *listener, void *data) { 318static void handle_mode(struct wl_listener *listener, void *data) {
265 struct sway_output *output = wl_container_of(listener, output, mode); 319 struct sway_output *output = wl_container_of(listener, output, mode);
266 arrange_layers(output); 320 arrange_layers(output);
267 arrange_windows(output->swayc, -1, -1); 321 arrange_windows(output->swayc, -1, -1);
268} 322}
269 323
270static void handle_output_transform(struct wl_listener *listener, void *data) { 324static void handle_transform(struct wl_listener *listener, void *data) {
271 struct sway_output *output = wl_container_of(listener, output, transform); 325 struct sway_output *output = wl_container_of(listener, output, transform);
272 arrange_layers(output); 326 arrange_layers(output);
273 arrange_windows(output->swayc, -1, -1); 327 arrange_windows(output->swayc, -1, -1);
@@ -292,6 +346,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
292 wlr_output_set_mode(wlr_output, mode); 346 wlr_output_set_mode(wlr_output, mode);
293 } 347 }
294 348
349 output->damage = wlr_output_damage_create(wlr_output);
350
295 output->swayc = container_output_create(output); 351 output->swayc = container_output_create(output);
296 if (!output->swayc) { 352 if (!output->swayc) {
297 free(output); 353 free(output);
@@ -305,14 +361,17 @@ void handle_new_output(struct wl_listener *listener, void *data) {
305 361
306 sway_input_manager_configure_xcursor(input_manager); 362 sway_input_manager_configure_xcursor(input_manager);
307 363
308 wl_signal_add(&wlr_output->events.frame, &output->frame);
309 output->frame.notify = output_frame_notify;
310 wl_signal_add(&wlr_output->events.destroy, &output->destroy); 364 wl_signal_add(&wlr_output->events.destroy, &output->destroy);
311 output->destroy.notify = handle_output_destroy; 365 output->destroy.notify = handle_destroy;
312 wl_signal_add(&wlr_output->events.mode, &output->mode); 366 wl_signal_add(&wlr_output->events.mode, &output->mode);
313 output->mode.notify = handle_output_mode; 367 output->mode.notify = handle_mode;
314 wl_signal_add(&wlr_output->events.transform, &output->transform); 368 wl_signal_add(&wlr_output->events.transform, &output->transform);
315 output->transform.notify = handle_output_transform; 369 output->transform.notify = handle_transform;
370
371 wl_signal_add(&output->damage->events.frame, &output->damage_frame);
372 output->damage_frame.notify = damage_handle_frame;
373 wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
374 output->damage_destroy.notify = damage_handle_destroy;
316 375
317 arrange_layers(output); 376 arrange_layers(output);
318 arrange_windows(&root_container, -1, -1); 377 arrange_windows(&root_container, -1, -1);
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c
index 4d4d1ed7..4fcc6317 100644
--- a/sway/desktop/wl_shell.c
+++ b/sway/desktop/wl_shell.c
@@ -67,6 +67,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
67 // TODO: Let floating views do whatever 67 // TODO: Let floating views do whatever
68 view->width = sway_surface->pending_width; 68 view->width = sway_surface->pending_width;
69 view->height = sway_surface->pending_height; 69 view->height = sway_surface->pending_height;
70 view_damage_from(view);
70} 71}
71 72
72static void handle_destroy(struct wl_listener *listener, void *data) { 73static void handle_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 25c0cbca..713437f2 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -76,6 +76,35 @@ static void handle_commit(struct wl_listener *listener, void *data) {
76 // TODO: Let floating views do whatever 76 // TODO: Let floating views do whatever
77 view->width = sway_surface->pending_width; 77 view->width = sway_surface->pending_width;
78 view->height = sway_surface->pending_height; 78 view->height = sway_surface->pending_height;
79 view_damage_from(view);
80}
81
82static void handle_unmap(struct wl_listener *listener, void *data) {
83 struct sway_xdg_surface_v6 *sway_surface =
84 wl_container_of(listener, sway_surface, unmap);
85 view_damage_whole(sway_surface->view);
86 container_view_destroy(sway_surface->view->swayc);
87 sway_surface->view->swayc = NULL;
88 sway_surface->view->surface = NULL;
89}
90
91static void handle_map(struct wl_listener *listener, void *data) {
92 struct sway_xdg_surface_v6 *sway_surface =
93 wl_container_of(listener, sway_surface, map);
94 struct sway_view *view = sway_surface->view;
95
96 sway_surface->view->surface = view->wlr_xdg_surface_v6->surface;
97
98 container_view_destroy(view->swayc);
99
100 struct sway_seat *seat = input_manager_current_seat(input_manager);
101 struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container);
102 struct sway_container *cont = container_view_create(focus, view);
103 view->swayc = cont;
104 arrange_windows(cont->parent, -1, -1);
105 sway_input_manager_set_focus(input_manager, cont);
106
107 view_damage_whole(sway_surface->view);
79} 108}
80 109
81static void handle_destroy(struct wl_listener *listener, void *data) { 110static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -83,10 +112,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
83 wl_container_of(listener, sway_xdg_surface, destroy); 112 wl_container_of(listener, sway_xdg_surface, destroy);
84 wl_list_remove(&sway_xdg_surface->commit.link); 113 wl_list_remove(&sway_xdg_surface->commit.link);
85 wl_list_remove(&sway_xdg_surface->destroy.link); 114 wl_list_remove(&sway_xdg_surface->destroy.link);
86 struct sway_container *parent = container_view_destroy(sway_xdg_surface->view->swayc); 115 container_view_destroy(sway_xdg_surface->view->swayc);
87 free(sway_xdg_surface->view); 116 free(sway_xdg_surface->view);
88 free(sway_xdg_surface); 117 free(sway_xdg_surface);
89 arrange_windows(parent, -1, -1);
90} 118}
91 119
92void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { 120void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
@@ -122,26 +150,22 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
122 sway_view->iface.close = close; 150 sway_view->iface.close = close;
123 sway_view->wlr_xdg_surface_v6 = xdg_surface; 151 sway_view->wlr_xdg_surface_v6 = xdg_surface;
124 sway_view->sway_xdg_surface_v6 = sway_surface; 152 sway_view->sway_xdg_surface_v6 = sway_surface;
125 sway_view->surface = xdg_surface->surface;
126 sway_surface->view = sway_view; 153 sway_surface->view = sway_view;
127 154
128 // TODO: 155 // TODO:
129 // - Look up pid and open on appropriate workspace 156 // - Look up pid and open on appropriate workspace
130 // - Set new view to maximized so it behaves nicely 157 // - Set new view to maximized so it behaves nicely
131 // - Criteria 158 // - Criteria
132 159
133 sway_surface->commit.notify = handle_commit; 160 sway_surface->commit.notify = handle_commit;
134 wl_signal_add(&xdg_surface->surface->events.commit, &sway_surface->commit); 161 wl_signal_add(&xdg_surface->surface->events.commit, &sway_surface->commit);
135 162
136 sway_surface->destroy.notify = handle_destroy; 163 sway_surface->map.notify = handle_map;
137 wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy); 164 wl_signal_add(&xdg_surface->events.map, &sway_surface->map);
138 165
139 struct sway_seat *seat = input_manager_current_seat(input_manager); 166 sway_surface->unmap.notify = handle_unmap;
140 struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); 167 wl_signal_add(&xdg_surface->events.unmap, &sway_surface->unmap);
141 struct sway_container *cont = container_view_create(focus, sway_view);
142 sway_view->swayc = cont;
143
144 arrange_windows(cont->parent, -1, -1);
145 168
146 sway_input_manager_set_focus(input_manager, cont); 169 sway_surface->destroy.notify = handle_destroy;
170 wl_signal_add(&xdg_surface->events.destroy, &sway_surface->destroy);
147} 171}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 38ee4656..01c993b3 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -14,10 +14,10 @@
14#include "sway/input/input-manager.h" 14#include "sway/input/input-manager.h"
15#include "log.h" 15#include "log.h"
16 16
17 static bool assert_xwayland(struct sway_view *view) { 17static bool assert_xwayland(struct sway_view *view) {
18 return sway_assert(view->type == SWAY_XWAYLAND_VIEW && view->wlr_xwayland_surface, 18 return sway_assert(view->type == SWAY_XWAYLAND_VIEW,
19 "Expected xwayland view!"); 19 "Expected xwayland view!");
20 } 20}
21 21
22static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) { 22static const char *get_prop(struct sway_view *view, enum sway_view_prop prop) {
23 if (!assert_xwayland(view)) { 23 if (!assert_xwayland(view)) {
@@ -99,73 +99,59 @@ static void handle_commit(struct wl_listener *listener, void *data) {
99 // TODO: Let floating views do whatever 99 // TODO: Let floating views do whatever
100 view->width = sway_surface->pending_width; 100 view->width = sway_surface->pending_width;
101 view->height = sway_surface->pending_height; 101 view->height = sway_surface->pending_height;
102 view_damage_from(view);
102} 103}
103 104
104static void handle_destroy(struct wl_listener *listener, void *data) { 105static void handle_destroy(struct wl_listener *listener, void *data) {
105 struct sway_xwayland_surface *sway_surface = 106 struct sway_xwayland_surface *sway_surface =
106 wl_container_of(listener, sway_surface, destroy); 107 wl_container_of(listener, sway_surface, destroy);
107 struct wlr_xwayland_surface *xsurface = data; 108
108 wl_list_remove(&sway_surface->commit.link); 109 wl_list_remove(&sway_surface->commit.link);
109 wl_list_remove(&sway_surface->destroy.link); 110 wl_list_remove(&sway_surface->destroy.link);
110 wl_list_remove(&sway_surface->request_configure.link); 111 wl_list_remove(&sway_surface->request_configure.link);
111 if (xsurface->override_redirect && xsurface->mapped) { 112 wl_list_remove(&sway_surface->view->unmanaged_view_link);
112 wl_list_remove(&sway_surface->view->unmanaged_view_link); 113 container_view_destroy(sway_surface->view->swayc);
113 wl_list_init(&sway_surface->view->unmanaged_view_link); 114 sway_surface->view->swayc = NULL;
114 } 115 sway_surface->view->surface = NULL;
115
116 struct sway_container *parent = container_view_destroy(sway_surface->view->swayc);
117 if (parent) {
118 arrange_windows(parent, -1, -1);
119 }
120
121 free(sway_surface->view);
122 free(sway_surface);
123} 116}
124 117
125static void handle_unmap_notify(struct wl_listener *listener, void *data) { 118static void handle_unmap(struct wl_listener *listener, void *data) {
126 struct sway_xwayland_surface *sway_surface = 119 struct sway_xwayland_surface *sway_surface =
127 wl_container_of(listener, sway_surface, unmap_notify); 120 wl_container_of(listener, sway_surface, unmap);
128 struct wlr_xwayland_surface *xsurface = data; 121 view_damage_whole(sway_surface->view);
129 if (xsurface->override_redirect && xsurface->mapped) { 122 wl_list_remove(&sway_surface->view->unmanaged_view_link);
130 wl_list_remove(&sway_surface->view->unmanaged_view_link); 123 wl_list_init(&sway_surface->view->unmanaged_view_link);
131 wl_list_init(&sway_surface->view->unmanaged_view_link); 124 container_view_destroy(sway_surface->view->swayc);
132 }
133
134 // take it out of the tree
135 struct sway_container *parent = container_view_destroy(sway_surface->view->swayc);
136 if (parent) {
137 arrange_windows(parent, -1, -1);
138 }
139
140 sway_surface->view->swayc = NULL; 125 sway_surface->view->swayc = NULL;
141 sway_surface->view->surface = NULL; 126 sway_surface->view->surface = NULL;
142} 127}
143 128
144static void handle_map_notify(struct wl_listener *listener, void *data) { 129static void handle_map(struct wl_listener *listener, void *data) {
145 // TODO put the view back into the tree
146 struct sway_xwayland_surface *sway_surface = 130 struct sway_xwayland_surface *sway_surface =
147 wl_container_of(listener, sway_surface, map_notify); 131 wl_container_of(listener, sway_surface, map);
148 struct wlr_xwayland_surface *xsurface = data; 132 struct wlr_xwayland_surface *xsurface = data;
149 133
150 sway_surface->view->surface = xsurface->surface; 134 sway_surface->view->surface = xsurface->surface;
151 135
152 // put it back into the tree 136 // put it back into the tree
153 if (xsurface->override_redirect) { 137 if (wlr_xwayland_surface_is_unmanaged(xsurface) ||
138 xsurface->override_redirect) {
139 wl_list_remove(&sway_surface->view->unmanaged_view_link);
154 wl_list_insert(&root_container.sway_root->unmanaged_views, 140 wl_list_insert(&root_container.sway_root->unmanaged_views,
155 &sway_surface->view->unmanaged_view_link); 141 &sway_surface->view->unmanaged_view_link);
156 } else { 142 } else {
157 struct sway_view *view = sway_surface->view; 143 struct sway_view *view = sway_surface->view;
158 container_view_destroy(view->swayc); 144 container_view_destroy(view->swayc);
159 145
160 struct sway_container *parent = root_container.children->items[0]; 146 struct sway_seat *seat = input_manager_current_seat(input_manager);
161 parent = parent->children->items[0]; // workspace 147 struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container);
162 148 struct sway_container *cont = container_view_create(focus, view);
163 struct sway_container *cont = container_view_create(parent, view);
164 view->swayc = cont; 149 view->swayc = cont;
165
166 arrange_windows(cont->parent, -1, -1); 150 arrange_windows(cont->parent, -1, -1);
167 sway_input_manager_set_focus(input_manager, cont); 151 sway_input_manager_set_focus(input_manager, cont);
168 } 152 }
153
154 view_damage_whole(sway_surface->view);
169} 155}
170 156
171static void handle_configure_request(struct wl_listener *listener, void *data) { 157static void handle_configure_request(struct wl_listener *listener, void *data) {
@@ -206,9 +192,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
206 sway_view->iface.close = close_view; 192 sway_view->iface.close = close_view;
207 sway_view->wlr_xwayland_surface = xsurface; 193 sway_view->wlr_xwayland_surface = xsurface;
208 sway_view->sway_xwayland_surface = sway_surface; 194 sway_view->sway_xwayland_surface = sway_surface;
209 sway_view->surface = xsurface->surface;
210 sway_surface->view = sway_view; 195 sway_surface->view = sway_view;
211 196
197 wl_list_init(&sway_view->unmanaged_view_link);
198
212 // TODO: 199 // TODO:
213 // - Look up pid and open on appropriate workspace 200 // - Look up pid and open on appropriate workspace
214 // - Set new view to maximized so it behaves nicely 201 // - Set new view to maximized so it behaves nicely
@@ -224,24 +211,11 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) {
224 &sway_surface->request_configure); 211 &sway_surface->request_configure);
225 sway_surface->request_configure.notify = handle_configure_request; 212 sway_surface->request_configure.notify = handle_configure_request;
226 213
227 wl_signal_add(&xsurface->events.unmap_notify, &sway_surface->unmap_notify); 214 wl_signal_add(&xsurface->events.unmap, &sway_surface->unmap);
228 sway_surface->unmap_notify.notify = handle_unmap_notify; 215 sway_surface->unmap.notify = handle_unmap;
229
230 wl_signal_add(&xsurface->events.map_notify, &sway_surface->map_notify);
231 sway_surface->map_notify.notify = handle_map_notify;
232
233 if (wlr_xwayland_surface_is_unmanaged(xsurface)) {
234 // these don't get a container in the tree
235 wl_list_insert(&root_container.sway_root->unmanaged_views,
236 &sway_view->unmanaged_view_link);
237 return;
238 }
239 216
240 struct sway_seat *seat = input_manager_current_seat(input_manager); 217 wl_signal_add(&xsurface->events.map, &sway_surface->map);
241 struct sway_container *focus = sway_seat_get_focus_inactive(seat, &root_container); 218 sway_surface->map.notify = handle_map;
242 struct sway_container *cont = container_view_create(focus, sway_view);
243 sway_view->swayc = cont;
244 219
245 arrange_windows(cont->parent, -1, -1); 220 handle_map(&sway_surface->map, xsurface);
246 sway_input_manager_set_focus(input_manager, cont);
247} 221}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index cded0005..d814e08e 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -6,10 +6,11 @@
6#endif 6#endif
7#include <wlr/types/wlr_cursor.h> 7#include <wlr/types/wlr_cursor.h>
8#include <wlr/types/wlr_xcursor_manager.h> 8#include <wlr/types/wlr_xcursor_manager.h>
9#include "sway/input/cursor.h"
10#include "sway/tree/view.h"
11#include "list.h" 9#include "list.h"
12#include "log.h" 10#include "log.h"
11#include "sway/input/cursor.h"
12#include "sway/output.h"
13#include "sway/tree/view.h"
13 14
14static void cursor_update_position(struct sway_cursor *cursor) { 15static void cursor_update_position(struct sway_cursor *cursor) {
15 double x = cursor->cursor->x; 16 double x = cursor->cursor->x;
@@ -19,18 +20,16 @@ static void cursor_update_position(struct sway_cursor *cursor) {
19 cursor->y = y; 20 cursor->y = y;
20} 21}
21 22
22static void cursor_send_pointer_motion(struct sway_cursor *cursor, 23/**
23 uint32_t time) { 24 * Returns the container at the cursor's position. If the container is a view,
24 struct wlr_seat *seat = cursor->seat->wlr_seat; 25 * stores the surface at the cursor's position in `*surface`.
25 struct wlr_surface *surface = NULL; 26 */
26 double sx, sy; 27static struct sway_container *container_at_cursor(struct sway_cursor *cursor,
27 28 struct wlr_surface **surface, double *sx, double *sy) {
28 struct sway_container *focus = NULL;
29
30 // check for unmanaged views first 29 // check for unmanaged views first
30 struct wl_list *unmanaged = &root_container.sway_root->unmanaged_views;
31 struct sway_view *view; 31 struct sway_view *view;
32 wl_list_for_each_reverse(view, &root_container.sway_root->unmanaged_views, 32 wl_list_for_each_reverse(view, unmanaged, unmanaged_view_link) {
33 unmanaged_view_link) {
34 if (view->type == SWAY_XWAYLAND_VIEW) { 33 if (view->type == SWAY_XWAYLAND_VIEW) {
35 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; 34 struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
36 struct wlr_box box = { 35 struct wlr_box box = {
@@ -41,24 +40,50 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
41 }; 40 };
42 41
43 if (wlr_box_contains_point(&box, cursor->x, cursor->y)) { 42 if (wlr_box_contains_point(&box, cursor->x, cursor->y)) {
44 focus = view->swayc; 43 *surface = xsurface->surface;
45 surface = xsurface->surface; 44 *sx = cursor->x - box.x;
46 sx = cursor->x - box.x; 45 *sy = cursor->y - box.y;
47 sy = cursor->y - box.y; 46 return view->swayc;
48 break;
49 } 47 }
50 } 48 }
51 } 49 }
52 50
53 // then check for managed views 51 // find the output the cursor is on
54 if (focus == NULL) { 52 struct wlr_output_layout *output_layout =
55 focus = container_at(&root_container, cursor->x, cursor->y, &surface, 53 root_container.sway_root->output_layout;
56 &sx, &sy); 54 struct wlr_output *wlr_output =
55 wlr_output_layout_output_at(output_layout, cursor->x, cursor->y);
56 if (wlr_output == NULL) {
57 return NULL;
58 }
59 struct sway_output *output = wlr_output->data;
60
61 // find the focused workspace on the output for this seat
62 struct sway_container *workspace_cont =
63 sway_seat_get_focus_inactive(cursor->seat, output->swayc);
64 if (workspace_cont != NULL && workspace_cont->type != C_WORKSPACE) {
65 workspace_cont = container_parent(workspace_cont, C_WORKSPACE);
66 }
67 if (workspace_cont == NULL) {
68 return output->swayc;
57 } 69 }
58 70
71 struct sway_container *view_cont = container_at(workspace_cont,
72 cursor->x, cursor->y, surface, sx, sy);
73 return view_cont != NULL ? view_cont : workspace_cont;
74}
75
76static void cursor_send_pointer_motion(struct sway_cursor *cursor,
77 uint32_t time) {
78 struct wlr_seat *seat = cursor->seat->wlr_seat;
79 struct wlr_surface *surface = NULL;
80 double sx, sy;
81 struct sway_container *cont =
82 container_at_cursor(cursor, &surface, &sx, &sy);
83
59 // reset cursor if switching between clients 84 // reset cursor if switching between clients
60 struct wl_client *client = NULL; 85 struct wl_client *client = NULL;
61 if (focus) { 86 if (surface != NULL) {
62 client = wl_resource_get_client(surface->resource); 87 client = wl_resource_get_client(surface->resource);
63 } 88 }
64 if (client != cursor->image_client) { 89 if (client != cursor->image_client) {
@@ -68,7 +93,7 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
68 } 93 }
69 94
70 // send pointer enter/leave 95 // send pointer enter/leave
71 if (focus) { 96 if (cont != NULL && surface != NULL) {
72 wlr_seat_pointer_notify_enter(seat, surface, sx, sy); 97 wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
73 wlr_seat_pointer_notify_motion(seat, time, sx, sy); 98 wlr_seat_pointer_notify_motion(seat, time, sx, sy);
74 } else { 99 } else {
@@ -77,8 +102,7 @@ static void cursor_send_pointer_motion(struct sway_cursor *cursor,
77} 102}
78 103
79static void handle_cursor_motion(struct wl_listener *listener, void *data) { 104static void handle_cursor_motion(struct wl_listener *listener, void *data) {
80 struct sway_cursor *cursor = 105 struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
81 wl_container_of(listener, cursor, motion);
82 struct wlr_event_pointer_motion *event = data; 106 struct wlr_event_pointer_motion *event = data;
83 wlr_cursor_move(cursor->cursor, event->device, 107 wlr_cursor_move(cursor->cursor, event->device,
84 event->delta_x, event->delta_y); 108 event->delta_x, event->delta_y);
@@ -97,17 +121,15 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener,
97} 121}
98 122
99static void handle_cursor_button(struct wl_listener *listener, void *data) { 123static void handle_cursor_button(struct wl_listener *listener, void *data) {
100 struct sway_cursor *cursor = 124 struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
101 wl_container_of(listener, cursor, button);
102 struct wlr_event_pointer_button *event = data; 125 struct wlr_event_pointer_button *event = data;
103 126
104 if (event->button == BTN_LEFT) { 127 if (event->button == BTN_LEFT) {
105 struct wlr_surface *surface = NULL; 128 struct wlr_surface *surface = NULL;
106 double sx, sy; 129 double sx, sy;
107 struct sway_container *swayc = 130 struct sway_container *cont =
108 container_at(&root_container, cursor->x, cursor->y, &surface, &sx, &sy); 131 container_at_cursor(cursor, &surface, &sx, &sy);
109 132 sway_seat_set_focus(cursor->seat, cont);
110 sway_seat_set_focus(cursor->seat, swayc);
111 } 133 }
112 134
113 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec, 135 wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, event->time_msec,
@@ -115,23 +137,20 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) {
115} 137}
116 138
117static void handle_cursor_axis(struct wl_listener *listener, void *data) { 139static void handle_cursor_axis(struct wl_listener *listener, void *data) {
118 struct sway_cursor *cursor = 140 struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);
119 wl_container_of(listener, cursor, axis);
120 struct wlr_event_pointer_axis *event = data; 141 struct wlr_event_pointer_axis *event = data;
121 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec, 142 wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
122 event->orientation, event->delta); 143 event->orientation, event->delta);
123} 144}
124 145
125static void handle_touch_down(struct wl_listener *listener, void *data) { 146static void handle_touch_down(struct wl_listener *listener, void *data) {
126 struct sway_cursor *cursor = 147 struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down);
127 wl_container_of(listener, cursor, touch_down);
128 struct wlr_event_touch_down *event = data; 148 struct wlr_event_touch_down *event = data;
129 wlr_log(L_DEBUG, "TODO: handle touch down event: %p", event); 149 wlr_log(L_DEBUG, "TODO: handle touch down event: %p", event);
130} 150}
131 151
132static void handle_touch_up(struct wl_listener *listener, void *data) { 152static void handle_touch_up(struct wl_listener *listener, void *data) {
133 struct sway_cursor *cursor = 153 struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up);
134 wl_container_of(listener, cursor, touch_up);
135 struct wlr_event_touch_up *event = data; 154 struct wlr_event_touch_up *event = data;
136 wlr_log(L_DEBUG, "TODO: handle touch up event: %p", event); 155 wlr_log(L_DEBUG, "TODO: handle touch up event: %p", event);
137} 156}
@@ -144,15 +163,13 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
144} 163}
145 164
146static void handle_tool_axis(struct wl_listener *listener, void *data) { 165static void handle_tool_axis(struct wl_listener *listener, void *data) {
147 struct sway_cursor *cursor = 166 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);
148 wl_container_of(listener, cursor, tool_axis);
149 struct wlr_event_tablet_tool_axis *event = data; 167 struct wlr_event_tablet_tool_axis *event = data;
150 wlr_log(L_DEBUG, "TODO: handle tool axis event: %p", event); 168 wlr_log(L_DEBUG, "TODO: handle tool axis event: %p", event);
151} 169}
152 170
153static void handle_tool_tip(struct wl_listener *listener, void *data) { 171static void handle_tool_tip(struct wl_listener *listener, void *data) {
154 struct sway_cursor *cursor = 172 struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip);
155 wl_container_of(listener, cursor, tool_tip);
156 struct wlr_event_tablet_tool_tip *event = data; 173 struct wlr_event_tablet_tool_tip *event = data;
157 wlr_log(L_DEBUG, "TODO: handle tool tip event: %p", event); 174 wlr_log(L_DEBUG, "TODO: handle tool tip event: %p", event);
158} 175}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 7cf0dd08..ae536264 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -8,6 +8,7 @@
8#include "sway/input/keyboard.h" 8#include "sway/input/keyboard.h"
9#include "sway/ipc-server.h" 9#include "sway/ipc-server.h"
10#include "sway/output.h" 10#include "sway/output.h"
11#include "sway/tree/container.h"
11#include "sway/tree/view.h" 12#include "sway/tree/view.h"
12#include "log.h" 13#include "log.h"
13 14
@@ -331,6 +332,9 @@ void sway_seat_set_focus(struct sway_seat *seat, struct sway_container *containe
331 if (last_ws) { 332 if (last_ws) {
332 wlr_log(L_DEBUG, "sending workspace event"); 333 wlr_log(L_DEBUG, "sending workspace event");
333 ipc_event_workspace(last_ws, container, "focus"); 334 ipc_event_workspace(last_ws, container, "focus");
335 if (last_ws->children->length == 0) {
336 container_workspace_destroy(last_ws);
337 }
334 } 338 }
335 } 339 }
336 340
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index eab6399f..7c5f7304 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -66,19 +66,42 @@ static const char *ipc_json_get_output_transform(enum wl_output_transform transf
66 66
67static void ipc_json_describe_output(struct sway_container *container, json_object *object) { 67static void ipc_json_describe_output(struct sway_container *container, json_object *object) {
68 struct wlr_output *wlr_output = container->sway_output->wlr_output; 68 struct wlr_output *wlr_output = container->sway_output->wlr_output;
69 json_object_object_add(object, "type", json_object_new_string("output")); 69 json_object_object_add(object, "type",
70 json_object_object_add(object, "active", json_object_new_boolean(true)); 70 json_object_new_string("output"));
71 json_object_object_add(object, "primary", json_object_new_boolean(false)); 71 json_object_object_add(object, "active",
72 json_object_object_add(object, "layout", json_object_new_string("output")); 72 json_object_new_boolean(true));
73 json_object_object_add(object, "make", json_object_new_string(wlr_output->make)); 73 json_object_object_add(object, "primary",
74 json_object_object_add(object, "model", json_object_new_string(wlr_output->model)); 74 json_object_new_boolean(false));
75 json_object_object_add(object, "serial", json_object_new_string(wlr_output->serial)); 75 json_object_object_add(object, "layout",
76 json_object_object_add(object, "scale", json_object_new_double(wlr_output->scale)); 76 json_object_new_string("output"));
77 json_object_object_add(object, "refresh", json_object_new_int(wlr_output->refresh)); 77 json_object_object_add(object, "make",
78 json_object_new_string(wlr_output->make));
79 json_object_object_add(object, "model",
80 json_object_new_string(wlr_output->model));
81 json_object_object_add(object, "serial",
82 json_object_new_string(wlr_output->serial));
83 json_object_object_add(object, "scale",
84 json_object_new_double(wlr_output->scale));
85 json_object_object_add(object, "refresh",
86 json_object_new_int(wlr_output->refresh));
78 json_object_object_add(object, "transform", 87 json_object_object_add(object, "transform",
79 json_object_new_string(ipc_json_get_output_transform(wlr_output->transform))); 88 json_object_new_string(
80 // TODO WLR need to set "current_workspace" to the currently focused 89 ipc_json_get_output_transform(wlr_output->transform)));
81 // workspace in a way that makes sense with multiseat 90
91 struct sway_seat *seat = sway_input_manager_get_default_seat(input_manager);
92 const char *ws = NULL;
93 if (seat) {
94 struct sway_container *focus =
95 sway_seat_get_focus_inactive(seat, container);
96 if (focus && focus->type != C_WORKSPACE) {
97 focus = container_parent(focus, C_WORKSPACE);
98 }
99 if (focus) {
100 ws = focus->name;
101 }
102 }
103 json_object_object_add(object, "current_workspace",
104 json_object_new_string(ws));
82 105
83 json_object *modes_array = json_object_new_array(); 106 json_object *modes_array = json_object_new_array();
84 struct wlr_output_mode *mode; 107 struct wlr_output_mode *mode;
@@ -95,16 +118,20 @@ static void ipc_json_describe_output(struct sway_container *container, json_obje
95 json_object_object_add(object, "modes", modes_array); 118 json_object_object_add(object, "modes", modes_array);
96} 119}
97 120
98static void ipc_json_describe_workspace(struct sway_container *workspace, json_object *object) { 121static void ipc_json_describe_workspace(struct sway_container *workspace,
99 int num = (isdigit(workspace->name[0])) ? atoi(workspace->name) : -1; 122 json_object *object) {
123 int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1;
100 124
101 json_object_object_add(object, "num", json_object_new_int(num)); 125 json_object_object_add(object, "num", json_object_new_int(num));
102 json_object_object_add(object, "output", (workspace->parent) ? json_object_new_string(workspace->parent->name) : NULL); 126 json_object_object_add(object, "output", workspace->parent ?
127 json_object_new_string(workspace->parent->name) : NULL);
103 json_object_object_add(object, "type", json_object_new_string("workspace")); 128 json_object_object_add(object, "type", json_object_new_string("workspace"));
129 json_object_object_add(object, "urgent", json_object_new_boolean(false));
104} 130}
105 131
106static void ipc_json_describe_view(struct sway_container *c, json_object *object) { 132static void ipc_json_describe_view(struct sway_container *c, json_object *object) {
107 json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); 133 json_object_object_add(object, "name",
134 c->name ? json_object_new_string(c->name) : NULL);
108} 135}
109 136
110json_object *ipc_json_describe_container(struct sway_container *c) { 137json_object *ipc_json_describe_container(struct sway_container *c) {
@@ -118,28 +145,26 @@ json_object *ipc_json_describe_container(struct sway_container *c) {
118 json_object *object = json_object_new_object(); 145 json_object *object = json_object_new_object();
119 146
120 json_object_object_add(object, "id", json_object_new_int((int)c->id)); 147 json_object_object_add(object, "id", json_object_new_int((int)c->id));
121 json_object_object_add(object, "name", (c->name) ? json_object_new_string(c->name) : NULL); 148 json_object_object_add(object, "name",
149 c->name ? json_object_new_string(c->name) : NULL);
122 json_object_object_add(object, "rect", ipc_json_create_rect(c)); 150 json_object_object_add(object, "rect", ipc_json_create_rect(c));
123 json_object_object_add(object, "focused", json_object_new_boolean(focused)); 151 json_object_object_add(object, "focused",
152 json_object_new_boolean(focused));
124 153
125 switch (c->type) { 154 switch (c->type) {
126 case C_ROOT: 155 case C_ROOT:
127 ipc_json_describe_root(c, object); 156 ipc_json_describe_root(c, object);
128 break; 157 break;
129
130 case C_OUTPUT: 158 case C_OUTPUT:
131 ipc_json_describe_output(c, object); 159 ipc_json_describe_output(c, object);
132 break; 160 break;
133
134 case C_CONTAINER: 161 case C_CONTAINER:
135 case C_VIEW: 162 case C_VIEW:
136 ipc_json_describe_view(c, object); 163 ipc_json_describe_view(c, object);
137 break; 164 break;
138
139 case C_WORKSPACE: 165 case C_WORKSPACE:
140 ipc_json_describe_workspace(c, object); 166 ipc_json_describe_workspace(c, object);
141 break; 167 break;
142
143 case C_TYPES: 168 case C_TYPES:
144 default: 169 default:
145 break; 170 break;
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 394161af..869f1ed0 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -390,7 +390,7 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
390 struct sway_seat *seat = 390 struct sway_seat *seat =
391 sway_input_manager_get_default_seat(input_manager); 391 sway_input_manager_get_default_seat(input_manager);
392 struct sway_container *focused_ws = sway_seat_get_focus(seat); 392 struct sway_container *focused_ws = sway_seat_get_focus(seat);
393 if (focused_ws->type != C_WORKSPACE) { 393 if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) {
394 focused_ws = container_parent(focused_ws, C_WORKSPACE); 394 focused_ws = container_parent(focused_ws, C_WORKSPACE);
395 } 395 }
396 bool focused = workspace == focused_ws; 396 bool focused = workspace == focused_ws;
@@ -398,6 +398,14 @@ static void ipc_get_workspaces_callback(struct sway_container *workspace,
398 json_object_object_add(workspace_json, "focused", 398 json_object_object_add(workspace_json, "focused",
399 json_object_new_boolean(focused)); 399 json_object_new_boolean(focused));
400 json_object_array_add((json_object *)data, workspace_json); 400 json_object_array_add((json_object *)data, workspace_json);
401
402 focused_ws = sway_seat_get_focus_inactive(seat, workspace->parent);
403 if (focused_ws->type != C_WORKSPACE) {
404 focused_ws = container_parent(focused_ws, C_WORKSPACE);
405 }
406 bool visible = workspace == focused_ws;
407 json_object_object_add(workspace_json, "visible",
408 json_object_new_boolean(visible));
401} 409}
402 410
403void ipc_client_handle_command(struct ipc_client *client) { 411void ipc_client_handle_command(struct ipc_client *client) {
diff --git a/sway/meson.build b/sway/meson.build
index 1e7ee7ae..e8a192f0 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -8,6 +8,7 @@ sway_sources = files(
8 'input/keyboard.c', 8 'input/keyboard.c',
9 'commands/bar.c', 9 'commands/bar.c',
10 'commands/bind.c', 10 'commands/bind.c',
11 'commands/default_orientation.c',
11 'commands/exit.c', 12 'commands/exit.c',
12 'commands/exec.c', 13 'commands/exec.c',
13 'commands/exec_always.c', 14 'commands/exec_always.c',
@@ -81,6 +82,7 @@ sway_sources = files(
81 'security.c', 82 'security.c',
82 'tree/container.c', 83 'tree/container.c',
83 'tree/layout.c', 84 'tree/layout.c',
85 'tree/output.c',
84 'tree/view.c', 86 'tree/view.c',
85 'tree/workspace.c', 87 'tree/workspace.c',
86) 88)
diff --git a/sway/server.c b/sway/server.c
index 3fba019d..728e624e 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -1,19 +1,19 @@
1#define _POSIX_C_SOURCE 200112L 1#define _POSIX_C_SOURCE 200112L
2#include <stdlib.h> 2#include <assert.h>
3#include <stdbool.h> 3#include <stdbool.h>
4#include <stdlib.h>
4#include <wayland-server.h> 5#include <wayland-server.h>
5#include <wlr/backend.h> 6#include <wlr/backend.h>
6#include <wlr/backend/session.h> 7#include <wlr/backend/session.h>
7#include <wlr/render/wlr_renderer.h> 8#include <wlr/render/wlr_renderer.h>
8#include <wlr/render/gles2.h>
9#include <wlr/types/wlr_compositor.h> 9#include <wlr/types/wlr_compositor.h>
10#include <wlr/types/wlr_gamma_control.h>
10#include <wlr/types/wlr_layer_shell.h> 11#include <wlr/types/wlr_layer_shell.h>
11#include <wlr/types/wlr_screenshooter.h> 12#include <wlr/types/wlr_screenshooter.h>
12#include <wlr/types/wlr_gamma_control.h>
13#include <wlr/types/wlr_wl_shell.h> 13#include <wlr/types/wlr_wl_shell.h>
14#include <wlr/util/log.h>
14// TODO WLR: make Xwayland optional 15// TODO WLR: make Xwayland optional
15#include <wlr/xwayland.h> 16#include <wlr/xwayland.h>
16#include <wlr/util/log.h>
17#include "sway/commands.h" 17#include "sway/commands.h"
18#include "sway/config.h" 18#include "sway/config.h"
19#include "sway/server.h" 19#include "sway/server.h"
@@ -42,11 +42,12 @@ bool server_init(struct sway_server *server) {
42 server->wl_event_loop = wl_display_get_event_loop(server->wl_display); 42 server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
43 server->backend = wlr_backend_autocreate(server->wl_display); 43 server->backend = wlr_backend_autocreate(server->wl_display);
44 44
45 server->renderer = wlr_gles2_renderer_create(server->backend); 45 struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend);
46 assert(renderer);
47
46 wl_display_init_shm(server->wl_display); 48 wl_display_init_shm(server->wl_display);
47 49
48 server->compositor = wlr_compositor_create( 50 server->compositor = wlr_compositor_create(server->wl_display, renderer);
49 server->wl_display, server->renderer);
50 server->data_device_manager = 51 server->data_device_manager =
51 wlr_data_device_manager_create(server->wl_display); 52 wlr_data_device_manager_create(server->wl_display);
52 53
@@ -95,8 +96,7 @@ bool server_init(struct sway_server *server) {
95} 96}
96 97
97void server_fini(struct sway_server *server) { 98void server_fini(struct sway_server *server) {
98 // TODO WLR: tear down more stuff 99 // TODO
99 wlr_backend_destroy(server->backend);
100} 100}
101 101
102void server_run(struct sway_server *server) { 102void server_run(struct sway_server *server) {
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 2eac812e..8705edc7 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -6,16 +6,16 @@
6#include <wayland-server.h> 6#include <wayland-server.h>
7#include <wlr/types/wlr_output_layout.h> 7#include <wlr/types/wlr_output_layout.h>
8#include <wlr/types/wlr_wl_shell.h> 8#include <wlr/types/wlr_wl_shell.h>
9#include "log.h"
9#include "sway/config.h" 10#include "sway/config.h"
10#include "sway/tree/container.h"
11#include "sway/input/input-manager.h" 11#include "sway/input/input-manager.h"
12#include "sway/input/seat.h" 12#include "sway/input/seat.h"
13#include "sway/tree/layout.h" 13#include "sway/ipc-server.h"
14#include "sway/output.h" 14#include "sway/output.h"
15#include "sway/server.h" 15#include "sway/server.h"
16#include "sway/tree/layout.h"
16#include "sway/tree/view.h" 17#include "sway/tree/view.h"
17#include "sway/tree/workspace.h" 18#include "sway/tree/workspace.h"
18#include "sway/ipc-server.h"
19#include "log.h" 19#include "log.h"
20 20
21static list_t *bfs_queue; 21static list_t *bfs_queue;
@@ -58,13 +58,14 @@ static struct sway_container *container_create(enum sway_container_type type) {
58 return c; 58 return c;
59} 59}
60 60
61static void container_destroy(struct sway_container *cont) { 61struct sway_container *container_destroy(struct sway_container *cont) {
62 if (cont == NULL) { 62 if (cont == NULL) {
63 return; 63 return NULL;
64 } 64 }
65 65
66 wl_signal_emit(&cont->events.destroy, cont); 66 wl_signal_emit(&cont->events.destroy, cont);
67 67
68 struct sway_container *parent = cont->parent;
68 if (cont->children) { 69 if (cont->children) {
69 // remove children until there are no more, container_destroy calls 70 // remove children until there are no more, container_destroy calls
70 // container_remove_child, which removes child from this container 71 // container_remove_child, which removes child from this container
@@ -77,13 +78,14 @@ static void container_destroy(struct sway_container *cont) {
77 list_foreach(cont->marks, free); 78 list_foreach(cont->marks, free);
78 list_free(cont->marks); 79 list_free(cont->marks);
79 } 80 }
80 if (cont->parent) { 81 if (parent) {
81 container_remove_child(cont); 82 parent = container_remove_child(cont);
82 } 83 }
83 if (cont->name) { 84 if (cont->name) {
84 free(cont->name); 85 free(cont->name);
85 } 86 }
86 free(cont); 87 free(cont);
88 return parent;
87} 89}
88 90
89struct sway_container *container_output_create( 91struct sway_container *container_output_create(
@@ -202,57 +204,6 @@ struct sway_container *container_view_create(struct sway_container *sibling,
202 return swayc; 204 return swayc;
203} 205}
204 206
205struct sway_container *container_output_destroy(struct sway_container *output) {
206 if (!sway_assert(output,
207 "null output passed to container_output_destroy")) {
208 return NULL;
209 }
210
211 if (output->children->length > 0) {
212 // TODO save workspaces when there are no outputs.
213 // TODO also check if there will ever be no outputs except for exiting
214 // program
215 if (root_container.children->length > 1) {
216 int p = root_container.children->items[0] == output;
217 // Move workspace from this output to another output
218 while (output->children->length) {
219 struct sway_container *child = output->children->items[0];
220 container_remove_child(child);
221 container_add_child(root_container.children->items[p], child);
222 }
223 container_sort_workspaces(root_container.children->items[p]);
224 arrange_windows(root_container.children->items[p],
225 -1, -1);
226 }
227 }
228
229 wl_list_remove(&output->sway_output->frame.link);
230 wl_list_remove(&output->sway_output->destroy.link);
231 wl_list_remove(&output->sway_output->mode.link);
232
233 wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
234 container_destroy(output);
235
236 return &root_container;
237}
238
239struct sway_container *container_view_destroy(struct sway_container *view) {
240 if (!view) {
241 return NULL;
242 }
243 wlr_log(L_DEBUG, "Destroying view '%s'", view->name);
244 struct sway_container *parent = view->parent;
245 container_destroy(view);
246
247 // TODO WLR: Destroy empty containers
248 /*
249 if (parent && parent->type == C_CONTAINER) {
250 return destroy_container(parent);
251 }
252 */
253 return parent;
254}
255
256struct sway_container *container_set_layout(struct sway_container *container, 207struct sway_container *container_set_layout(struct sway_container *container,
257 enum sway_container_layout layout) { 208 enum sway_container_layout layout) {
258 if (container->type == C_WORKSPACE) { 209 if (container->type == C_WORKSPACE) {
@@ -438,3 +389,14 @@ void container_for_each_descendant_bfs(struct sway_container *con,
438 list_cat(queue, current->children); 389 list_cat(queue, current->children);
439 } 390 }
440} 391}
392
393bool container_has_anscestor(struct sway_container *descendant,
394 struct sway_container *anscestor) {
395 while (descendant->type != C_ROOT) {
396 descendant = descendant->parent;
397 if (descendant == anscestor) {
398 return true;
399 }
400 }
401 return false;
402}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index dc0ee5b4..588ceb2d 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -9,8 +9,10 @@
9#include "sway/tree/container.h" 9#include "sway/tree/container.h"
10#include "sway/tree/layout.h" 10#include "sway/tree/layout.h"
11#include "sway/output.h" 11#include "sway/output.h"
12#include "sway/tree/workspace.h"
12#include "sway/tree/view.h" 13#include "sway/tree/view.h"
13#include "sway/input/seat.h" 14#include "sway/input/seat.h"
15#include "sway/ipc-server.h"
14#include "list.h" 16#include "list.h"
15#include "log.h" 17#include "log.h"
16 18
@@ -98,37 +100,67 @@ void container_add_child(struct sway_container *parent,
98 parent, parent->type, parent->width, parent->height); 100 parent, parent->type, parent->width, parent->height);
99 list_add(parent->children, child); 101 list_add(parent->children, child);
100 child->parent = parent; 102 child->parent = parent;
101 // set focus for this container 103}
102 /* TODO WLR 104
103 if (parent->type == C_WORKSPACE && child->type == C_VIEW && 105struct sway_container *container_reap_empty(struct sway_container *container) {
104 (parent->workspace_layout == L_TABBED || parent->workspace_layout == 106 if (!sway_assert(container, "reaping null container")) {
105 L_STACKED)) { 107 return NULL;
106 child = new_container(child, parent->workspace_layout);
107 } 108 }
108 */ 109 wlr_log(L_DEBUG, "reaping %p %s", container, container->name);
110 while (container->children->length == 0) {
111 if (container->type == C_WORKSPACE) {
112 if (!workspace_is_visible(container)) {
113 struct sway_container *parent = container->parent;
114 container_workspace_destroy(container);
115 return parent;
116 }
117 return container;
118 } else if (container->type == C_CONTAINER) {
119 struct sway_container *parent = container->parent;
120 container_destroy(container);
121 container = parent;
122 } else {
123 container = container->parent;
124 }
125 }
126 return container;
109} 127}
110 128
111struct sway_container *container_remove_child(struct sway_container *child) { 129struct sway_container *container_remove_child(struct sway_container *child) {
112 int i;
113 struct sway_container *parent = child->parent; 130 struct sway_container *parent = child->parent;
114 for (i = 0; i < parent->children->length; ++i) { 131 for (int i = 0; i < parent->children->length; ++i) {
115 if (parent->children->items[i] == child) { 132 if (parent->children->items[i] == child) {
116 list_del(parent->children, i); 133 list_del(parent->children, i);
117 break; 134 break;
118 } 135 }
119 } 136 }
120 child->parent = NULL; 137 child->parent = NULL;
121 return parent; 138 return container_reap_empty(parent);
139}
140
141void container_move_to(struct sway_container* container,
142 struct sway_container* destination) {
143 if (container == destination
144 || container_has_anscestor(container, destination)) {
145 return;
146 }
147 struct sway_container *old_parent = container_remove_child(container);
148 container->width = container->height = 0;
149 struct sway_container *new_parent =
150 container_add_sibling(destination, container);
151 if (old_parent) {
152 arrange_windows(old_parent, -1, -1);
153 }
154 arrange_windows(new_parent, -1, -1);
122} 155}
123 156
124enum sway_container_layout container_get_default_layout( 157enum sway_container_layout container_get_default_layout(
125 struct sway_container *output) { 158 struct sway_container *output) {
126 /* TODO WLR
127 if (config->default_layout != L_NONE) { 159 if (config->default_layout != L_NONE) {
128 //return config->default_layout; 160 return config->default_layout;
129 } else if (config->default_orientation != L_NONE) { 161 } else if (config->default_orientation != L_NONE) {
130 return config->default_orientation; 162 return config->default_orientation;
131 } else */if (output->width >= output->height) { 163 } else if (output->width >= output->height) {
132 return L_HORIZ; 164 return L_HORIZ;
133 } else { 165 } else {
134 return L_VERT; 166 return L_VERT;
diff --git a/sway/tree/output.c b/sway/tree/output.c
new file mode 100644
index 00000000..7248fd00
--- /dev/null
+++ b/sway/tree/output.c
@@ -0,0 +1,39 @@
1#include "sway/tree/container.h"
2#include "sway/tree/layout.h"
3#include "sway/output.h"
4#include "log.h"
5
6struct sway_container *container_output_destroy(struct sway_container *output) {
7 if (!sway_assert(output, "cannot destroy null output")) {
8 return NULL;
9 }
10
11 if (output->children->length > 0) {
12 // TODO save workspaces when there are no outputs.
13 // TODO also check if there will ever be no outputs except for exiting
14 // program
15 if (root_container.children->length > 1) {
16 int p = root_container.children->items[0] == output;
17 // Move workspace from this output to another output
18 while (output->children->length) {
19 struct sway_container *child = output->children->items[0];
20 container_remove_child(child);
21 container_add_child(root_container.children->items[p], child);
22 }
23 container_sort_workspaces(root_container.children->items[p]);
24 arrange_windows(root_container.children->items[p],
25 -1, -1);
26 }
27 }
28
29 wl_list_remove(&output->sway_output->destroy.link);
30 wl_list_remove(&output->sway_output->mode.link);
31 wl_list_remove(&output->sway_output->transform.link);
32
33 wl_list_remove(&output->sway_output->damage_destroy.link);
34 wl_list_remove(&output->sway_output->damage_frame.link);
35
36 wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name);
37 container_destroy(output);
38 return &root_container;
39}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index d5325c31..b7d1a41b 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -1,5 +1,7 @@
1#include <wayland-server.h> 1#include <wayland-server.h>
2#include <wlr/types/wlr_output_layout.h> 2#include <wlr/types/wlr_output_layout.h>
3#include "log.h"
4#include "sway/output.h"
3#include "sway/tree/container.h" 5#include "sway/tree/container.h"
4#include "sway/tree/layout.h" 6#include "sway/tree/layout.h"
5#include "sway/tree/view.h" 7#include "sway/tree/view.h"
@@ -94,3 +96,28 @@ void view_update_outputs(struct sway_view *view, const struct wlr_box *before) {
94 } 96 }
95 } 97 }
96} 98}
99
100struct sway_container *container_view_destroy(struct sway_container *view) {
101 if (!view) {
102 return NULL;
103 }
104 wlr_log(L_DEBUG, "Destroying view '%s'", view->name);
105 struct sway_container *parent = container_destroy(view);
106 arrange_windows(parent, -1, -1);
107 return parent;
108}
109
110void view_damage_whole(struct sway_view *view) {
111 struct sway_container *cont = NULL;
112 for (int i = 0; i < root_container.children->length; ++i) {
113 cont = root_container.children->items[i];
114 if (cont->type == C_OUTPUT) {
115 output_damage_whole_view(cont->sway_output, view);
116 }
117 }
118}
119
120void view_damage_from(struct sway_view *view) {
121 // TODO
122 view_damage_whole(view);
123}
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 5800ea09..c629f1f1 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -6,9 +6,10 @@
6#include <stdio.h> 6#include <stdio.h>
7#include <strings.h> 7#include <strings.h>
8#include "stringop.h" 8#include "stringop.h"
9#include "sway/tree/container.h"
10#include "sway/input/input-manager.h" 9#include "sway/input/input-manager.h"
11#include "sway/input/seat.h" 10#include "sway/input/seat.h"
11#include "sway/ipc-server.h"
12#include "sway/tree/container.h"
12#include "sway/tree/workspace.h" 13#include "sway/tree/workspace.h"
13#include "log.h" 14#include "log.h"
14#include "util.h" 15#include "util.h"
@@ -202,7 +203,48 @@ struct sway_container *workspace_create(const char *name) {
202 sway_seat_get_focus_inactive(seat, &root_container); 203 sway_seat_get_focus_inactive(seat, &root_container);
203 parent = focus; 204 parent = focus;
204 parent = container_parent(parent, C_OUTPUT); 205 parent = container_parent(parent, C_OUTPUT);
205 return container_workspace_create(parent, name); 206 struct sway_container *new_ws = container_workspace_create(parent, name);
207 ipc_event_workspace(NULL, new_ws, "init");
208 return new_ws;
209}
210
211struct sway_container *container_workspace_destroy(
212 struct sway_container *workspace) {
213 if (!sway_assert(workspace, "cannot destroy null workspace")) {
214 return NULL;
215 }
216
217 // Do not destroy this if it's the last workspace on this output
218 struct sway_container *output = container_parent(workspace, C_OUTPUT);
219 if (output && output->children->length == 1) {
220 return NULL;
221 }
222
223 struct sway_container *parent = workspace->parent;
224 if (workspace->children->length == 0) {
225 // destroy the WS if there are no children (TODO check for floating)
226 wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name);
227 ipc_event_workspace(workspace, NULL, "empty");
228 } else {
229 // Move children to a different workspace on this output
230 struct sway_container *new_workspace = NULL;
231 // TODO move floating
232 for (int i = 0; i < output->children->length; i++) {
233 if (output->children->items[i] != workspace) {
234 new_workspace = output->children->items[i];
235 break;
236 }
237 }
238
239 wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'",
240 workspace->name, new_workspace->name);
241 for (int i = 0; i < workspace->children->length; i++) {
242 container_move_to(workspace->children->items[i], new_workspace);
243 }
244 }
245
246 container_destroy(workspace);
247 return parent;
206} 248}
207 249
208/** 250/**
@@ -343,3 +385,13 @@ bool workspace_switch(struct sway_container *workspace) {
343 arrange_windows(output, -1, -1); 385 arrange_windows(output, -1, -1);
344 return true; 386 return true;
345} 387}
388
389bool workspace_is_visible(struct sway_container *ws) {
390 struct sway_container *output = container_parent(ws, C_OUTPUT);
391 struct sway_seat *seat = input_manager_current_seat(input_manager);
392 struct sway_container *focus = sway_seat_get_focus_inactive(seat, output);
393 if (focus->type != C_WORKSPACE) {
394 focus = container_parent(focus, C_WORKSPACE);
395 }
396 return focus == ws;
397}
diff --git a/swaybg/main.c b/swaybg/main.c
index f431526c..203082f6 100644
--- a/swaybg/main.c
+++ b/swaybg/main.c
@@ -300,6 +300,7 @@ int main(int argc, const char **argv) {
300 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | 300 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
301 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | 301 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
302 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); 302 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
303 zwlr_layer_surface_v1_set_exclusive_zone(state.layer_surface, -1);
303 zwlr_layer_surface_v1_add_listener(state.layer_surface, 304 zwlr_layer_surface_v1_add_listener(state.layer_surface,
304 &layer_surface_listener, &state); 305 &layer_surface_listener, &state);
305 state.run_display = true; 306 state.run_display = true;