diff --git a/sway/desktop/output.c b/sway/desktop/output.c index dea51bdf..1b3143d0 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -66,6 +66,10 @@ struct root_geometry { static bool get_surface_box(struct root_geometry *geo, struct sway_output *output, struct wlr_surface *surface, int sx, int sy, struct wlr_box *surface_box) { + if (!wlr_surface_has_buffer(surface)) { + return false; + } + int sw = surface->current->width; int sh = surface->current->height; @@ -95,7 +99,7 @@ static bool get_surface_box(struct root_geometry *geo, return wlr_box_intersection(&output_box, &rotated_box, &intersection); } -static void output_surface_for_each_surface(struct wlr_surface *surface, +static void surface_for_each_surface(struct wlr_surface *surface, double ox, double oy, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { geo->x = ox; @@ -119,6 +123,34 @@ static void output_view_for_each_surface(struct sway_view *view, view_for_each_surface(view, iterator, user_data); } +static void layer_for_each_surface(struct wl_list *layer_surfaces, + struct root_geometry *geo, wlr_surface_iterator_func_t iterator, + void *user_data) { + struct sway_layer_surface *layer_surface; + wl_list_for_each(layer_surface, layer_surfaces, link) { + struct wlr_layer_surface *wlr_layer_surface = + layer_surface->layer_surface; + surface_for_each_surface(wlr_layer_surface->surface, + layer_surface->geo.x, layer_surface->geo.y, geo, iterator, + user_data); + } +} + +static void unmanaged_for_each_surface(struct wl_list *unmanaged, + struct sway_output *output, struct root_geometry *geo, + wlr_surface_iterator_func_t iterator, void *user_data) { + struct sway_xwayland_unmanaged *unmanaged_surface; + wl_list_for_each(unmanaged_surface, unmanaged, link) { + struct wlr_xwayland_surface *xsurface = + unmanaged_surface->wlr_xwayland_surface; + double ox = unmanaged_surface->lx - output->swayc->x; + double oy = unmanaged_surface->ly - output->swayc->y; + + surface_for_each_surface(xsurface->surface, ox, oy, geo, + iterator, user_data); + } +} + static void scale_box(struct wlr_box *box, float scale) { box->x *= scale; box->y *= scale; @@ -129,7 +161,6 @@ static void scale_box(struct wlr_box *box, float scale) { struct render_data { struct root_geometry root_geo; struct sway_output *output; - struct timespec *when; float alpha; }; @@ -137,7 +168,6 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, void *_data) { struct render_data *data = _data; struct wlr_output *wlr_output = data->output->wlr_output; - struct timespec *when = data->when; float rotation = data->root_geo.rotation; float alpha = data->alpha; @@ -169,59 +199,52 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, wlr_render_texture_with_matrix(renderer, surface->texture, matrix, alpha); - - // TODO: don't send the frame done event now - wlr_surface_send_frame_done(surface, when); } -static void render_surface(struct sway_output *output, struct timespec *when, - struct wlr_surface *surface, double ox, double oy) { - struct render_data data = { - .output = output, - .when = when, - .alpha = 1.0f, - }; - - output_surface_for_each_surface(surface, ox, oy, &data.root_geo, +static void render_layer(struct sway_output *output, + struct wl_list *layer_surfaces) { + struct render_data data = { .output = output, .alpha = 1.0f }; + layer_for_each_surface(layer_surfaces, &data.root_geo, render_surface_iterator, &data); } -static void render_view(struct sway_output *output, struct timespec *when, - struct sway_view *view) { - struct render_data data = { - .output = output, - .when = when, - .alpha = view->swayc->alpha, - }; - - output_view_for_each_surface(view, &data.root_geo, +static void render_unmanaged(struct sway_output *output, + struct wl_list *unmanaged) { + struct render_data data = { .output = output, .alpha = 1.0f }; + unmanaged_for_each_surface(unmanaged, output, &data.root_geo, render_surface_iterator, &data); } -static void render_layer(struct sway_output *output, struct timespec *when, - struct wl_list *layer_surfaces) { - struct sway_layer_surface *layer_surface; - wl_list_for_each(layer_surface, layer_surfaces, link) { - struct wlr_layer_surface *wlr_layer_surface = - layer_surface->layer_surface; - render_surface(output, when, wlr_layer_surface->surface, - layer_surface->geo.x, layer_surface->geo.y); +static void render_container_iterator(struct sway_container *con, + void *_data) { + struct sway_output *output = _data; + if (!sway_assert(con->type == C_VIEW, "expected a view")) { + return; } + struct render_data data = { .output = output, .alpha = con->alpha }; + output_view_for_each_surface(con->sway_view, &data.root_geo, + render_surface_iterator, &data); } -struct render_view_data { - struct sway_output *output; - struct timespec *when; -}; - -static void render_view_iterator(struct sway_container *con, void *_data) { - struct render_view_data *data = _data; +static void render_container(struct sway_output *output, + struct sway_container *con) { + container_descendants(con, C_VIEW, render_container_iterator, output); +} - if (!sway_assert(con->type == C_VIEW, "expected a view")) { - return; +static struct sway_container *output_get_active_workspace( + struct sway_output *output) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = + seat_get_focus_inactive(seat, output->swayc); + if (!focus) { + // We've never been to this output before + focus = output->swayc->children->items[0]; } - - render_view(data->output, data->when, con->sway_view); + struct sway_container *workspace = focus; + if (workspace->type != C_WORKSPACE) { + workspace = container_parent(workspace, C_WORKSPACE); + } + return workspace; } static void render_output(struct sway_output *output, struct timespec *when, @@ -250,40 +273,17 @@ static void render_output(struct sway_output *output, struct timespec *when, float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; wlr_renderer_clear(renderer, clear_color); - render_layer(output, when, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(output, when, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - // Render all views in the current workspace - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = - seat_get_focus_inactive(seat, output->swayc); - if (!focus) { - // We've never been to this output before - focus = output->swayc->children->items[0]; - } - struct sway_container *workspace = focus->type == C_WORKSPACE ? - focus : container_parent(focus, C_WORKSPACE); - struct render_view_data data = { .output = output, .when = when }; - container_descendants(workspace, C_VIEW, render_view_iterator, &data); + struct sway_container *workspace = output_get_active_workspace(output); + render_container(output, workspace); - // Render unmanaged views on top - struct wl_list *unmanaged = &root_container.sway_root->xwayland_unmanaged; - struct sway_xwayland_unmanaged *unmanaged_surface; - wl_list_for_each(unmanaged_surface, unmanaged, link) { - struct wlr_xwayland_surface *xsurface = - unmanaged_surface->wlr_xwayland_surface; - double ox = unmanaged_surface->lx - output->swayc->x; - double oy = unmanaged_surface->ly - output->swayc->y; - render_surface(output, when, xsurface->surface, ox, oy); - } + render_unmanaged(output, &root_container.sway_root->xwayland_unmanaged); // TODO: consider revising this when fullscreen windows are supported - render_layer(output, when, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer(output, when, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + render_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); renderer_end: if (root_container.sway_root->debug_tree) { @@ -298,6 +298,74 @@ renderer_end: output->last_frame = *when; } +struct send_frame_done_data { + struct root_geometry root_geo; + struct sway_output *output; + struct timespec *when; +}; + +static void send_frame_done_iterator(struct wlr_surface *surface, + int sx, int sy, void *_data) { + struct send_frame_done_data *data = _data; + + bool intersects = get_surface_box(&data->root_geo, data->output, surface, + sx, sy, NULL); + if (intersects) { + wlr_surface_send_frame_done(surface, data->when); + } +} + +static void send_frame_done_layer(struct send_frame_done_data *data, + struct wl_list *layer_surfaces) { + layer_for_each_surface(layer_surfaces, &data->root_geo, + send_frame_done_iterator, data); +} + +static void send_frame_done_unmanaged(struct send_frame_done_data *data, + struct wl_list *unmanaged) { + unmanaged_for_each_surface(unmanaged, data->output, &data->root_geo, + send_frame_done_iterator, data); +} + +static void send_frame_done_container_iterator(struct sway_container *con, + void *_data) { + struct send_frame_done_data *data = _data; + if (!sway_assert(con->type == C_VIEW, "expected a view")) { + return; + } + output_view_for_each_surface(con->sway_view, &data->root_geo, + send_frame_done_iterator, data); +} + +static void send_frame_done_container(struct send_frame_done_data *data, + struct sway_container *con) { + container_descendants(con, C_VIEW, + send_frame_done_container_iterator, data); +} + +static void send_frame_done(struct sway_output *output, struct timespec *when) { + struct send_frame_done_data data = { + .output = output, + .when = when, + }; + + send_frame_done_layer(&data, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + send_frame_done_layer(&data, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + + struct sway_container *workspace = output_get_active_workspace(output); + send_frame_done_container(&data, workspace); + + send_frame_done_unmanaged(&data, + &root_container.sway_root->xwayland_unmanaged); + + send_frame_done_layer(&data, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + send_frame_done_layer(&data, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); +} + static void damage_handle_frame(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, damage_frame); @@ -322,7 +390,8 @@ static void damage_handle_frame(struct wl_listener *listener, void *data) { pixman_region32_fini(&damage); - // TODO: send frame done events here instead of inside render_surface + // Send frame done to all visible surfaces + send_frame_done(output, &now); } void output_damage_whole(struct sway_output *output) { @@ -342,10 +411,6 @@ static void damage_surface_iterator(struct wlr_surface *surface, int sx, int sy, float rotation = data->root_geo.rotation; bool whole = data->whole; - if (!wlr_surface_has_buffer(surface)) { - return; - } - struct wlr_box box; bool intersects = get_surface_box(&data->root_geo, data->output, surface, sx, sy, &box); @@ -387,7 +452,7 @@ void output_damage_surface(struct sway_output *output, double ox, double oy, .whole = whole, }; - output_surface_for_each_surface(surface, ox, oy, &data.root_geo, + surface_for_each_surface(surface, ox, oy, &data.root_geo, damage_surface_iterator, &data); }