aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-04-07 11:53:10 -0400
committerLibravatar GitHub <noreply@github.com>2018-04-07 11:53:10 -0400
commitc47b4d4edb7714612ec7236fafda5ca54cb92ce4 (patch)
tree9a7f991e9c3da20351b58c53e0b6dbe376f12dca
parentMerge pull request #1700 from swaywm/move-cmd-full (diff)
parentDamage all surfaces when damaging whole container (diff)
downloadsway-c47b4d4edb7714612ec7236fafda5ca54cb92ce4.tar.gz
sway-c47b4d4edb7714612ec7236fafda5ca54cb92ce4.tar.zst
sway-c47b4d4edb7714612ec7236fafda5ca54cb92ce4.zip
Merge pull request #1756 from emersion/output-damage
Fine-grained damage tracking
-rw-r--r--include/sway/desktop.h7
-rw-r--r--include/sway/output.h8
-rw-r--r--include/sway/tree/view.h4
-rw-r--r--sway/commands/opacity.c5
-rw-r--r--sway/desktop/desktop.c14
-rw-r--r--sway/desktop/layer_shell.c44
-rw-r--r--sway/desktop/output.c439
-rw-r--r--sway/desktop/wl_shell.c2
-rw-r--r--sway/desktop/xdg_shell_v6.c26
-rw-r--r--sway/desktop/xwayland.c18
-rw-r--r--sway/tree/view.c27
11 files changed, 332 insertions, 262 deletions
diff --git a/include/sway/desktop.h b/include/sway/desktop.h
index 96bdc94c..f1ad759a 100644
--- a/include/sway/desktop.h
+++ b/include/sway/desktop.h
@@ -1,7 +1,4 @@
1#include <wlr/types/wlr_surface.h> 1#include <wlr/types/wlr_surface.h>
2 2
3void desktop_damage_whole_surface(struct wlr_surface *surface, double lx, 3void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
4 double ly); 4 bool whole);
5
6void desktop_damage_from_surface(struct wlr_surface *surface, double lx,
7 double ly);
diff --git a/include/sway/output.h b/include/sway/output.h
index 4bffa2b7..56571548 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -34,11 +34,11 @@ struct sway_output {
34 34
35void output_damage_whole(struct sway_output *output); 35void output_damage_whole(struct sway_output *output);
36 36
37void output_damage_whole_surface(struct sway_output *output, 37void output_damage_surface(struct sway_output *output, double ox, double oy,
38 double ox, double oy, struct wlr_surface *surface); 38 struct wlr_surface *surface, bool whole);
39 39
40void output_damage_whole_view(struct sway_output *output, 40void output_damage_view(struct sway_output *output, struct sway_view *view,
41 struct sway_view *view); 41 bool whole);
42 42
43void output_damage_whole_container(struct sway_output *output, 43void output_damage_whole_container(struct sway_output *output,
44 struct sway_container *con); 44 struct sway_container *con);
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h
index 611c4f0b..b51c54b5 100644
--- a/include/sway/tree/view.h
+++ b/include/sway/tree/view.h
@@ -157,9 +157,7 @@ void view_set_activated(struct sway_view *view, bool activated);
157 157
158void view_close(struct sway_view *view); 158void view_close(struct sway_view *view);
159 159
160void view_damage_whole(struct sway_view *view); 160void view_damage(struct sway_view *view, bool whole);
161
162void view_damage_from(struct sway_view *view);
163 161
164void view_for_each_surface(struct sway_view *view, 162void view_for_each_surface(struct sway_view *view,
165 wlr_surface_iterator_func_t iterator, void *user_data); 163 wlr_surface_iterator_func_t iterator, void *user_data);
diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c
index b8cd1f09..68fd9f42 100644
--- a/sway/commands/opacity.c
+++ b/sway/commands/opacity.c
@@ -30,10 +30,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
30 } 30 }
31 31
32 con->alpha = opacity; 32 con->alpha = opacity;
33 33 container_damage_whole(con);
34 if (con->type == C_VIEW) {
35 view_damage_whole(con->sway_view);
36 }
37 34
38 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 35 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
39} 36}
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c
index 3a13191f..66f33151 100644
--- a/sway/desktop/desktop.c
+++ b/sway/desktop/desktop.c
@@ -2,19 +2,13 @@
2#include "sway/desktop.h" 2#include "sway/desktop.h"
3#include "sway/output.h" 3#include "sway/output.h"
4 4
5void desktop_damage_whole_surface(struct wlr_surface *surface, double lx, 5void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
6 double ly) { 6 bool whole) {
7 for (int i = 0; i < root_container.children->length; ++i) { 7 for (int i = 0; i < root_container.children->length; ++i) {
8 struct sway_container *cont = root_container.children->items[i]; 8 struct sway_container *cont = root_container.children->items[i];
9 if (cont->type == C_OUTPUT) { 9 if (cont->type == C_OUTPUT) {
10 output_damage_whole_surface(cont->sway_output, 10 output_damage_surface(cont->sway_output, lx - cont->x, ly - cont->y,
11 lx - cont->x, ly - cont->y, surface); 11 surface, whole);
12 } 12 }
13 } 13 }
14} 14}
15
16void desktop_damage_from_surface(struct wlr_surface *surface, double lx,
17 double ly) {
18 // TODO
19 desktop_damage_whole_surface(surface, lx, ly);
20}
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 663ec7ba..f841e5f1 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -229,33 +229,39 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
229 wl_container_of(listener, layer, surface_commit); 229 wl_container_of(listener, layer, surface_commit);
230 struct wlr_layer_surface *layer_surface = layer->layer_surface; 230 struct wlr_layer_surface *layer_surface = layer->layer_surface;
231 struct wlr_output *wlr_output = layer_surface->output; 231 struct wlr_output *wlr_output = layer_surface->output;
232 if (wlr_output != NULL) { 232 if (wlr_output == NULL) {
233 struct sway_output *output = wlr_output->data; 233 return;
234 struct wlr_box old_geo = layer->geo; 234 }
235 arrange_layers(output); 235
236 if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) { 236 struct sway_output *output = wlr_output->data;
237 // TODO DAMAGE apply whole surface from previous and new geos 237 struct wlr_box old_geo = layer->geo;
238 } else { 238 arrange_layers(output);
239 // TODO DAMAGE from surface damage 239 if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) {
240 } 240 output_damage_surface(output, old_geo.x, old_geo.y,
241 wlr_output_damage_add_box(output->damage, &old_geo); 241 layer_surface->surface, true);
242 wlr_output_damage_add_box(output->damage, &layer->geo); 242 output_damage_surface(output, layer->geo.x, layer->geo.y,
243 layer_surface->surface, true);
244 } else {
245 output_damage_surface(output, layer->geo.x, layer->geo.y,
246 layer_surface->surface, false);
243 } 247 }
244} 248}
245 249
246static void unmap(struct sway_layer_surface *sway_layer) { 250static void unmap(struct sway_layer_surface *sway_layer) {
247 struct wlr_output *wlr_output = sway_layer->layer_surface->output; 251 struct wlr_output *wlr_output = sway_layer->layer_surface->output;
248 if (wlr_output != NULL) { 252 if (wlr_output == NULL) {
249 struct sway_output *output = wlr_output->data; 253 return;
250 wlr_output_damage_add_box(output->damage, &sway_layer->geo);
251 } 254 }
255 struct sway_output *output = wlr_output->data;
256 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
257 sway_layer->layer_surface->surface, true);
252} 258}
253 259
254static void handle_destroy(struct wl_listener *listener, void *data) { 260static void handle_destroy(struct wl_listener *listener, void *data) {
255 struct sway_layer_surface *sway_layer = wl_container_of(listener, 261 struct sway_layer_surface *sway_layer =
256 sway_layer, destroy); 262 wl_container_of(listener, sway_layer, destroy);
257 wlr_log(L_DEBUG, "Layer surface destroyed (%s)", 263 wlr_log(L_DEBUG, "Layer surface destroyed (%s)",
258 sway_layer->layer_surface->namespace); 264 sway_layer->layer_surface->namespace);
259 if (sway_layer->layer_surface->mapped) { 265 if (sway_layer->layer_surface->mapped) {
260 unmap(sway_layer); 266 unmap(sway_layer);
261 } 267 }
@@ -277,7 +283,9 @@ static void handle_map(struct wl_listener *listener, void *data) {
277 struct sway_layer_surface *sway_layer = wl_container_of(listener, 283 struct sway_layer_surface *sway_layer = wl_container_of(listener,
278 sway_layer, map); 284 sway_layer, map);
279 struct sway_output *output = sway_layer->layer_surface->output->data; 285 struct sway_output *output = sway_layer->layer_surface->output->data;
280 wlr_output_damage_add_box(output->damage, &sway_layer->geo); 286 output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
287 sway_layer->layer_surface->surface, true);
288 // TODO: send enter to subsurfaces and popups
281 wlr_surface_send_enter(sway_layer->layer_surface->surface, 289 wlr_surface_send_enter(sway_layer->layer_surface->surface,
282 sway_layer->layer_surface->output); 290 sway_layer->layer_surface->output);
283} 291}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index ad777796..23d20b79 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -1,8 +1,8 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 2#include <assert.h>
3#include <stdlib.h> 3#include <stdlib.h>
4#include <time.h>
5#include <strings.h> 4#include <strings.h>
5#include <time.h>
6#include <wayland-server.h> 6#include <wayland-server.h>
7#include <wlr/render/wlr_renderer.h> 7#include <wlr/render/wlr_renderer.h>
8#include <wlr/types/wlr_box.h> 8#include <wlr/types/wlr_box.h>
@@ -12,6 +12,7 @@
12#include <wlr/types/wlr_output.h> 12#include <wlr/types/wlr_output.h>
13#include <wlr/types/wlr_surface.h> 13#include <wlr/types/wlr_surface.h>
14#include <wlr/types/wlr_wl_shell.h> 14#include <wlr/types/wlr_wl_shell.h>
15#include <wlr/util/region.h>
15#include "log.h" 16#include "log.h"
16#include "sway/input/input-manager.h" 17#include "sway/input/input-manager.h"
17#include "sway/input/seat.h" 18#include "sway/input/seat.h"
@@ -38,191 +39,201 @@ struct sway_container *output_by_name(const char *name) {
38 */ 39 */
39static void rotate_child_position(double *sx, double *sy, double sw, double sh, 40static void rotate_child_position(double *sx, double *sy, double sw, double sh,
40 double pw, double ph, float rotation) { 41 double pw, double ph, float rotation) {
41 if (rotation != 0.0) { 42 if (rotation == 0.0f) {
42 // Coordinates relative to the center of the subsurface 43 return;
43 double ox = *sx - pw/2 + sw/2,
44 oy = *sy - ph/2 + sh/2;
45 // Rotated coordinates
46 double rx = cos(-rotation)*ox - sin(-rotation)*oy,
47 ry = cos(-rotation)*oy + sin(-rotation)*ox;
48 *sx = rx + pw/2 - sw/2;
49 *sy = ry + ph/2 - sh/2;
50 } 44 }
45
46 // Coordinates relative to the center of the subsurface
47 double ox = *sx - pw/2 + sw/2,
48 oy = *sy - ph/2 + sh/2;
49 // Rotated coordinates
50 double rx = cos(-rotation)*ox - sin(-rotation)*oy,
51 ry = cos(-rotation)*oy + sin(-rotation)*ox;
52 *sx = rx + pw/2 - sw/2;
53 *sy = ry + ph/2 - sh/2;
51} 54}
52 55
53/** 56/**
54 * Checks whether a surface at (lx, ly) intersects an output. If `box` is not 57 * Contains a surface's root geometry information. For instance, when rendering
55 * NULL, it populates it with the surface box in the output, in output-local 58 * a popup, this will contain the parent view's position and size.
56 * coordinates.
57 */ 59 */
58static bool surface_intersect_output(struct wlr_surface *surface, 60struct root_geometry {
59 struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, 61 double x, y;
60 double ox, double oy, float rotation, struct wlr_box *box) { 62 int width, height;
61 if (box != NULL) { 63 float rotation;
62 box->x = ox * wlr_output->scale; 64};
63 box->y = oy * wlr_output->scale; 65
64 box->width = surface->current->width * wlr_output->scale; 66static bool get_surface_box(struct root_geometry *geo,
65 box->height = surface->current->height * wlr_output->scale; 67 struct sway_output *output, struct wlr_surface *surface, int sx, int sy,
68 struct wlr_box *surface_box) {
69 int sw = surface->current->width;
70 int sh = surface->current->height;
71
72 double _sx = sx, _sy = sy;
73 rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height,
74 geo->rotation);
75
76 struct wlr_box box = {
77 .x = geo->x + _sx,
78 .y = geo->y + _sy,
79 .width = sw,
80 .height = sh,
81 };
82 if (surface_box != NULL) {
83 memcpy(surface_box, &box, sizeof(struct wlr_box));
66 } 84 }
67 85
68 struct wlr_box layout_box = { 86 struct wlr_box rotated_box;
69 .x = wlr_output->lx + ox, .y = wlr_output->ly + oy, 87 wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box);
70 .width = surface->current->width, .height = surface->current->height, 88
89 struct wlr_box output_box = {
90 .width = output->swayc->width,
91 .height = output->swayc->height,
71 }; 92 };
72 wlr_box_rotated_bounds(&layout_box, rotation, &layout_box); 93
73 return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); 94 struct wlr_box intersection;
95 return wlr_box_intersection(&output_box, &rotated_box, &intersection);
74} 96}
75 97
76static void render_surface(struct wlr_surface *surface, 98static void output_surface_for_each_surface(struct wlr_surface *surface,
77 struct wlr_output *wlr_output, struct timespec *when, 99 double ox, double oy, struct root_geometry *geo,
78 double ox, double oy, float rotation, float alpha) { 100 wlr_surface_iterator_func_t iterator, void *user_data) {
79 struct wlr_renderer *renderer = 101 geo->x = ox;
80 wlr_backend_get_renderer(wlr_output->backend); 102 geo->y = oy;
103 geo->width = surface->current->width;
104 geo->height = surface->current->height;
105 geo->rotation = 0;
106
107 wlr_surface_for_each_surface(surface, iterator, user_data);
108}
109
110static void output_view_for_each_surface(struct sway_view *view,
111 struct root_geometry *geo, wlr_surface_iterator_func_t iterator,
112 void *user_data) {
113 geo->x = view->swayc->x;
114 geo->y = view->swayc->y;
115 geo->width = view->surface->current->width;
116 geo->height = view->surface->current->height;
117 geo->rotation = 0; // TODO
118
119 view_for_each_surface(view, iterator, user_data);
120}
121
122static void scale_box(struct wlr_box *box, float scale) {
123 box->x *= scale;
124 box->y *= scale;
125 box->width *= scale;
126 box->height *= scale;
127}
128
129struct render_data {
130 struct root_geometry root_geo;
131 struct sway_output *output;
132 struct timespec *when;
133 float alpha;
134};
135
136static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy,
137 void *_data) {
138 struct render_data *data = _data;
139 struct wlr_output *wlr_output = data->output->wlr_output;
140 struct timespec *when = data->when;
141 float rotation = data->root_geo.rotation;
142 float alpha = data->alpha;
81 143
82 if (!wlr_surface_has_buffer(surface)) { 144 if (!wlr_surface_has_buffer(surface)) {
83 return; 145 return;
84 } 146 }
85 147
86 struct wlr_output_layout *layout = root_container.sway_root->output_layout;
87
88 struct wlr_box box; 148 struct wlr_box box;
89 bool intersects = surface_intersect_output(surface, layout, wlr_output, 149 bool intersects = get_surface_box(&data->root_geo, data->output, surface,
90 ox, oy, rotation, &box); 150 sx, sy, &box);
91 if (intersects) { 151 if (!intersects) {
92 float matrix[9]; 152 return;
93 enum wl_output_transform transform =
94 wlr_output_transform_invert(surface->current->transform);
95 wlr_matrix_project_box(matrix, &box, transform, rotation,
96 wlr_output->transform_matrix);
97
98 wlr_render_texture_with_matrix(renderer, surface->texture,
99 matrix, alpha);
100
101 wlr_surface_send_frame_done(surface, when);
102 } 153 }
103 154
104 struct wlr_subsurface *subsurface; 155 struct wlr_renderer *renderer =
105 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { 156 wlr_backend_get_renderer(wlr_output->backend);
106 struct wlr_surface_state *state = subsurface->surface->current; 157 if (!sway_assert(renderer != NULL,
107 double sx = state->subsurface_position.x; 158 "expected the output backend to have a renderer")) {
108 double sy = state->subsurface_position.y; 159 return;
109 rotate_child_position(&sx, &sy, state->width, state->height,
110 surface->current->width, surface->current->height, rotation);
111
112 render_surface(subsurface->surface, wlr_output, when,
113 ox + sx, oy + sy, rotation, alpha);
114 } 160 }
161
162 scale_box(&box, wlr_output->scale);
163
164 float matrix[9];
165 enum wl_output_transform transform =
166 wlr_output_transform_invert(surface->current->transform);
167 wlr_matrix_project_box(matrix, &box, transform, rotation,
168 wlr_output->transform_matrix);
169
170 wlr_render_texture_with_matrix(renderer, surface->texture,
171 matrix, alpha);
172
173 // TODO: don't send the frame done event now
174 wlr_surface_send_frame_done(surface, when);
115} 175}
116 176
117static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, 177static void render_surface(struct sway_output *output, struct timespec *when,
118 struct wlr_output *wlr_output, struct timespec *when, double base_x, 178 struct wlr_surface *surface, double ox, double oy) {
119 double base_y, float rotation, float alpha) { 179 struct render_data data = {
120 double width = surface->surface->current->width; 180 .output = output,
121 double height = surface->surface->current->height; 181 .when = when,
122 182 .alpha = 1.0f,
123 struct wlr_xdg_popup_v6 *popup_state; 183 };
124 wl_list_for_each(popup_state, &surface->popups, link) {
125 struct wlr_xdg_surface_v6 *popup = popup_state->base;
126 if (!popup->configured) {
127 continue;
128 }
129 184
130 double popup_width = popup->surface->current->width; 185 output_surface_for_each_surface(surface, ox, oy, &data.root_geo,
131 double popup_height = popup->surface->current->height; 186 render_surface_iterator, &data);
187}
132 188
133 double popup_sx, popup_sy; 189static void render_view(struct sway_output *output, struct timespec *when,
134 wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); 190 struct sway_view *view) {
135 rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, 191 struct render_data data = {
136 width, height, rotation); 192 .output = output,
193 .when = when,
194 .alpha = view->swayc->alpha,
195 };
137 196
138 render_surface(popup->surface, wlr_output, when, 197 output_view_for_each_surface(view, &data.root_geo,
139 base_x + popup_sx, base_y + popup_sy, rotation, alpha); 198 render_surface_iterator, &data);
140 render_xdg_v6_popups(popup, wlr_output, when,
141 base_x + popup_sx, base_y + popup_sy, rotation, alpha);
142 }
143} 199}
144 200
145static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, 201static void render_layer(struct sway_output *output, struct timespec *when,
146 struct wlr_output *wlr_output, struct timespec *when, 202 struct wl_list *layer_surfaces) {
147 double lx, double ly, float rotation, float alpha, 203 struct sway_layer_surface *layer_surface;
148 bool is_child) { 204 wl_list_for_each(layer_surface, layer_surfaces, link) {
149 if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { 205 struct wlr_layer_surface *wlr_layer_surface =
150 render_surface(surface->surface, wlr_output, when, 206 layer_surface->layer_surface;
151 lx, ly, rotation, alpha); 207 render_surface(output, when, wlr_layer_surface->surface,
152 208 layer_surface->geo.x, layer_surface->geo.y);
153 double width = surface->surface->current->width;
154 double height = surface->surface->current->height;
155
156 struct wlr_wl_shell_surface *popup;
157 wl_list_for_each(popup, &surface->popups, popup_link) {
158 double popup_width = popup->surface->current->width;
159 double popup_height = popup->surface->current->height;
160
161 double popup_x = popup->transient_state->x;
162 double popup_y = popup->transient_state->y;
163 rotate_child_position(&popup_x, &popup_y, popup_width, popup_height,
164 width, height, rotation);
165
166 render_wl_shell_surface(popup, wlr_output, when,
167 lx + popup_x, ly + popup_y, rotation, alpha, true);
168 }
169 } 209 }
170} 210}
171 211
172struct render_data { 212struct render_view_data {
173 struct sway_output *output; 213 struct sway_output *output;
174 struct timespec *when; 214 struct timespec *when;
175}; 215};
176 216
177static void render_view(struct sway_container *view, void *data) { 217static void render_view_iterator(struct sway_container *con, void *_data) {
178 struct render_data *rdata = data; 218 struct render_view_data *data = _data;
179 struct sway_output *output = rdata->output;
180 struct timespec *when = rdata->when;
181 struct wlr_output *wlr_output = output->wlr_output;
182 struct sway_view *sway_view = view->sway_view;
183 struct wlr_surface *surface = sway_view->surface;
184 float alpha = sway_view->swayc->alpha;
185 219
186 if (!surface) { 220 if (!sway_assert(con->type == C_VIEW, "expected a view")) {
187 return; 221 return;
188 } 222 }
189 223
190 switch (sway_view->type) { 224 render_view(data->output, data->when, con->sway_view);
191 case SWAY_VIEW_XDG_SHELL_V6: {
192 int window_offset_x = view->sway_view->wlr_xdg_surface_v6->geometry.x;
193 int window_offset_y = view->sway_view->wlr_xdg_surface_v6->geometry.y;
194 render_surface(surface, wlr_output, when,
195 view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
196 render_xdg_v6_popups(sway_view->wlr_xdg_surface_v6, wlr_output,
197 when, view->x - window_offset_x, view->y - window_offset_y, 0, alpha);
198 break;
199 }
200 case SWAY_VIEW_WL_SHELL:
201 render_wl_shell_surface(sway_view->wlr_wl_shell_surface, wlr_output,
202 when, view->x, view->y, 0, alpha, false);
203 break;
204 case SWAY_VIEW_XWAYLAND:
205 render_surface(surface, wlr_output, when, view->x, view->y, 0, alpha);
206 break;
207 }
208}
209
210static void render_layer(struct sway_output *output, struct timespec *when,
211 struct wl_list *layer) {
212 struct sway_layer_surface *sway_layer;
213 wl_list_for_each(sway_layer, layer, link) {
214 struct wlr_layer_surface *layer = sway_layer->layer_surface;
215 render_surface(layer->surface, output->wlr_output, when,
216 sway_layer->geo.x, sway_layer->geo.y, 0, 1.0f);
217 wlr_surface_send_frame_done(layer->surface, when);
218 }
219} 225}
220 226
221static void render_output(struct sway_output *output, struct timespec *when, 227static void render_output(struct sway_output *output, struct timespec *when,
222 pixman_region32_t *damage) { 228 pixman_region32_t *damage) {
223 struct wlr_output *wlr_output = output->wlr_output; 229 struct wlr_output *wlr_output = output->wlr_output;
230
224 struct wlr_renderer *renderer = 231 struct wlr_renderer *renderer =
225 wlr_backend_get_renderer(wlr_output->backend); 232 wlr_backend_get_renderer(wlr_output->backend);
233 if (!sway_assert(renderer != NULL,
234 "expected the output backend to have a renderer")) {
235 return;
236 }
226 237
227 wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); 238 wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
228 239
@@ -231,7 +242,7 @@ static void render_output(struct sway_output *output, struct timespec *when,
231 goto renderer_end; 242 goto renderer_end;
232 } 243 }
233 244
234 // TODO: don't damage the whole output here 245 // TODO: don't damage the whole output
235 int width, height; 246 int width, height;
236 wlr_output_transformed_resolution(wlr_output, &width, &height); 247 wlr_output_transformed_resolution(wlr_output, &width, &height);
237 pixman_region32_union_rect(damage, damage, 0, 0, width, height); 248 pixman_region32_union_rect(damage, damage, 0, 0, width, height);
@@ -239,16 +250,12 @@ static void render_output(struct sway_output *output, struct timespec *when,
239 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; 250 float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f};
240 wlr_renderer_clear(renderer, clear_color); 251 wlr_renderer_clear(renderer, clear_color);
241 252
242 struct wlr_output_layout *output_layout =
243 root_container.sway_root->output_layout;
244 const struct wlr_box *output_box =
245 wlr_output_layout_get_box(output_layout, wlr_output);
246
247 render_layer(output, when, 253 render_layer(output, when,
248 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); 254 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]);
249 render_layer(output, when, 255 render_layer(output, when,
250 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); 256 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
251 257
258 // Render all views in the current workspace
252 struct sway_seat *seat = input_manager_current_seat(input_manager); 259 struct sway_seat *seat = input_manager_current_seat(input_manager);
253 struct sway_container *focus = 260 struct sway_container *focus =
254 seat_get_focus_inactive(seat, output->swayc); 261 seat_get_focus_inactive(seat, output->swayc);
@@ -258,36 +265,21 @@ static void render_output(struct sway_output *output, struct timespec *when,
258 } 265 }
259 struct sway_container *workspace = focus->type == C_WORKSPACE ? 266 struct sway_container *workspace = focus->type == C_WORKSPACE ?
260 focus : container_parent(focus, C_WORKSPACE); 267 focus : container_parent(focus, C_WORKSPACE);
268 struct render_view_data data = { .output = output, .when = when };
269 container_descendants(workspace, C_VIEW, render_view_iterator, &data);
261 270
262 struct render_data rdata = { 271 // Render unmanaged views on top
263 .output = output,
264 .when = when,
265 };
266 container_descendants(workspace, C_VIEW, render_view, &rdata);
267
268 // render unmanaged views on top
269 struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; 272 struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged;
270 struct sway_xwayland_unmanaged *unmanaged_surface; 273 struct sway_xwayland_unmanaged *unmanaged_surface;
271 wl_list_for_each(unmanaged_surface, unmanaged, link) { 274 wl_list_for_each(unmanaged_surface, unmanaged, link) {
272 struct wlr_xwayland_surface *xsurface = 275 struct wlr_xwayland_surface *xsurface =
273 unmanaged_surface->wlr_xwayland_surface; 276 unmanaged_surface->wlr_xwayland_surface;
274 277 double ox = unmanaged_surface->lx - output->swayc->x;
275 const struct wlr_box view_box = { 278 double oy = unmanaged_surface->ly - output->swayc->y;
276 .x = unmanaged_surface->lx, 279 render_surface(output, when, xsurface->surface, ox, oy);
277 .y = unmanaged_surface->ly,
278 .width = xsurface->width,
279 .height = xsurface->height,
280 };
281 struct wlr_box intersection;
282 if (!wlr_box_intersection(&view_box, output_box, &intersection)) {
283 continue;
284 }
285
286 render_surface(xsurface->surface, wlr_output, &output->last_frame,
287 view_box.x - output_box->x, view_box.y - output_box->y, 0, 1.0f);
288 } 280 }
289 281
290 // TODO: Consider revising this when fullscreen windows are supported 282 // TODO: consider revising this when fullscreen windows are supported
291 render_layer(output, when, 283 render_layer(output, when,
292 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); 284 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
293 render_layer(output, when, 285 render_layer(output, when,
@@ -337,22 +329,107 @@ void output_damage_whole(struct sway_output *output) {
337 wlr_output_damage_add_whole(output->damage); 329 wlr_output_damage_add_whole(output->damage);
338} 330}
339 331
340void output_damage_whole_surface(struct sway_output *output, 332struct damage_data {
341 double ox, double oy, struct wlr_surface *surface) { 333 struct root_geometry root_geo;
342 // TODO 334 struct sway_output *output;
343 output_damage_whole(output); 335 bool whole;
336};
337
338static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy,
339 void *_data) {
340 struct damage_data *data = _data;
341 struct sway_output *output = data->output;
342 float rotation = data->root_geo.rotation;
343 bool whole = data->whole;
344
345 if (!wlr_surface_has_buffer(surface)) {
346 return;
347 }
348
349 struct wlr_box box;
350 bool intersects = get_surface_box(&data->root_geo, data->output, surface,
351 sx, sy, &box);
352 if (!intersects) {
353 return;
354 }
355
356 scale_box(&box, output->wlr_output->scale);
357
358 if (whole) {
359 wlr_box_rotated_bounds(&box, rotation, &box);
360 wlr_output_damage_add_box(output->damage, &box);
361 } else {
362 int center_x = box.x + box.width/2;
363 int center_y = box.y + box.height/2;
364
365 pixman_region32_t damage;
366 pixman_region32_init(&damage);
367 pixman_region32_copy(&damage, &surface->current->surface_damage);
368 wlr_region_scale(&damage, &damage, output->wlr_output->scale);
369 if (ceil(output->wlr_output->scale) > surface->current->scale) {
370 // When scaling up a surface, it'll become blurry so we need to
371 // expand the damage region
372 wlr_region_expand(&damage, &damage,
373 ceil(output->wlr_output->scale) - surface->current->scale);
374 }
375 pixman_region32_translate(&damage, box.x, box.y);
376 wlr_region_rotated_bounds(&damage, &damage, rotation,
377 center_x, center_y);
378 wlr_output_damage_add(output->damage, &damage);
379 pixman_region32_fini(&damage);
380 }
381}
382
383void output_damage_surface(struct sway_output *output, double ox, double oy,
384 struct wlr_surface *surface, bool whole) {
385 struct damage_data data = {
386 .output = output,
387 .whole = whole,
388 };
389
390 output_surface_for_each_surface(surface, ox, oy, &data.root_geo,
391 damage_surface_iterator, &data);
344} 392}
345 393
346void output_damage_whole_view(struct sway_output *output, 394void output_damage_view(struct sway_output *output, struct sway_view *view,
347 struct sway_view *view) { 395 bool whole) {
348 // TODO 396 if (!sway_assert(view->swayc != NULL, "expected a view in the tree")) {
349 output_damage_whole(output); 397 return;
398 }
399
400 struct damage_data data = {
401 .output = output,
402 .whole = whole,
403 };
404
405 output_view_for_each_surface(view, &data.root_geo,
406 damage_surface_iterator, &data);
407}
408
409static void output_damage_whole_container_iterator(struct sway_container *con,
410 void *data) {
411 struct sway_output *output = data;
412
413 if (!sway_assert(con->type != C_VIEW, "expected a view")) {
414 return;
415 }
416
417 output_damage_view(output, con->sway_view, true);
350} 418}
351 419
352void output_damage_whole_container(struct sway_output *output, 420void output_damage_whole_container(struct sway_output *output,
353 struct sway_container *con) { 421 struct sway_container *con) {
354 // TODO 422 float scale = output->wlr_output->scale;
355 output_damage_whole(output); 423 struct wlr_box box = {
424 .x = con->x * scale,
425 .y = con->y * scale,
426 .width = con->width * scale,
427 .height = con->height * scale,
428 };
429 wlr_output_damage_add_box(output->damage, &box);
430
431 container_descendants(con, C_VIEW, output_damage_whole_container_iterator,
432 output);
356} 433}
357 434
358static void damage_handle_destroy(struct wl_listener *listener, void *data) { 435static void damage_handle_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/wl_shell.c b/sway/desktop/wl_shell.c
index fff31da8..b63c220c 100644
--- a/sway/desktop/wl_shell.c
+++ b/sway/desktop/wl_shell.c
@@ -79,7 +79,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
79 // TODO: Let floating views do whatever 79 // TODO: Let floating views do whatever
80 view_update_size(view, wl_shell_view->pending_width, 80 view_update_size(view, wl_shell_view->pending_width,
81 wl_shell_view->pending_height); 81 wl_shell_view->pending_height);
82 view_damage_from(view); 82 view_damage(view, false);
83} 83}
84 84
85static void handle_destroy(struct wl_listener *listener, void *data) { 85static 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 8361aab3..e4703040 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -143,9 +143,7 @@ static void destroy(struct sway_view *view) {
143 if (xdg_shell_v6_view == NULL) { 143 if (xdg_shell_v6_view == NULL) {
144 return; 144 return;
145 } 145 }
146 wl_list_remove(&xdg_shell_v6_view->commit.link);
147 wl_list_remove(&xdg_shell_v6_view->destroy.link); 146 wl_list_remove(&xdg_shell_v6_view->destroy.link);
148 wl_list_remove(&xdg_shell_v6_view->new_popup.link);
149 wl_list_remove(&xdg_shell_v6_view->map.link); 147 wl_list_remove(&xdg_shell_v6_view->map.link);
150 wl_list_remove(&xdg_shell_v6_view->unmap.link); 148 wl_list_remove(&xdg_shell_v6_view->unmap.link);
151 free(xdg_shell_v6_view); 149 free(xdg_shell_v6_view);
@@ -169,7 +167,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
169 // TODO: Let floating views do whatever 167 // TODO: Let floating views do whatever
170 view_update_size(view, xdg_shell_v6_view->pending_width, 168 view_update_size(view, xdg_shell_v6_view->pending_width,
171 xdg_shell_v6_view->pending_height); 169 xdg_shell_v6_view->pending_height);
172 view_damage_from(view); 170 view_damage(view, false);
173} 171}
174 172
175static void handle_new_popup(struct wl_listener *listener, void *data) { 173static void handle_new_popup(struct wl_listener *listener, void *data) {
@@ -182,14 +180,28 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
182static void handle_unmap(struct wl_listener *listener, void *data) { 180static void handle_unmap(struct wl_listener *listener, void *data) {
183 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 181 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
184 wl_container_of(listener, xdg_shell_v6_view, unmap); 182 wl_container_of(listener, xdg_shell_v6_view, unmap);
183
185 view_unmap(&xdg_shell_v6_view->view); 184 view_unmap(&xdg_shell_v6_view->view);
185
186 wl_list_remove(&xdg_shell_v6_view->commit.link);
187 wl_list_remove(&xdg_shell_v6_view->new_popup.link);
186} 188}
187 189
188static void handle_map(struct wl_listener *listener, void *data) { 190static void handle_map(struct wl_listener *listener, void *data) {
189 struct sway_xdg_shell_v6_view *xdg_shell_v6_view = 191 struct sway_xdg_shell_v6_view *xdg_shell_v6_view =
190 wl_container_of(listener, xdg_shell_v6_view, map); 192 wl_container_of(listener, xdg_shell_v6_view, map);
191 struct sway_view *view = &xdg_shell_v6_view->view; 193 struct sway_view *view = &xdg_shell_v6_view->view;
194 struct wlr_xdg_surface_v6 *xdg_surface = view->wlr_xdg_surface_v6;
195
192 view_map(view, view->wlr_xdg_surface_v6->surface); 196 view_map(view, view->wlr_xdg_surface_v6->surface);
197
198 xdg_shell_v6_view->commit.notify = handle_commit;
199 wl_signal_add(&xdg_surface->surface->events.commit,
200 &xdg_shell_v6_view->commit);
201
202 xdg_shell_v6_view->new_popup.notify = handle_new_popup;
203 wl_signal_add(&xdg_surface->events.new_popup,
204 &xdg_shell_v6_view->new_popup);
193} 205}
194 206
195static void handle_destroy(struct wl_listener *listener, void *data) { 207static void handle_destroy(struct wl_listener *listener, void *data) {
@@ -226,14 +238,6 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) {
226 // - Look up pid and open on appropriate workspace 238 // - Look up pid and open on appropriate workspace
227 // - Criteria 239 // - Criteria
228 240
229 xdg_shell_v6_view->commit.notify = handle_commit;
230 wl_signal_add(&xdg_surface->surface->events.commit,
231 &xdg_shell_v6_view->commit);
232
233 xdg_shell_v6_view->new_popup.notify = handle_new_popup;
234 wl_signal_add(&xdg_surface->events.new_popup,
235 &xdg_shell_v6_view->new_popup);
236
237 xdg_shell_v6_view->map.notify = handle_map; 241 xdg_shell_v6_view->map.notify = handle_map;
238 wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map); 242 wl_signal_add(&xdg_surface->events.map, &xdg_shell_v6_view->map);
239 243
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 10bfcc89..6de1365d 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -32,15 +32,15 @@ static void unmanaged_handle_commit(struct wl_listener *listener, void *data) {
32 32
33 if (xsurface->x != surface->lx || xsurface->y != surface->ly) { 33 if (xsurface->x != surface->lx || xsurface->y != surface->ly) {
34 // Surface has moved 34 // Surface has moved
35 desktop_damage_whole_surface(xsurface->surface, 35 desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
36 surface->lx, surface->ly); 36 true);
37 surface->lx = xsurface->x; 37 surface->lx = xsurface->x;
38 surface->ly = xsurface->y; 38 surface->ly = xsurface->y;
39 desktop_damage_whole_surface(xsurface->surface, 39 desktop_damage_surface(xsurface->surface, surface->lx, surface->ly,
40 surface->lx, surface->ly); 40 true);
41 } else { 41 } else {
42 desktop_damage_from_surface(xsurface->surface, 42 desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y,
43 xsurface->x, xsurface->y); 43 false);
44 } 44 }
45} 45}
46 46
@@ -57,7 +57,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
57 57
58 surface->lx = xsurface->x; 58 surface->lx = xsurface->x;
59 surface->ly = xsurface->y; 59 surface->ly = xsurface->y;
60 desktop_damage_whole_surface(xsurface->surface, surface->lx, surface->ly); 60 desktop_damage_surface(xsurface->surface, surface->lx, surface->ly, true);
61 61
62 // TODO: we don't send surface enter/leave events to xwayland unmanaged 62 // TODO: we don't send surface enter/leave events to xwayland unmanaged
63 // surfaces, but xwayland doesn't support HiDPI anyway 63 // surfaces, but xwayland doesn't support HiDPI anyway
@@ -67,7 +67,7 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
67 struct sway_xwayland_unmanaged *surface = 67 struct sway_xwayland_unmanaged *surface =
68 wl_container_of(listener, surface, unmap); 68 wl_container_of(listener, surface, unmap);
69 struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; 69 struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
70 desktop_damage_whole_surface(xsurface->surface, xsurface->x, xsurface->y); 70 desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true);
71 wl_list_remove(&surface->link); 71 wl_list_remove(&surface->link);
72 wl_list_remove(&surface->commit.link); 72 wl_list_remove(&surface->commit.link);
73} 73}
@@ -209,7 +209,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
209 // TODO: Let floating views do whatever 209 // TODO: Let floating views do whatever
210 view_update_size(view, xwayland_view->pending_width, 210 view_update_size(view, xwayland_view->pending_width,
211 xwayland_view->pending_height); 211 xwayland_view->pending_height);
212 view_damage_from(view); 212 view_damage(view, false);
213} 213}
214 214
215static void handle_unmap(struct wl_listener *listener, void *data) { 215static void handle_unmap(struct wl_listener *listener, void *data) {
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 9855c5e1..99b44720 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -79,20 +79,15 @@ void view_close(struct sway_view *view) {
79 } 79 }
80} 80}
81 81
82void view_damage_whole(struct sway_view *view) { 82void view_damage(struct sway_view *view, bool whole) {
83 for (int i = 0; i < root_container.children->length; ++i) { 83 for (int i = 0; i < root_container.children->length; ++i) {
84 struct sway_container *cont = root_container.children->items[i]; 84 struct sway_container *cont = root_container.children->items[i];
85 if (cont->type == C_OUTPUT) { 85 if (cont->type == C_OUTPUT) {
86 output_damage_whole_view(cont->sway_output, view); 86 output_damage_view(cont->sway_output, view, whole);
87 } 87 }
88 } 88 }
89} 89}
90 90
91void view_damage_from(struct sway_view *view) {
92 // TODO
93 view_damage_whole(view);
94}
95
96static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) { 91static void view_get_layout_box(struct sway_view *view, struct wlr_box *box) {
97 struct sway_container *output = container_parent(view->swayc, C_OUTPUT); 92 struct sway_container *output = container_parent(view->swayc, C_OUTPUT);
98 93
@@ -191,7 +186,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
191 arrange_windows(cont->parent, -1, -1); 186 arrange_windows(cont->parent, -1, -1);
192 input_manager_set_focus(input_manager, cont); 187 input_manager_set_focus(input_manager, cont);
193 188
194 view_damage_whole(view); 189 view_damage(view, true);
195 view_handle_container_reparent(&view->container_reparent, NULL); 190 view_handle_container_reparent(&view->container_reparent, NULL);
196} 191}
197 192
@@ -202,7 +197,7 @@ void view_unmap(struct sway_view *view) {
202 197
203 wl_signal_emit(&view->events.unmap, view); 198 wl_signal_emit(&view->events.unmap, view);
204 199
205 view_damage_whole(view); 200 view_damage(view, true);
206 201
207 wl_list_remove(&view->surface_new_subsurface.link); 202 wl_list_remove(&view->surface_new_subsurface.link);
208 wl_list_remove(&view->container_reparent.link); 203 wl_list_remove(&view->container_reparent.link);
@@ -220,10 +215,10 @@ void view_update_position(struct sway_view *view, double ox, double oy) {
220 return; 215 return;
221 } 216 }
222 217
223 view_damage_whole(view); 218 view_damage(view, true);
224 view->swayc->x = ox; 219 view->swayc->x = ox;
225 view->swayc->y = oy; 220 view->swayc->y = oy;
226 view_damage_whole(view); 221 view_damage(view, true);
227} 222}
228 223
229void view_update_size(struct sway_view *view, int width, int height) { 224void view_update_size(struct sway_view *view, int width, int height) {
@@ -231,10 +226,10 @@ void view_update_size(struct sway_view *view, int width, int height) {
231 return; 226 return;
232 } 227 }
233 228
234 view_damage_whole(view); 229 view_damage(view, true);
235 view->width = width; 230 view->width = width;
236 view->height = height; 231 view->height = height;
237 view_damage_whole(view); 232 view_damage(view, true);
238} 233}
239 234
240 235
@@ -253,7 +248,7 @@ static void view_child_handle_surface_commit(struct wl_listener *listener,
253 struct sway_view_child *child = 248 struct sway_view_child *child =
254 wl_container_of(listener, child, surface_commit); 249 wl_container_of(listener, child, surface_commit);
255 // TODO: only accumulate damage from the child 250 // TODO: only accumulate damage from the child
256 view_damage_from(child->view); 251 view_damage(child->view, false);
257} 252}
258 253
259static void view_child_handle_surface_new_subsurface( 254static void view_child_handle_surface_new_subsurface(
@@ -315,12 +310,12 @@ void view_child_init(struct sway_view_child *child,
315 view_init_subsurfaces(child->view, surface); 310 view_init_subsurfaces(child->view, surface);
316 311
317 // TODO: only damage the whole child 312 // TODO: only damage the whole child
318 view_damage_whole(child->view); 313 view_damage(child->view, true);
319} 314}
320 315
321void view_child_destroy(struct sway_view_child *child) { 316void view_child_destroy(struct sway_view_child *child) {
322 // TODO: only damage the whole child 317 // TODO: only damage the whole child
323 view_damage_whole(child->view); 318 view_damage(child->view, true);
324 319
325 wl_list_remove(&child->surface_commit.link); 320 wl_list_remove(&child->surface_commit.link);
326 wl_list_remove(&child->surface_destroy.link); 321 wl_list_remove(&child->surface_destroy.link);