diff options
Diffstat (limited to 'sway/desktop/output.c')
-rw-r--r-- | sway/desktop/output.c | 439 |
1 files changed, 258 insertions, 181 deletions
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 | */ |
39 | static void rotate_child_position(double *sx, double *sy, double sw, double sh, | 40 | static 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 | */ |
58 | static bool surface_intersect_output(struct wlr_surface *surface, | 60 | struct 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; | 66 | static 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 | ||
76 | static void render_surface(struct wlr_surface *surface, | 98 | static 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 | |||
110 | static 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 | |||
122 | static 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 | |||
129 | struct render_data { | ||
130 | struct root_geometry root_geo; | ||
131 | struct sway_output *output; | ||
132 | struct timespec *when; | ||
133 | float alpha; | ||
134 | }; | ||
135 | |||
136 | static 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 | ||
117 | static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, | 177 | static 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; | 189 | static 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 | ||
145 | static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, | 201 | static 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 | ||
172 | struct render_data { | 212 | struct 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 | ||
177 | static void render_view(struct sway_container *view, void *data) { | 217 | static 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 | |||
210 | static 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 | ||
221 | static void render_output(struct sway_output *output, struct timespec *when, | 227 | static 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 | ||
340 | void output_damage_whole_surface(struct sway_output *output, | 332 | struct 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 | |||
338 | static 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 | |||
383 | void 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 | ||
346 | void output_damage_whole_view(struct sway_output *output, | 394 | void 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 | |||
409 | static 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 | ||
352 | void output_damage_whole_container(struct sway_output *output, | 420 | void 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 | ||
358 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { | 435 | static void damage_handle_destroy(struct wl_listener *listener, void *data) { |