diff options
-rw-r--r-- | sway/desktop/output.c | 334 |
1 files changed, 160 insertions, 174 deletions
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3bbd0bb2..90ec3c77 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -38,191 +38,201 @@ struct sway_container *output_by_name(const char *name) { | |||
38 | */ | 38 | */ |
39 | static void rotate_child_position(double *sx, double *sy, double sw, double sh, | 39 | static void rotate_child_position(double *sx, double *sy, double sw, double sh, |
40 | double pw, double ph, float rotation) { | 40 | double pw, double ph, float rotation) { |
41 | if (rotation != 0.0) { | 41 | if (rotation == 0.0f) { |
42 | // Coordinates relative to the center of the subsurface | 42 | 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 | } | 43 | } |
44 | |||
45 | // Coordinates relative to the center of the subsurface | ||
46 | double ox = *sx - pw/2 + sw/2, | ||
47 | oy = *sy - ph/2 + sh/2; | ||
48 | // Rotated coordinates | ||
49 | double rx = cos(-rotation)*ox - sin(-rotation)*oy, | ||
50 | ry = cos(-rotation)*oy + sin(-rotation)*ox; | ||
51 | *sx = rx + pw/2 - sw/2; | ||
52 | *sy = ry + ph/2 - sh/2; | ||
51 | } | 53 | } |
52 | 54 | ||
53 | /** | 55 | /** |
54 | * Checks whether a surface at (lx, ly) intersects an output. If `box` is not | 56 | * 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 | 57 | * a popup, this will contain the parent view's position and size. |
56 | * coordinates. | ||
57 | */ | 58 | */ |
58 | static bool surface_intersect_output(struct wlr_surface *surface, | 59 | struct root_geometry { |
59 | struct wlr_output_layout *output_layout, struct wlr_output *wlr_output, | 60 | double x, y; |
60 | double ox, double oy, float rotation, struct wlr_box *box) { | 61 | int width, height; |
61 | if (box != NULL) { | 62 | float rotation; |
62 | box->x = ox * wlr_output->scale; | 63 | }; |
63 | box->y = oy * wlr_output->scale; | 64 | |
64 | box->width = surface->current->width * wlr_output->scale; | 65 | static bool get_surface_box(struct root_geometry *geo, |
65 | box->height = surface->current->height * wlr_output->scale; | 66 | struct sway_output *output, struct wlr_surface *surface, int sx, int sy, |
67 | struct wlr_box *surface_box) { | ||
68 | int sw = surface->current->width; | ||
69 | int sh = surface->current->height; | ||
70 | |||
71 | double _sx = sx, _sy = sy; | ||
72 | rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height, | ||
73 | geo->rotation); | ||
74 | |||
75 | struct wlr_box box = { | ||
76 | .x = geo->x + _sx, | ||
77 | .y = geo->y + _sy, | ||
78 | .width = sw, | ||
79 | .height = sh, | ||
80 | }; | ||
81 | if (surface_box != NULL) { | ||
82 | memcpy(surface_box, &box, sizeof(struct wlr_box)); | ||
66 | } | 83 | } |
67 | 84 | ||
68 | struct wlr_box layout_box = { | 85 | struct wlr_box rotated_box; |
69 | .x = wlr_output->lx + ox, .y = wlr_output->ly + oy, | 86 | wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box); |
70 | .width = surface->current->width, .height = surface->current->height, | 87 | |
88 | struct wlr_box output_box = { | ||
89 | .width = output->swayc->width, | ||
90 | .height = output->swayc->height, | ||
71 | }; | 91 | }; |
72 | wlr_box_rotated_bounds(&layout_box, rotation, &layout_box); | 92 | |
73 | return wlr_output_layout_intersects(output_layout, wlr_output, &layout_box); | 93 | struct wlr_box intersection; |
94 | return wlr_box_intersection(&output_box, &rotated_box, &intersection); | ||
74 | } | 95 | } |
75 | 96 | ||
76 | static void render_surface(struct wlr_surface *surface, | 97 | static void output_surface_for_each_surface(struct wlr_surface *surface, |
77 | struct wlr_output *wlr_output, struct timespec *when, | 98 | double ox, double oy, float rotation, struct root_geometry *geo, |
78 | double ox, double oy, float rotation, float alpha) { | 99 | wlr_surface_iterator_func_t iterator, void *user_data) { |
79 | struct wlr_renderer *renderer = | 100 | geo->x = ox; |
80 | wlr_backend_get_renderer(wlr_output->backend); | 101 | geo->y = oy; |
102 | geo->width = surface->current->width; | ||
103 | geo->height = surface->current->height; | ||
104 | geo->rotation = rotation; | ||
105 | |||
106 | wlr_surface_for_each_surface(surface, iterator, user_data); | ||
107 | } | ||
108 | |||
109 | static void output_view_for_each_surface(struct sway_view *view, | ||
110 | struct root_geometry *geo, wlr_surface_iterator_func_t iterator, | ||
111 | void *user_data) { | ||
112 | geo->x = view->swayc->x; | ||
113 | geo->y = view->swayc->y; | ||
114 | geo->width = view->surface->current->width; | ||
115 | geo->height = view->surface->current->height; | ||
116 | geo->rotation = 0; // TODO | ||
117 | |||
118 | view_for_each_surface(view, iterator, user_data); | ||
119 | } | ||
120 | |||
121 | static void scale_box(struct wlr_box *box, float scale) { | ||
122 | box->x *= scale; | ||
123 | box->y *= scale; | ||
124 | box->width *= scale; | ||
125 | box->height *= scale; | ||
126 | } | ||
127 | |||
128 | struct render_data { | ||
129 | struct root_geometry root_geo; | ||
130 | struct sway_output *output; | ||
131 | struct timespec *when; | ||
132 | float alpha; | ||
133 | }; | ||
134 | |||
135 | static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, | ||
136 | void *_data) { | ||
137 | struct render_data *data = _data; | ||
138 | struct wlr_output *wlr_output = data->output->wlr_output; | ||
139 | struct timespec *when = data->when; | ||
140 | float rotation = data->root_geo.rotation; | ||
141 | float alpha = data->alpha; | ||
81 | 142 | ||
82 | if (!wlr_surface_has_buffer(surface)) { | 143 | if (!wlr_surface_has_buffer(surface)) { |
83 | return; | 144 | return; |
84 | } | 145 | } |
85 | 146 | ||
86 | struct wlr_output_layout *layout = root_container.sway_root->output_layout; | ||
87 | |||
88 | struct wlr_box box; | 147 | struct wlr_box box; |
89 | bool intersects = surface_intersect_output(surface, layout, wlr_output, | 148 | bool intersects = get_surface_box(&data->root_geo, data->output, surface, |
90 | ox, oy, rotation, &box); | 149 | sx, sy, &box); |
91 | if (intersects) { | 150 | if (!intersects) { |
92 | float matrix[9]; | 151 | 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 | } | 152 | } |
103 | 153 | ||
104 | struct wlr_subsurface *subsurface; | 154 | struct wlr_renderer *renderer = |
105 | wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { | 155 | wlr_backend_get_renderer(wlr_output->backend); |
106 | struct wlr_surface_state *state = subsurface->surface->current; | 156 | if (!sway_assert(renderer != NULL, |
107 | double sx = state->subsurface_position.x; | 157 | "expected the output backend to have a renderer")) { |
108 | double sy = state->subsurface_position.y; | 158 | 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 | } | 159 | } |
160 | |||
161 | scale_box(&box, wlr_output->scale); | ||
162 | |||
163 | float matrix[9]; | ||
164 | enum wl_output_transform transform = | ||
165 | wlr_output_transform_invert(surface->current->transform); | ||
166 | wlr_matrix_project_box(matrix, &box, transform, rotation, | ||
167 | wlr_output->transform_matrix); | ||
168 | |||
169 | wlr_render_texture_with_matrix(renderer, surface->texture, | ||
170 | matrix, alpha); | ||
171 | |||
172 | // TODO: don't send the frame done event now | ||
173 | wlr_surface_send_frame_done(surface, when); | ||
115 | } | 174 | } |
116 | 175 | ||
117 | static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, | 176 | static void render_surface(struct sway_output *output, struct timespec *when, |
118 | struct wlr_output *wlr_output, struct timespec *when, double base_x, | 177 | struct wlr_surface *surface, double ox, double oy, float rotation) { |
119 | double base_y, float rotation, float alpha) { | 178 | struct render_data data = { |
120 | double width = surface->surface->current->width; | 179 | .output = output, |
121 | double height = surface->surface->current->height; | 180 | .when = when, |
122 | 181 | .alpha = 1.0f, | |
123 | struct wlr_xdg_popup_v6 *popup_state; | 182 | }; |
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 | 183 | ||
130 | double popup_width = popup->surface->current->width; | 184 | output_surface_for_each_surface(surface, ox, oy, rotation, &data.root_geo, |
131 | double popup_height = popup->surface->current->height; | 185 | render_surface_iterator, &data); |
186 | } | ||
132 | 187 | ||
133 | double popup_sx, popup_sy; | 188 | static void render_view(struct sway_output *output, struct timespec *when, |
134 | wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); | 189 | struct sway_view *view) { |
135 | rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, | 190 | struct render_data data = { |
136 | width, height, rotation); | 191 | .output = output, |
192 | .when = when, | ||
193 | .alpha = view->swayc->alpha, | ||
194 | }; | ||
137 | 195 | ||
138 | render_surface(popup->surface, wlr_output, when, | 196 | output_view_for_each_surface(view, &data.root_geo, |
139 | base_x + popup_sx, base_y + popup_sy, rotation, alpha); | 197 | 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 | } | 198 | } |
144 | 199 | ||
145 | static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, | 200 | static void render_layer(struct sway_output *output, struct timespec *when, |
146 | struct wlr_output *wlr_output, struct timespec *when, | 201 | struct wl_list *layer_surfaces) { |
147 | double lx, double ly, float rotation, float alpha, | 202 | struct sway_layer_surface *layer_surface; |
148 | bool is_child) { | 203 | wl_list_for_each(layer_surface, layer_surfaces, link) { |
149 | if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { | 204 | struct wlr_layer_surface *wlr_layer_surface = |
150 | render_surface(surface->surface, wlr_output, when, | 205 | layer_surface->layer_surface; |
151 | lx, ly, rotation, alpha); | 206 | render_surface(output, when, wlr_layer_surface->surface, |
152 | 207 | layer_surface->geo.x, layer_surface->geo.y, 0); | |
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 | } | 208 | } |
170 | } | 209 | } |
171 | 210 | ||
172 | struct render_data { | 211 | struct render_view_data { |
173 | struct sway_output *output; | 212 | struct sway_output *output; |
174 | struct timespec *when; | 213 | struct timespec *when; |
175 | }; | 214 | }; |
176 | 215 | ||
177 | static void render_view(struct sway_container *view, void *data) { | 216 | static void render_view_iterator(struct sway_container *con, void *_data) { |
178 | struct render_data *rdata = data; | 217 | 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 | 218 | ||
186 | if (!surface) { | 219 | if (!sway_assert(con->type == C_VIEW, "expected a view")) { |
187 | return; | 220 | return; |
188 | } | 221 | } |
189 | 222 | ||
190 | switch (sway_view->type) { | 223 | 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 | } | 224 | } |
220 | 225 | ||
221 | static void render_output(struct sway_output *output, struct timespec *when, | 226 | static void render_output(struct sway_output *output, struct timespec *when, |
222 | pixman_region32_t *damage) { | 227 | pixman_region32_t *damage) { |
223 | struct wlr_output *wlr_output = output->wlr_output; | 228 | struct wlr_output *wlr_output = output->wlr_output; |
229 | |||
224 | struct wlr_renderer *renderer = | 230 | struct wlr_renderer *renderer = |
225 | wlr_backend_get_renderer(wlr_output->backend); | 231 | wlr_backend_get_renderer(wlr_output->backend); |
232 | if (!sway_assert(renderer != NULL, | ||
233 | "expected the output backend to have a renderer")) { | ||
234 | return; | ||
235 | } | ||
226 | 236 | ||
227 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | 237 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); |
228 | 238 | ||
@@ -231,24 +241,15 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
231 | goto renderer_end; | 241 | goto renderer_end; |
232 | } | 242 | } |
233 | 243 | ||
234 | // TODO: don't damage the whole output here | ||
235 | int width, height; | ||
236 | wlr_output_transformed_resolution(wlr_output, &width, &height); | ||
237 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | ||
238 | |||
239 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; | 244 | float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; |
240 | wlr_renderer_clear(renderer, clear_color); | 245 | wlr_renderer_clear(renderer, clear_color); |
241 | 246 | ||
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, | 247 | render_layer(output, when, |
248 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); | 248 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); |
249 | render_layer(output, when, | 249 | render_layer(output, when, |
250 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); | 250 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); |
251 | 251 | ||
252 | // Render all views in the current workspace | ||
252 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 253 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
253 | struct sway_container *focus = | 254 | struct sway_container *focus = |
254 | seat_get_focus_inactive(seat, output->swayc); | 255 | seat_get_focus_inactive(seat, output->swayc); |
@@ -258,36 +259,21 @@ static void render_output(struct sway_output *output, struct timespec *when, | |||
258 | } | 259 | } |
259 | struct sway_container *workspace = focus->type == C_WORKSPACE ? | 260 | struct sway_container *workspace = focus->type == C_WORKSPACE ? |
260 | focus : container_parent(focus, C_WORKSPACE); | 261 | focus : container_parent(focus, C_WORKSPACE); |
262 | struct render_view_data data = { .output = output, .when = when }; | ||
263 | container_descendants(workspace, C_VIEW, render_view_iterator, &data); | ||
261 | 264 | ||
262 | struct render_data rdata = { | 265 | // 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; | 266 | struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; |
270 | struct sway_xwayland_unmanaged *unmanaged_surface; | 267 | struct sway_xwayland_unmanaged *unmanaged_surface; |
271 | wl_list_for_each(unmanaged_surface, unmanaged, link) { | 268 | wl_list_for_each(unmanaged_surface, unmanaged, link) { |
272 | struct wlr_xwayland_surface *xsurface = | 269 | struct wlr_xwayland_surface *xsurface = |
273 | unmanaged_surface->wlr_xwayland_surface; | 270 | unmanaged_surface->wlr_xwayland_surface; |
274 | 271 | double ox = unmanaged_surface->lx - output->swayc->x; | |
275 | const struct wlr_box view_box = { | 272 | double oy = unmanaged_surface->ly - output->swayc->y; |
276 | .x = unmanaged_surface->lx, | 273 | render_surface(output, when, xsurface->surface, ox, oy, 0); |
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 | } | 274 | } |
289 | 275 | ||
290 | // TODO: Consider revising this when fullscreen windows are supported | 276 | // TODO: consider revising this when fullscreen windows are supported |
291 | render_layer(output, when, | 277 | render_layer(output, when, |
292 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); | 278 | &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); |
293 | render_layer(output, when, | 279 | render_layer(output, when, |