aboutsummaryrefslogtreecommitdiffstats
path: root/sway/desktop/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/desktop/output.c')
-rw-r--r--sway/desktop/output.c439
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 */
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) {