From ce7e5b9f103401946469ad63cfbc1c4590314efa Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 12:15:02 +1000 Subject: [PATCH 01/11] Move rendering functions into render.c --- include/sway/desktop/render.h | 9 + sway/desktop/output.c | 815 +------------------------- sway/desktop/render.c | 1007 +++++++++++++++++++++++++++++++++ sway/meson.build | 1 + 4 files changed, 1018 insertions(+), 814 deletions(-) create mode 100644 include/sway/desktop/render.h create mode 100644 sway/desktop/render.c diff --git a/include/sway/desktop/render.h b/include/sway/desktop/render.h new file mode 100644 index 000000000..571de05dc --- /dev/null +++ b/include/sway/desktop/render.h @@ -0,0 +1,9 @@ +#ifndef _SWAY_RENDER_H +#define _SWAY_RENDER_H +#include +#include "sway/output.h" + +void render_output(struct sway_output *output, struct timespec *when, + pixman_region32_t *damage); + +#endif diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1e7494b3e..e8796fc6a 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -15,6 +15,7 @@ #include #include "log.h" #include "sway/config.h" +#include "sway/desktop/render.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" @@ -185,720 +186,6 @@ static void scale_box(struct wlr_box *box, float scale) { box->height *= scale; } -static void scissor_output(struct wlr_output *wlr_output, - pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); - assert(renderer); - - struct wlr_box box = { - .x = rect->x1, - .y = rect->y1, - .width = rect->x2 - rect->x1, - .height = rect->y2 - rect->y1, - }; - - int ow, oh; - wlr_output_transformed_resolution(wlr_output, &ow, &oh); - - enum wl_output_transform transform = - wlr_output_transform_invert(wlr_output->transform); - wlr_box_transform(&box, transform, ow, oh, &box); - - wlr_renderer_scissor(renderer, &box); -} - -static void render_texture(struct wlr_output *wlr_output, - pixman_region32_t *output_damage, struct wlr_texture *texture, - const struct wlr_box *box, const float matrix[static 9], float alpha) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box->x, box->y, - box->width, box->height); - pixman_region32_intersect(&damage, &damage, output_damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto damage_finish; - } - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); - } - -damage_finish: - pixman_region32_fini(&damage); -} - -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; - float rotation = data->root_geo.rotation; - pixman_region32_t *output_damage = data->damage; - float alpha = data->alpha; - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - return; - } - - struct wlr_box box; - bool intersects = get_surface_box(&data->root_geo, data->output, surface, - sx, sy, &box); - if (!intersects) { - return; - } - - scale_box(&box, wlr_output->scale); - - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current->transform); - wlr_matrix_project_box(matrix, &box, transform, rotation, - wlr_output->transform_matrix); - - render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); -} - -static void render_layer(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *layer_surfaces) { - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - layer_for_each_surface(layer_surfaces, &data.root_geo, - render_surface_iterator, &data); -} - -static void render_unmanaged(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *unmanaged) { - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - unmanaged_for_each_surface(unmanaged, output, &data.root_geo, - render_surface_iterator, &data); -} - -static void render_drag_icons(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *drag_icons) { - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - drag_icons_for_each_surface(drag_icons, output, &data.root_geo, - render_surface_iterator, &data); -} - -static void render_rect(struct wlr_output *wlr_output, - pixman_region32_t *output_damage, const struct wlr_box *_box, - float color[static 4]) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= wlr_output->lx * wlr_output->scale; - box.y -= wlr_output->ly * wlr_output->scale; - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box.x, box.y, - box.width, box.height); - pixman_region32_intersect(&damage, &damage, output_damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto damage_finish; - } - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_render_rect(renderer, &box, color, - wlr_output->transform_matrix); - } - -damage_finish: - pixman_region32_fini(&damage); -} - -static void premultiply_alpha(float color[4], float opacity) { - color[3] *= opacity; - color[0] *= color[3]; - color[1] *= color[3]; - color[2] *= color[3]; -} - -static void render_view_surfaces(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { - struct render_data data = { - .output = output, - .damage = damage, - .view = view, - .alpha = alpha, - }; - output_view_for_each_surface( - view, &data.root_geo, render_surface_iterator, &data); -} - -static void render_saved_view(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { - struct wlr_output *wlr_output = output->wlr_output; - - int width, height; - struct wlr_texture *texture = - transaction_get_saved_texture(view, &width, &height); - if (!texture) { - return; - } - struct wlr_box box = { - .x = view->swayc->current.view_x - output->swayc->current.swayc_x, - .y = view->swayc->current.view_y - output->swayc->current.swayc_y, - .width = width, - .height = height, - }; - - struct wlr_box output_box = { - .width = output->swayc->current.swayc_width, - .height = output->swayc->current.swayc_height, - }; - - struct wlr_box intersection; - bool intersects = wlr_box_intersection(&output_box, &box, &intersection); - if (!intersects) { - return; - } - - scale_box(&box, wlr_output->scale); - - float matrix[9]; - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, - wlr_output->transform_matrix); - - render_texture(wlr_output, damage, texture, &box, matrix, alpha); -} - -/** - * Render a view's surface and left/bottom/right borders. - */ -static void render_view(struct sway_output *output, pixman_region32_t *damage, - struct sway_container *con, struct border_colors *colors) { - struct sway_view *view = con->sway_view; - if (view->swayc->instructions->length) { - render_saved_view(view, output, damage, view->swayc->alpha); - } else { - render_view_surfaces(view, output, damage, view->swayc->alpha); - } - - struct wlr_box box; - float output_scale = output->wlr_output->scale; - float color[4]; - struct sway_container_state *state = &con->current; - - if (state->border != B_NONE) { - if (state->border_left) { - memcpy(&color, colors->child_border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; - box.y = state->view_y; - box.width = state->border_thickness; - box.height = state->view_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } - - if (state->border_right) { - if (state->parent->current.children->length == 1 - && state->parent->current.layout == L_HORIZ) { - memcpy(&color, colors->indicator, sizeof(float) * 4); - } else { - memcpy(&color, colors->child_border, sizeof(float) * 4); - } - premultiply_alpha(color, con->alpha); - box.x = state->view_x + state->view_width; - box.y = state->view_y; - box.width = state->border_thickness; - box.height = state->view_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } - - if (state->border_bottom) { - if (state->parent->current.children->length == 1 - && con->current.parent->current.layout == L_VERT) { - memcpy(&color, colors->indicator, sizeof(float) * 4); - } else { - memcpy(&color, colors->child_border, sizeof(float) * 4); - } - premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; - box.y = state->view_y + state->view_height; - box.width = state->swayc_width; - box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); - } - } -} - -/** - * Render a titlebar. - * - * Care must be taken not to render over the same pixel multiple times, - * otherwise the colors will be incorrect when using opacity. - * - * The height is: 1px border, 3px padding, font height, 3px padding, 1px border - * The left side for L_TABBED is: 1px border, 2px padding, title - * The left side for other layouts is: 3px padding, title - */ -static void render_titlebar(struct sway_output *output, - pixman_region32_t *output_damage, struct sway_container *con, - int x, int y, int width, - struct border_colors *colors, struct wlr_texture *title_texture, - struct wlr_texture *marks_texture) { - struct wlr_box box; - float color[4]; - struct sway_container_state *state = &con->current; - float output_scale = output->wlr_output->scale; - enum sway_container_layout layout = state->parent->current.layout; - list_t *children = state->parent->current.children; - bool is_last_child = children->items[children->length - 1] == con; - double output_x = output->swayc->current.swayc_x; - double output_y = output->swayc->current.swayc_y; - - // Single pixel bar above title - memcpy(&color, colors->border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = x; - box.y = y; - box.width = width; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Single pixel bar below title - size_t left_offset = 0, right_offset = 0; - bool connects_sides = false; - if (layout == L_HORIZ || layout == L_VERT || - (layout == L_STACKED && is_last_child)) { - if (con->type == C_VIEW) { - left_offset = state->border_left * state->border_thickness; - right_offset = state->border_right * state->border_thickness; - connects_sides = true; - } - } - box.x = x + left_offset; - box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = width - left_offset - right_offset; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - if (layout == L_TABBED) { - // Single pixel left edge - box.x = x; - box.y = y + TITLEBAR_BORDER_THICKNESS; - box.width = TITLEBAR_BORDER_THICKNESS; - box.height = - container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Single pixel right edge - box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); - } - - size_t inner_width = width - TITLEBAR_H_PADDING * 2; - - // Marks - size_t marks_width = 0; - if (config->show_marks && marks_texture) { - struct wlr_box texture_box; - wlr_texture_get_size(marks_texture, - &texture_box.width, &texture_box.height); - texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) - * output_scale - texture_box.width; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; - - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - - if (inner_width * output_scale < texture_box.width) { - texture_box.width = inner_width * output_scale; - } - render_texture(output->wlr_output, output_damage, marks_texture, - &texture_box, matrix, con->alpha); - marks_width = texture_box.width; - } - - // Title text - size_t title_width = 0; - if (title_texture) { - struct wlr_box texture_box; - wlr_texture_get_size(title_texture, - &texture_box.width, &texture_box.height); - texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; - - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - - if (inner_width * output_scale - marks_width < texture_box.width) { - texture_box.width = inner_width * output_scale - marks_width; - } - render_texture(output->wlr_output, output_damage, title_texture, - &texture_box, matrix, con->alpha); - title_width = texture_box.width; - } - - // Padding above title - memcpy(&color, colors->background, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; - box.y = y + TITLEBAR_BORDER_THICKNESS; - box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2; - box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Padding below title - box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); - - // Filler between title and marks - box.width = inner_width * output_scale - title_width - marks_width; - if (box.width > 0) { - box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width; - box.y = (y + TITLEBAR_V_PADDING) * output_scale; - box.height = config->font_height * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); - } - - // Padding left of title - left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; - box.x = x + left_offset; - box.y = y + TITLEBAR_V_PADDING; - box.width = TITLEBAR_H_PADDING - left_offset; - box.height = config->font_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Padding right of marks - right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; - box.x = x + width - TITLEBAR_H_PADDING; - box.y = y + TITLEBAR_V_PADDING; - box.width = TITLEBAR_H_PADDING - right_offset; - box.height = config->font_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - if (connects_sides) { - // Left pixel in line with bottom bar - box.x = x; - box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = state->border_thickness * state->border_left; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - - // Right pixel in line with bottom bar - box.x = x + width - state->border_thickness * state->border_right; - box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; - box.width = state->border_thickness * state->border_right; - box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); - } -} - -/** - * Render the top border line for a view using "border pixel". - */ -static void render_top_border(struct sway_output *output, - pixman_region32_t *output_damage, struct sway_container *con, - struct border_colors *colors) { - struct sway_container_state *state = &con->current; - if (!state->border_top) { - return; - } - struct wlr_box box; - float color[4]; - float output_scale = output->wlr_output->scale; - - // Child border - top edge - memcpy(&color, colors->child_border, sizeof(float) * 4); - premultiply_alpha(color, con->alpha); - box.x = state->swayc_x; - box.y = state->swayc_y; - box.width = state->swayc_width; - box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); -} - -static void render_container(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, bool parent_focused); - -/** - * Render a container's children using a L_HORIZ or L_VERT layout. - * - * Wrap child views in borders and leave child containers borderless because - * they'll apply their own borders to their children. - */ -static void render_container_simple(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; - - if (child->type == C_VIEW) { - struct sway_view *view = child->sway_view; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - struct sway_container_state *state = &child->current; - - if (focus == child || parent_focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = view->marks_focused; - } else if (seat_get_focus_inactive(seat, con) == child) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = view->marks_focused_inactive; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = view->marks_unfocused; - } - - if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, state->swayc_x, - state->swayc_y, state->swayc_width, colors, - title_texture, marks_texture); - } else { - render_top_border(output, damage, child, colors); - } - render_view(output, damage, child, colors); - } else { - render_container(output, damage, child, - parent_focused || focus == child); - } - } -} - -/** - * Render a container's children using the L_TABBED layout. - */ -static void render_container_tabbed(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - if (!con->current.children->length) { - return; - } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; - struct sway_container_state *pstate = &con->current; - - // Render tabs - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; - struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; - struct sway_container_state *cstate = &child->current; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - - if (focus == child || parent_focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = view ? view->marks_focused_inactive : NULL; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = view ? view->marks_unfocused : NULL; - } - - int tab_width = pstate->swayc_width / pstate->children->length; - int x = pstate->swayc_x + tab_width * i; - // Make last tab use the remaining width of the parent - if (i == pstate->children->length - 1) { - tab_width = pstate->swayc_width - tab_width * i; - } - - render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, - colors, title_texture, marks_texture); - - if (child == current) { - current_colors = colors; - } - } - - // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } - } -} - -/** - * Render a container's children using the L_STACKED layout. - */ -static void render_container_stacked(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - if (!con->current.children->length) { - return; - } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; - struct sway_container_state *pstate = &con->current; - - // Render titles - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; - struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; - struct sway_container_state *cstate = &child->current; - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - - if (focus == child || parent_focused) { - colors = &config->border_colors.focused; - title_texture = child->title_focused; - marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { - colors = &config->border_colors.focused_inactive; - title_texture = child->title_focused_inactive; - marks_texture = view ? view->marks_focused_inactive : NULL; - } else { - colors = &config->border_colors.unfocused; - title_texture = child->title_unfocused; - marks_texture = view ? view->marks_unfocused : NULL; - } - - int y = pstate->swayc_y + container_titlebar_height() * i; - render_titlebar(output, damage, child, cstate->swayc_x, y, - cstate->swayc_width, colors, title_texture, marks_texture); - - if (child == current) { - current_colors = colors; - } - } - - // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } - } -} - -static void render_container(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { - switch (con->current.layout) { - case L_NONE: - case L_HORIZ: - case L_VERT: - render_container_simple(output, damage, con, parent_focused); - break; - case L_STACKED: - render_container_stacked(output, damage, con, parent_focused); - break; - case L_TABBED: - render_container_tabbed(output, damage, con, parent_focused); - break; - case L_FLOATING: - sway_assert(false, "Didn't expect to see floating here"); - } -} - -static void render_floating_container(struct sway_output *soutput, - pixman_region32_t *damage, struct sway_container *con) { - if (con->type == C_VIEW) { - struct sway_view *view = con->sway_view; - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct border_colors *colors; - struct wlr_texture *title_texture; - struct wlr_texture *marks_texture; - - if (focus == con) { - colors = &config->border_colors.focused; - title_texture = con->title_focused; - marks_texture = view->marks_focused; - } else { - colors = &config->border_colors.unfocused; - title_texture = con->title_unfocused; - marks_texture = view->marks_unfocused; - } - - if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, con->current.swayc_x, - con->current.swayc_y, con->current.swayc_width, colors, - title_texture, marks_texture); - } else if (con->current.border != B_NONE) { - render_top_border(soutput, damage, con, colors); - } - render_view(soutput, damage, con, colors); - } else { - render_container(soutput, damage, con, false); - } -} - -static void render_floating(struct sway_output *soutput, - pixman_region32_t *damage) { - for (int i = 0; i < root_container.current.children->length; ++i) { - struct sway_container *output = - root_container.current.children->items[i]; - for (int j = 0; j < output->current.children->length; ++j) { - struct sway_container *ws = output->current.children->items[j]; - if (!workspace_is_visible(ws)) { - continue; - } - list_t *floating = - ws->current.ws_floating->current.children; - for (int k = 0; k < floating->length; ++k) { - struct sway_container *floater = floating->items[k]; - render_floating_container(soutput, damage, floater); - } - } - } -} - static struct sway_container *output_get_active_workspace( struct sway_output *output) { struct sway_seat *seat = input_manager_current_seat(input_manager); @@ -915,106 +202,6 @@ static struct sway_container *output_get_active_workspace( return workspace; } -static void render_output(struct sway_output *output, struct timespec *when, - pixman_region32_t *damage) { - struct wlr_output *wlr_output = output->wlr_output; - - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - if (!sway_assert(renderer != NULL, - "expected the output backend to have a renderer")) { - return; - } - - wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); - - bool damage_whole_before_swap = false; - if (!pixman_region32_not_empty(damage)) { - // Output isn't damaged but needs buffer swap - goto renderer_end; - } - - const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG"); - if (damage_debug != NULL) { - if (strcmp(damage_debug, "highlight") == 0) { - wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); - damage_whole_before_swap = true; - } else if (strcmp(damage_debug, "rerender") == 0) { - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(damage, damage, 0, 0, width, height); - } - } - - struct sway_container *workspace = output_get_active_workspace(output); - struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; - - if (fullscreen_view) { - float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - - // TODO: handle views smaller than the output - render_view_surfaces(fullscreen_view, output, damage, 1.0f); - - if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); - } - } else { - float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - render_container(output, damage, workspace, focus == workspace); - render_floating(output, damage); - - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - } - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_drag_icons(output, damage, &root_container.sway_root->drag_icons); - -renderer_end: - if (root_container.sway_root->debug_tree) { - wlr_render_texture(renderer, root_container.sway_root->debug_tree, - wlr_output->transform_matrix, 0, 0, 1); - } - - if (damage_whole_before_swap || root_container.sway_root->debug_tree) { - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(damage, damage, 0, 0, width, height); - } - - wlr_renderer_scissor(renderer, NULL); - wlr_renderer_end(renderer); - if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) { - return; - } - output->last_frame = *when; -} - struct send_frame_done_data { struct root_geometry root_geo; struct sway_output *output; diff --git a/sway/desktop/render.c b/sway/desktop/render.c new file mode 100644 index 000000000..bb1b26a93 --- /dev/null +++ b/sway/desktop/render.c @@ -0,0 +1,1007 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" +#include "sway/config.h" +#include "sway/desktop/render.h" +#include "sway/desktop/transaction.h" +#include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/layers.h" +#include "sway/output.h" +#include "sway/server.h" +#include "sway/tree/container.h" +#include "sway/tree/layout.h" +#include "sway/tree/view.h" +#include "sway/tree/workspace.h" + +/** + * Rotate a child's position relative to a parent. The parent size is (pw, ph), + * the child position is (*sx, *sy) and its size is (sw, sh). + */ +static void rotate_child_position(double *sx, double *sy, double sw, double sh, + double pw, double ph, float rotation) { + if (rotation == 0.0f) { + return; + } + + // Coordinates relative to the center of the subsurface + double ox = *sx - pw/2 + sw/2, + oy = *sy - ph/2 + sh/2; + // Rotated coordinates + double rx = cos(-rotation)*ox - sin(-rotation)*oy, + ry = cos(-rotation)*oy + sin(-rotation)*ox; + *sx = rx + pw/2 - sw/2; + *sy = ry + ph/2 - sh/2; +} + +/** + * Contains a surface's root geometry information. For instance, when rendering + * a popup, this will contain the parent view's position and size. + */ +struct root_geometry { + double x, y; + int width, height; + float rotation; +}; + +struct render_data { + struct root_geometry root_geo; + struct sway_output *output; + pixman_region32_t *damage; + struct sway_view *view; + float alpha; +}; + +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; + + double _sx = sx, _sy = sy; + rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height, + geo->rotation); + + struct wlr_box box = { + .x = geo->x + _sx, + .y = geo->y + _sy, + .width = sw, + .height = sh, + }; + if (surface_box != NULL) { + memcpy(surface_box, &box, sizeof(struct wlr_box)); + } + + struct wlr_box rotated_box; + wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box); + + struct wlr_box output_box = { + .width = output->swayc->current.swayc_width, + .height = output->swayc->current.swayc_height, + }; + + struct wlr_box intersection; + return wlr_box_intersection(&output_box, &rotated_box, &intersection); +} + +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; + geo->y = oy; + geo->width = surface->current->width; + geo->height = surface->current->height; + geo->rotation = 0; + + wlr_surface_for_each_surface(surface, iterator, user_data); +} + +static void output_view_for_each_surface(struct sway_view *view, + struct root_geometry *geo, wlr_surface_iterator_func_t iterator, + void *user_data) { + struct render_data *data = user_data; + geo->x = view->swayc->current.view_x - data->output->swayc->current.swayc_x; + geo->y = view->swayc->current.view_y - data->output->swayc->current.swayc_y; + geo->width = view->swayc->current.view_width; + geo->height = view->swayc->current.view_height; + geo->rotation = 0; // TODO + + 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->current.swayc_x; + double oy = unmanaged_surface->ly - output->swayc->current.swayc_y; + + surface_for_each_surface(xsurface->surface, ox, oy, geo, + iterator, user_data); + } +} + +static void drag_icons_for_each_surface(struct wl_list *drag_icons, + struct sway_output *output, struct root_geometry *geo, + wlr_surface_iterator_func_t iterator, void *user_data) { + struct sway_drag_icon *drag_icon; + wl_list_for_each(drag_icon, drag_icons, link) { + double ox = drag_icon->x - output->swayc->x; + double oy = drag_icon->y - output->swayc->y; + + if (drag_icon->wlr_drag_icon->mapped) { + surface_for_each_surface(drag_icon->wlr_drag_icon->surface, + ox, oy, geo, iterator, user_data); + } + } +} + +static void scale_box(struct wlr_box *box, float scale) { + box->x *= scale; + box->y *= scale; + box->width *= scale; + box->height *= scale; +} + +static void scissor_output(struct wlr_output *wlr_output, + pixman_box32_t *rect) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + assert(renderer); + + struct wlr_box box = { + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, + }; + + int ow, oh; + wlr_output_transformed_resolution(wlr_output, &ow, &oh); + + enum wl_output_transform transform = + wlr_output_transform_invert(wlr_output->transform); + wlr_box_transform(&box, transform, ow, oh, &box); + + wlr_renderer_scissor(renderer, &box); +} + +static void render_texture(struct wlr_output *wlr_output, + pixman_region32_t *output_damage, struct wlr_texture *texture, + const struct wlr_box *box, const float matrix[static 9], float alpha) { + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_union_rect(&damage, &damage, box->x, box->y, + box->width, box->height); + pixman_region32_intersect(&damage, &damage, output_damage); + bool damaged = pixman_region32_not_empty(&damage); + if (!damaged) { + goto damage_finish; + } + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); + } + +damage_finish: + pixman_region32_fini(&damage); +} + +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; + float rotation = data->root_geo.rotation; + pixman_region32_t *output_damage = data->damage; + float alpha = data->alpha; + + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (!texture) { + return; + } + + struct wlr_box box; + bool intersects = get_surface_box(&data->root_geo, data->output, surface, + sx, sy, &box); + if (!intersects) { + return; + } + + scale_box(&box, wlr_output->scale); + + float matrix[9]; + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current->transform); + wlr_matrix_project_box(matrix, &box, transform, rotation, + wlr_output->transform_matrix); + + render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); +} + +static void render_layer(struct sway_output *output, + pixman_region32_t *damage, struct wl_list *layer_surfaces) { + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + layer_for_each_surface(layer_surfaces, &data.root_geo, + render_surface_iterator, &data); +} + +static void render_unmanaged(struct sway_output *output, + pixman_region32_t *damage, struct wl_list *unmanaged) { + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + unmanaged_for_each_surface(unmanaged, output, &data.root_geo, + render_surface_iterator, &data); +} + +static void render_drag_icons(struct sway_output *output, + pixman_region32_t *damage, struct wl_list *drag_icons) { + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + drag_icons_for_each_surface(drag_icons, output, &data.root_geo, + render_surface_iterator, &data); +} + +static void render_rect(struct wlr_output *wlr_output, + pixman_region32_t *output_damage, const struct wlr_box *_box, + float color[static 4]) { + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + + struct wlr_box box; + memcpy(&box, _box, sizeof(struct wlr_box)); + box.x -= wlr_output->lx * wlr_output->scale; + box.y -= wlr_output->ly * wlr_output->scale; + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_union_rect(&damage, &damage, box.x, box.y, + box.width, box.height); + pixman_region32_intersect(&damage, &damage, output_damage); + bool damaged = pixman_region32_not_empty(&damage); + if (!damaged) { + goto damage_finish; + } + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_render_rect(renderer, &box, color, + wlr_output->transform_matrix); + } + +damage_finish: + pixman_region32_fini(&damage); +} + +static void premultiply_alpha(float color[4], float opacity) { + color[3] *= opacity; + color[0] *= color[3]; + color[1] *= color[3]; + color[2] *= color[3]; +} + +static void render_view_surfaces(struct sway_view *view, + struct sway_output *output, pixman_region32_t *damage, float alpha) { + struct render_data data = { + .output = output, + .damage = damage, + .view = view, + .alpha = alpha, + }; + output_view_for_each_surface( + view, &data.root_geo, render_surface_iterator, &data); +} + +static void render_saved_view(struct sway_view *view, + struct sway_output *output, pixman_region32_t *damage, float alpha) { + struct wlr_output *wlr_output = output->wlr_output; + + int width, height; + struct wlr_texture *texture = + transaction_get_saved_texture(view, &width, &height); + if (!texture) { + return; + } + struct wlr_box box = { + .x = view->swayc->current.view_x - output->swayc->current.swayc_x, + .y = view->swayc->current.view_y - output->swayc->current.swayc_y, + .width = width, + .height = height, + }; + + struct wlr_box output_box = { + .width = output->swayc->current.swayc_width, + .height = output->swayc->current.swayc_height, + }; + + struct wlr_box intersection; + bool intersects = wlr_box_intersection(&output_box, &box, &intersection); + if (!intersects) { + return; + } + + scale_box(&box, wlr_output->scale); + + float matrix[9]; + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, + wlr_output->transform_matrix); + + render_texture(wlr_output, damage, texture, &box, matrix, alpha); +} + +/** + * Render a view's surface and left/bottom/right borders. + */ +static void render_view(struct sway_output *output, pixman_region32_t *damage, + struct sway_container *con, struct border_colors *colors) { + struct sway_view *view = con->sway_view; + if (view->swayc->instructions->length) { + render_saved_view(view, output, damage, view->swayc->alpha); + } else { + render_view_surfaces(view, output, damage, view->swayc->alpha); + } + + struct wlr_box box; + float output_scale = output->wlr_output->scale; + float color[4]; + struct sway_container_state *state = &con->current; + + if (state->border != B_NONE) { + if (state->border_left) { + memcpy(&color, colors->child_border, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = state->swayc_x; + box.y = state->view_y; + box.width = state->border_thickness; + box.height = state->view_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + + if (state->border_right) { + if (state->parent->current.children->length == 1 + && state->parent->current.layout == L_HORIZ) { + memcpy(&color, colors->indicator, sizeof(float) * 4); + } else { + memcpy(&color, colors->child_border, sizeof(float) * 4); + } + premultiply_alpha(color, con->alpha); + box.x = state->view_x + state->view_width; + box.y = state->view_y; + box.width = state->border_thickness; + box.height = state->view_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + + if (state->border_bottom) { + if (state->parent->current.children->length == 1 + && con->current.parent->current.layout == L_VERT) { + memcpy(&color, colors->indicator, sizeof(float) * 4); + } else { + memcpy(&color, colors->child_border, sizeof(float) * 4); + } + premultiply_alpha(color, con->alpha); + box.x = state->swayc_x; + box.y = state->view_y + state->view_height; + box.width = state->swayc_width; + box.height = state->border_thickness; + scale_box(&box, output_scale); + render_rect(output->wlr_output, damage, &box, color); + } + } +} + +/** + * Render a titlebar. + * + * Care must be taken not to render over the same pixel multiple times, + * otherwise the colors will be incorrect when using opacity. + * + * The height is: 1px border, 3px padding, font height, 3px padding, 1px border + * The left side for L_TABBED is: 1px border, 2px padding, title + * The left side for other layouts is: 3px padding, title + */ +static void render_titlebar(struct sway_output *output, + pixman_region32_t *output_damage, struct sway_container *con, + int x, int y, int width, + struct border_colors *colors, struct wlr_texture *title_texture, + struct wlr_texture *marks_texture) { + struct wlr_box box; + float color[4]; + struct sway_container_state *state = &con->current; + float output_scale = output->wlr_output->scale; + enum sway_container_layout layout = state->parent->current.layout; + list_t *children = state->parent->current.children; + bool is_last_child = children->items[children->length - 1] == con; + double output_x = output->swayc->current.swayc_x; + double output_y = output->swayc->current.swayc_y; + + // Single pixel bar above title + memcpy(&color, colors->border, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = x; + box.y = y; + box.width = width; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Single pixel bar below title + size_t left_offset = 0, right_offset = 0; + bool connects_sides = false; + if (layout == L_HORIZ || layout == L_VERT || + (layout == L_STACKED && is_last_child)) { + if (con->type == C_VIEW) { + left_offset = state->border_left * state->border_thickness; + right_offset = state->border_right * state->border_thickness; + connects_sides = true; + } + } + box.x = x + left_offset; + box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; + box.width = width - left_offset - right_offset; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + if (layout == L_TABBED) { + // Single pixel left edge + box.x = x; + box.y = y + TITLEBAR_BORDER_THICKNESS; + box.width = TITLEBAR_BORDER_THICKNESS; + box.height = + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Single pixel right edge + box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale; + render_rect(output->wlr_output, output_damage, &box, color); + } + + size_t inner_width = width - TITLEBAR_H_PADDING * 2; + + // Marks + size_t marks_width = 0; + if (config->show_marks && marks_texture) { + struct wlr_box texture_box; + wlr_texture_get_size(marks_texture, + &texture_box.width, &texture_box.height); + texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) + * output_scale - texture_box.width; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + + float matrix[9]; + wlr_matrix_project_box(matrix, &texture_box, + WL_OUTPUT_TRANSFORM_NORMAL, + 0.0, output->wlr_output->transform_matrix); + + if (inner_width * output_scale < texture_box.width) { + texture_box.width = inner_width * output_scale; + } + render_texture(output->wlr_output, output_damage, marks_texture, + &texture_box, matrix, con->alpha); + marks_width = texture_box.width; + } + + // Title text + size_t title_width = 0; + if (title_texture) { + struct wlr_box texture_box; + wlr_texture_get_size(title_texture, + &texture_box.width, &texture_box.height); + texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; + texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + + float matrix[9]; + wlr_matrix_project_box(matrix, &texture_box, + WL_OUTPUT_TRANSFORM_NORMAL, + 0.0, output->wlr_output->transform_matrix); + + if (inner_width * output_scale - marks_width < texture_box.width) { + texture_box.width = inner_width * output_scale - marks_width; + } + render_texture(output->wlr_output, output_damage, title_texture, + &texture_box, matrix, con->alpha); + title_width = texture_box.width; + } + + // Padding above title + memcpy(&color, colors->background, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; + box.y = y + TITLEBAR_BORDER_THICKNESS; + box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2; + box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Padding below title + box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale; + render_rect(output->wlr_output, output_damage, &box, color); + + // Filler between title and marks + box.width = inner_width * output_scale - title_width - marks_width; + if (box.width > 0) { + box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width; + box.y = (y + TITLEBAR_V_PADDING) * output_scale; + box.height = config->font_height * output_scale; + render_rect(output->wlr_output, output_damage, &box, color); + } + + // Padding left of title + left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; + box.x = x + left_offset; + box.y = y + TITLEBAR_V_PADDING; + box.width = TITLEBAR_H_PADDING - left_offset; + box.height = config->font_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Padding right of marks + right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; + box.x = x + width - TITLEBAR_H_PADDING; + box.y = y + TITLEBAR_V_PADDING; + box.width = TITLEBAR_H_PADDING - right_offset; + box.height = config->font_height; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + if (connects_sides) { + // Left pixel in line with bottom bar + box.x = x; + box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; + box.width = state->border_thickness * state->border_left; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + + // Right pixel in line with bottom bar + box.x = x + width - state->border_thickness * state->border_right; + box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; + box.width = state->border_thickness * state->border_right; + box.height = TITLEBAR_BORDER_THICKNESS; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); + } +} + +/** + * Render the top border line for a view using "border pixel". + */ +static void render_top_border(struct sway_output *output, + pixman_region32_t *output_damage, struct sway_container *con, + struct border_colors *colors) { + struct sway_container_state *state = &con->current; + if (!state->border_top) { + return; + } + struct wlr_box box; + float color[4]; + float output_scale = output->wlr_output->scale; + + // Child border - top edge + memcpy(&color, colors->child_border, sizeof(float) * 4); + premultiply_alpha(color, con->alpha); + box.x = state->swayc_x; + box.y = state->swayc_y; + box.width = state->swayc_width; + box.height = state->border_thickness; + scale_box(&box, output_scale); + render_rect(output->wlr_output, output_damage, &box, color); +} + +static void render_container(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, bool parent_focused); + +/** + * Render a container's children using a L_HORIZ or L_VERT layout. + * + * Wrap child views in borders and leave child containers borderless because + * they'll apply their own borders to their children. + */ +static void render_container_simple(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + + if (child->type == C_VIEW) { + struct sway_view *view = child->sway_view; + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + struct sway_container_state *state = &child->current; + + if (focus == child || parent_focused) { + colors = &config->border_colors.focused; + title_texture = child->title_focused; + marks_texture = view->marks_focused; + } else if (seat_get_focus_inactive(seat, con) == child) { + colors = &config->border_colors.focused_inactive; + title_texture = child->title_focused_inactive; + marks_texture = view->marks_focused_inactive; + } else { + colors = &config->border_colors.unfocused; + title_texture = child->title_unfocused; + marks_texture = view->marks_unfocused; + } + + if (state->border == B_NORMAL) { + render_titlebar(output, damage, child, state->swayc_x, + state->swayc_y, state->swayc_width, colors, + title_texture, marks_texture); + } else { + render_top_border(output, damage, child, colors); + } + render_view(output, damage, child, colors); + } else { + render_container(output, damage, child, + parent_focused || focus == child); + } + } +} + +/** + * Render a container's children using the L_TABBED layout. + */ +static void render_container_tabbed(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + if (!con->current.children->length) { + return; + } + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *current = seat_get_active_current_child(seat, con); + struct border_colors *current_colors = &config->border_colors.unfocused; + struct sway_container_state *pstate = &con->current; + + // Render tabs + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + struct sway_container_state *cstate = &child->current; + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + + if (focus == child || parent_focused) { + colors = &config->border_colors.focused; + title_texture = child->title_focused; + marks_texture = view ? view->marks_focused : NULL; + } else if (child == current) { + colors = &config->border_colors.focused_inactive; + title_texture = child->title_focused_inactive; + marks_texture = view ? view->marks_focused_inactive : NULL; + } else { + colors = &config->border_colors.unfocused; + title_texture = child->title_unfocused; + marks_texture = view ? view->marks_unfocused : NULL; + } + + int tab_width = pstate->swayc_width / pstate->children->length; + int x = pstate->swayc_x + tab_width * i; + // Make last tab use the remaining width of the parent + if (i == pstate->children->length - 1) { + tab_width = pstate->swayc_width - tab_width * i; + } + + render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, + colors, title_texture, marks_texture); + + if (child == current) { + current_colors = colors; + } + } + + // Render surface and left/right/bottom borders + if (current) { + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current == focus); + } + } +} + +/** + * Render a container's children using the L_STACKED layout. + */ +static void render_container_stacked(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + if (!con->current.children->length) { + return; + } + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct sway_container *current = seat_get_active_current_child(seat, con); + struct border_colors *current_colors = &config->border_colors.unfocused; + struct sway_container_state *pstate = &con->current; + + // Render titles + for (int i = 0; i < con->current.children->length; ++i) { + struct sway_container *child = con->current.children->items[i]; + struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; + struct sway_container_state *cstate = &child->current; + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + + if (focus == child || parent_focused) { + colors = &config->border_colors.focused; + title_texture = child->title_focused; + marks_texture = view ? view->marks_focused : NULL; + } else if (child == current) { + colors = &config->border_colors.focused_inactive; + title_texture = child->title_focused_inactive; + marks_texture = view ? view->marks_focused_inactive : NULL; + } else { + colors = &config->border_colors.unfocused; + title_texture = child->title_unfocused; + marks_texture = view ? view->marks_unfocused : NULL; + } + + int y = pstate->swayc_y + container_titlebar_height() * i; + render_titlebar(output, damage, child, cstate->swayc_x, y, + cstate->swayc_width, colors, title_texture, marks_texture); + + if (child == current) { + current_colors = colors; + } + } + + // Render surface and left/right/bottom borders + if (current) { + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current == focus); + } + } +} + +static void render_container(struct sway_output *output, + pixman_region32_t *damage, struct sway_container *con, + bool parent_focused) { + switch (con->current.layout) { + case L_NONE: + case L_HORIZ: + case L_VERT: + render_container_simple(output, damage, con, parent_focused); + break; + case L_STACKED: + render_container_stacked(output, damage, con, parent_focused); + break; + case L_TABBED: + render_container_tabbed(output, damage, con, parent_focused); + break; + case L_FLOATING: + sway_assert(false, "Didn't expect to see floating here"); + } +} + +static void render_floating_container(struct sway_output *soutput, + pixman_region32_t *damage, struct sway_container *con) { + if (con->type == C_VIEW) { + struct sway_view *view = con->sway_view; + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + struct border_colors *colors; + struct wlr_texture *title_texture; + struct wlr_texture *marks_texture; + + if (focus == con) { + colors = &config->border_colors.focused; + title_texture = con->title_focused; + marks_texture = view->marks_focused; + } else { + colors = &config->border_colors.unfocused; + title_texture = con->title_unfocused; + marks_texture = view->marks_unfocused; + } + + if (con->current.border == B_NORMAL) { + render_titlebar(soutput, damage, con, con->current.swayc_x, + con->current.swayc_y, con->current.swayc_width, colors, + title_texture, marks_texture); + } else if (con->current.border != B_NONE) { + render_top_border(soutput, damage, con, colors); + } + render_view(soutput, damage, con, colors); + } else { + render_container(soutput, damage, con, false); + } +} + +static void render_floating(struct sway_output *soutput, + pixman_region32_t *damage) { + for (int i = 0; i < root_container.current.children->length; ++i) { + struct sway_container *output = + root_container.current.children->items[i]; + for (int j = 0; j < output->current.children->length; ++j) { + struct sway_container *ws = output->current.children->items[j]; + if (!workspace_is_visible(ws)) { + continue; + } + list_t *floating = + ws->current.ws_floating->current.children; + for (int k = 0; k < floating->length; ++k) { + struct sway_container *floater = floating->items[k]; + render_floating_container(soutput, damage, floater); + } + } + } +} + +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->current.children->items[0]; + } + struct sway_container *workspace = focus; + if (workspace->type != C_WORKSPACE) { + workspace = container_parent(workspace, C_WORKSPACE); + } + return workspace; +} + +void render_output(struct sway_output *output, struct timespec *when, + pixman_region32_t *damage) { + struct wlr_output *wlr_output = output->wlr_output; + + struct wlr_renderer *renderer = + wlr_backend_get_renderer(wlr_output->backend); + if (!sway_assert(renderer != NULL, + "expected the output backend to have a renderer")) { + return; + } + + wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); + + bool damage_whole_before_swap = false; + if (!pixman_region32_not_empty(damage)) { + // Output isn't damaged but needs buffer swap + goto renderer_end; + } + + const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG"); + if (damage_debug != NULL) { + if (strcmp(damage_debug, "highlight") == 0) { + wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); + damage_whole_before_swap = true; + } else if (strcmp(damage_debug, "rerender") == 0) { + int width, height; + wlr_output_transformed_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(damage, damage, 0, 0, width, height); + } + } + + struct sway_container *workspace = output_get_active_workspace(output); + struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; + + if (fullscreen_view) { + float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, clear_color); + } + + // TODO: handle views smaller than the output + render_view_surfaces(fullscreen_view, output, damage, 1.0f); + + if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { + render_unmanaged(output, damage, + &root_container.sway_root->xwayland_unmanaged); + } + } else { + float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, clear_color); + } + + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = seat_get_focus(seat); + render_container(output, damage, workspace, focus == workspace); + render_floating(output, damage); + + render_unmanaged(output, damage, + &root_container.sway_root->xwayland_unmanaged); + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + } + render_layer(output, damage, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + render_drag_icons(output, damage, &root_container.sway_root->drag_icons); + +renderer_end: + if (root_container.sway_root->debug_tree) { + wlr_render_texture(renderer, root_container.sway_root->debug_tree, + wlr_output->transform_matrix, 0, 0, 1); + } + + if (damage_whole_before_swap || root_container.sway_root->debug_tree) { + int width, height; + wlr_output_transformed_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(damage, damage, 0, 0, width, height); + } + + wlr_renderer_scissor(renderer, NULL); + wlr_renderer_end(renderer); + if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) { + return; + } + output->last_frame = *when; +} diff --git a/sway/meson.build b/sway/meson.build index a81a3406f..e492aeeed 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -13,6 +13,7 @@ sway_sources = files( 'desktop/idle_inhibit_v1.c', 'desktop/layer_shell.c', 'desktop/output.c', + 'desktop/render.c', 'desktop/transaction.c', 'desktop/xdg_shell_v6.c', 'desktop/xdg_shell.c', From d2d530bd092cbd754dff182f59fc1defa4a6e9cb Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 12:50:54 +1000 Subject: [PATCH 02/11] Introduce render_context and reduce number of function arguments This adds a struct render_context which contains the commonly accessed output-specific properties and saves us from having to pass them through several functions as arguments. --- sway/desktop/render.c | 330 +++++++++++++++++++----------------------- 1 file changed, 152 insertions(+), 178 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index bb1b26a93..0de8bdd97 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -27,6 +27,15 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" +struct render_context { + struct sway_output *output; + int output_lx; + int output_ly; + pixman_region32_t *damage; + float scale; +}; +struct render_context context; + /** * Rotate a child's position relative to a parent. The parent size is (pw, ph), * the child position is (*sx, *sy) and its size is (sw, sh). @@ -66,7 +75,7 @@ struct render_data { }; static bool get_surface_box(struct root_geometry *geo, - struct sway_output *output, struct wlr_surface *surface, int sx, int sy, + struct wlr_surface *surface, int sx, int sy, struct wlr_box *surface_box) { if (!wlr_surface_has_buffer(surface)) { return false; @@ -93,8 +102,8 @@ static bool get_surface_box(struct root_geometry *geo, wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box); struct wlr_box output_box = { - .width = output->swayc->current.swayc_width, - .height = output->swayc->current.swayc_height, + .width = context.output->swayc->current.swayc_width, + .height = context.output->swayc->current.swayc_height, }; struct wlr_box intersection; @@ -116,9 +125,10 @@ static void surface_for_each_surface(struct wlr_surface *surface, static void output_view_for_each_surface(struct sway_view *view, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { - struct render_data *data = user_data; - geo->x = view->swayc->current.view_x - data->output->swayc->current.swayc_x; - geo->y = view->swayc->current.view_y - data->output->swayc->current.swayc_y; + geo->x = + view->swayc->current.view_x - context.output->swayc->current.swayc_x; + geo->y = + view->swayc->current.view_y - context.output->swayc->current.swayc_y; geo->width = view->swayc->current.view_width; geo->height = view->swayc->current.view_height; geo->rotation = 0; // TODO @@ -140,14 +150,14 @@ static void layer_for_each_surface(struct wl_list *layer_surfaces, } 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 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->current.swayc_x; - double oy = unmanaged_surface->ly - output->swayc->current.swayc_y; + double ox = unmanaged_surface->lx - context.output_lx; + double oy = unmanaged_surface->ly - context.output_ly; surface_for_each_surface(xsurface->surface, ox, oy, geo, iterator, user_data); @@ -155,12 +165,12 @@ static void unmanaged_for_each_surface(struct wl_list *unmanaged, } static void drag_icons_for_each_surface(struct wl_list *drag_icons, - struct sway_output *output, struct root_geometry *geo, - wlr_surface_iterator_func_t iterator, void *user_data) { + struct root_geometry *geo, wlr_surface_iterator_func_t iterator, + void *user_data) { struct sway_drag_icon *drag_icon; wl_list_for_each(drag_icon, drag_icons, link) { - double ox = drag_icon->x - output->swayc->x; - double oy = drag_icon->y - output->swayc->y; + double ox = drag_icon->x - context.output_lx; + double oy = drag_icon->y - context.output_ly; if (drag_icon->wlr_drag_icon->mapped) { surface_for_each_surface(drag_icon->wlr_drag_icon->surface, @@ -198,9 +208,9 @@ static void scissor_output(struct wlr_output *wlr_output, wlr_renderer_scissor(renderer, &box); } -static void render_texture(struct wlr_output *wlr_output, - pixman_region32_t *output_damage, struct wlr_texture *texture, +static void render_texture(struct wlr_texture *texture, const struct wlr_box *box, const float matrix[static 9], float alpha) { + struct wlr_output *wlr_output = context.output->wlr_output; struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); @@ -208,7 +218,7 @@ static void render_texture(struct wlr_output *wlr_output, pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, box->x, box->y, box->width, box->height); - pixman_region32_intersect(&damage, &damage, output_damage); + pixman_region32_intersect(&damage, &damage, context.damage); bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { goto damage_finish; @@ -228,9 +238,8 @@ damage_finish: 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 wlr_output *wlr_output = context.output->wlr_output; float rotation = data->root_geo.rotation; - pixman_region32_t *output_damage = data->damage; float alpha = data->alpha; struct wlr_texture *texture = wlr_surface_get_texture(surface); @@ -239,13 +248,12 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, } struct wlr_box box; - bool intersects = get_surface_box(&data->root_geo, data->output, surface, - sx, sy, &box); + bool intersects = get_surface_box(&data->root_geo, surface, sx, sy, &box); if (!intersects) { return; } - scale_box(&box, wlr_output->scale); + scale_box(&box, context.scale); float matrix[9]; enum wl_output_transform transform = @@ -253,58 +261,48 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, wlr_matrix_project_box(matrix, &box, transform, rotation, wlr_output->transform_matrix); - render_texture(wlr_output, output_damage, texture, &box, matrix, alpha); + render_texture(texture, &box, matrix, alpha); } -static void render_layer(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *layer_surfaces) { +static void render_layer(struct wl_list *layer_surfaces) { struct render_data data = { - .output = output, - .damage = damage, .alpha = 1.0f, }; layer_for_each_surface(layer_surfaces, &data.root_geo, render_surface_iterator, &data); } -static void render_unmanaged(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *unmanaged) { +static void render_unmanaged(struct wl_list *unmanaged) { struct render_data data = { - .output = output, - .damage = damage, .alpha = 1.0f, }; - unmanaged_for_each_surface(unmanaged, output, &data.root_geo, + unmanaged_for_each_surface(unmanaged, &data.root_geo, render_surface_iterator, &data); } -static void render_drag_icons(struct sway_output *output, - pixman_region32_t *damage, struct wl_list *drag_icons) { +static void render_drag_icons(struct wl_list *drag_icons) { struct render_data data = { - .output = output, - .damage = damage, .alpha = 1.0f, }; - drag_icons_for_each_surface(drag_icons, output, &data.root_geo, + drag_icons_for_each_surface(drag_icons, &data.root_geo, render_surface_iterator, &data); } -static void render_rect(struct wlr_output *wlr_output, - pixman_region32_t *output_damage, const struct wlr_box *_box, - float color[static 4]) { +static void render_rect(const struct wlr_box *_box, float color[static 4]) { + struct wlr_output *wlr_output = context.output->wlr_output; struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); struct wlr_box box; memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= wlr_output->lx * wlr_output->scale; - box.y -= wlr_output->ly * wlr_output->scale; + box.x -= context.output_lx * context.scale; + box.y -= context.output_ly * context.scale; pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, box.x, box.y, box.width, box.height); - pixman_region32_intersect(&damage, &damage, output_damage); + pixman_region32_intersect(&damage, &damage, context.damage); bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { goto damage_finish; @@ -314,8 +312,7 @@ static void render_rect(struct wlr_output *wlr_output, pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(wlr_output, &rects[i]); - wlr_render_rect(renderer, &box, color, - wlr_output->transform_matrix); + wlr_render_rect(renderer, &box, color, wlr_output->transform_matrix); } damage_finish: @@ -329,11 +326,8 @@ static void premultiply_alpha(float color[4], float opacity) { color[2] *= color[3]; } -static void render_view_surfaces(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { +static void render_view_surfaces(struct sway_view *view, float alpha) { struct render_data data = { - .output = output, - .damage = damage, .view = view, .alpha = alpha, }; @@ -341,10 +335,7 @@ static void render_view_surfaces(struct sway_view *view, view, &data.root_geo, render_surface_iterator, &data); } -static void render_saved_view(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { - struct wlr_output *wlr_output = output->wlr_output; - +static void render_saved_view(struct sway_view *view, float alpha) { int width, height; struct wlr_texture *texture = transaction_get_saved_texture(view, &width, &height); @@ -352,15 +343,15 @@ static void render_saved_view(struct sway_view *view, return; } struct wlr_box box = { - .x = view->swayc->current.view_x - output->swayc->current.swayc_x, - .y = view->swayc->current.view_y - output->swayc->current.swayc_y, + .x = view->swayc->current.view_x - context.output_lx, + .y = view->swayc->current.view_y - context.output_ly, .width = width, .height = height, }; struct wlr_box output_box = { - .width = output->swayc->current.swayc_width, - .height = output->swayc->current.swayc_height, + .width = context.output->swayc->current.swayc_width, + .height = context.output->swayc->current.swayc_height, }; struct wlr_box intersection; @@ -369,29 +360,28 @@ static void render_saved_view(struct sway_view *view, return; } - scale_box(&box, wlr_output->scale); + scale_box(&box, context.scale); float matrix[9]; wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0, - wlr_output->transform_matrix); + context.output->wlr_output->transform_matrix); - render_texture(wlr_output, damage, texture, &box, matrix, alpha); + render_texture(texture, &box, matrix, alpha); } /** * Render a view's surface and left/bottom/right borders. */ -static void render_view(struct sway_output *output, pixman_region32_t *damage, - struct sway_container *con, struct border_colors *colors) { +static void render_view(struct sway_container *con, + struct border_colors *colors) { struct sway_view *view = con->sway_view; if (view->swayc->instructions->length) { - render_saved_view(view, output, damage, view->swayc->alpha); + render_saved_view(view, view->swayc->alpha); } else { - render_view_surfaces(view, output, damage, view->swayc->alpha); + render_view_surfaces(view, view->swayc->alpha); } struct wlr_box box; - float output_scale = output->wlr_output->scale; float color[4]; struct sway_container_state *state = &con->current; @@ -403,8 +393,8 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, box.y = state->view_y; box.width = state->border_thickness; box.height = state->view_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); } if (state->border_right) { @@ -419,8 +409,8 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, box.y = state->view_y; box.width = state->border_thickness; box.height = state->view_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); } if (state->border_bottom) { @@ -435,8 +425,8 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, box.y = state->view_y + state->view_height; box.width = state->swayc_width; box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(output->wlr_output, damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); } } } @@ -451,20 +441,15 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, * The left side for L_TABBED is: 1px border, 2px padding, title * The left side for other layouts is: 3px padding, title */ -static void render_titlebar(struct sway_output *output, - pixman_region32_t *output_damage, struct sway_container *con, - int x, int y, int width, +static void render_titlebar(struct sway_container *con, int x, int y, int width, struct border_colors *colors, struct wlr_texture *title_texture, struct wlr_texture *marks_texture) { struct wlr_box box; float color[4]; struct sway_container_state *state = &con->current; - float output_scale = output->wlr_output->scale; enum sway_container_layout layout = state->parent->current.layout; list_t *children = state->parent->current.children; bool is_last_child = children->items[children->length - 1] == con; - double output_x = output->swayc->current.swayc_x; - double output_y = output->swayc->current.swayc_y; // Single pixel bar above title memcpy(&color, colors->border, sizeof(float) * 4); @@ -473,8 +458,8 @@ static void render_titlebar(struct sway_output *output, box.y = y; box.width = width; box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); // Single pixel bar below title size_t left_offset = 0, right_offset = 0; @@ -491,8 +476,8 @@ static void render_titlebar(struct sway_output *output, box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; box.width = width - left_offset - right_offset; box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); if (layout == L_TABBED) { // Single pixel left edge @@ -501,12 +486,12 @@ static void render_titlebar(struct sway_output *output, box.width = TITLEBAR_BORDER_THICKNESS; box.height = container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); // Single pixel right edge - box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); + box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * context.scale; + render_rect(&box, color); } size_t inner_width = width - TITLEBAR_H_PADDING * 2; @@ -517,20 +502,20 @@ static void render_titlebar(struct sway_output *output, struct wlr_box texture_box; wlr_texture_get_size(marks_texture, &texture_box.width, &texture_box.height); - texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) - * output_scale - texture_box.width; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + texture_box.x = (x - context.output_lx + width - TITLEBAR_H_PADDING) + * context.scale - texture_box.width; + texture_box.y = (y - context.output_ly + TITLEBAR_V_PADDING) + * context.scale; float matrix[9]; wlr_matrix_project_box(matrix, &texture_box, WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); + 0.0, context.output->wlr_output->transform_matrix); - if (inner_width * output_scale < texture_box.width) { - texture_box.width = inner_width * output_scale; + if (inner_width * context.scale < texture_box.width) { + texture_box.width = inner_width * context.scale; } - render_texture(output->wlr_output, output_damage, marks_texture, - &texture_box, matrix, con->alpha); + render_texture(marks_texture, &texture_box, matrix, con->alpha); marks_width = texture_box.width; } @@ -540,19 +525,20 @@ static void render_titlebar(struct sway_output *output, struct wlr_box texture_box; wlr_texture_get_size(title_texture, &texture_box.width, &texture_box.height); - texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; - texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale; + texture_box.x = + (x - context.output_lx + TITLEBAR_H_PADDING) * context.scale; + texture_box.y = + (y - context.output_ly + TITLEBAR_V_PADDING) * context.scale; float matrix[9]; wlr_matrix_project_box(matrix, &texture_box, WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); + 0.0, context.output->wlr_output->transform_matrix); - if (inner_width * output_scale - marks_width < texture_box.width) { - texture_box.width = inner_width * output_scale - marks_width; + if (inner_width * context.scale - marks_width < texture_box.width) { + texture_box.width = inner_width * context.scale - marks_width; } - render_texture(output->wlr_output, output_damage, title_texture, - &texture_box, matrix, con->alpha); + render_texture(title_texture, &texture_box, matrix, con->alpha); title_width = texture_box.width; } @@ -563,20 +549,20 @@ static void render_titlebar(struct sway_output *output, box.y = y + TITLEBAR_BORDER_THICKNESS; box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2; box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); // Padding below title - box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); + box.y = (y + TITLEBAR_V_PADDING + config->font_height) * context.scale; + render_rect(&box, color); // Filler between title and marks - box.width = inner_width * output_scale - title_width - marks_width; + box.width = inner_width * context.scale - title_width - marks_width; if (box.width > 0) { - box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_width; - box.y = (y + TITLEBAR_V_PADDING) * output_scale; - box.height = config->font_height * output_scale; - render_rect(output->wlr_output, output_damage, &box, color); + box.x = (x + TITLEBAR_H_PADDING) * context.scale + title_width; + box.y = (y + TITLEBAR_V_PADDING) * context.scale; + box.height = config->font_height * context.scale; + render_rect(&box, color); } // Padding left of title @@ -585,8 +571,8 @@ static void render_titlebar(struct sway_output *output, box.y = y + TITLEBAR_V_PADDING; box.width = TITLEBAR_H_PADDING - left_offset; box.height = config->font_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); // Padding right of marks right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; @@ -594,8 +580,8 @@ static void render_titlebar(struct sway_output *output, box.y = y + TITLEBAR_V_PADDING; box.width = TITLEBAR_H_PADDING - right_offset; box.height = config->font_height; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); if (connects_sides) { // Left pixel in line with bottom bar @@ -603,24 +589,23 @@ static void render_titlebar(struct sway_output *output, box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; box.width = state->border_thickness * state->border_left; box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); // Right pixel in line with bottom bar box.x = x + width - state->border_thickness * state->border_right; box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS; box.width = state->border_thickness * state->border_right; box.height = TITLEBAR_BORDER_THICKNESS; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); } } /** * Render the top border line for a view using "border pixel". */ -static void render_top_border(struct sway_output *output, - pixman_region32_t *output_damage, struct sway_container *con, +static void render_top_border(struct sway_container *con, struct border_colors *colors) { struct sway_container_state *state = &con->current; if (!state->border_top) { @@ -628,7 +613,6 @@ static void render_top_border(struct sway_output *output, } struct wlr_box box; float color[4]; - float output_scale = output->wlr_output->scale; // Child border - top edge memcpy(&color, colors->child_border, sizeof(float) * 4); @@ -637,12 +621,11 @@ static void render_top_border(struct sway_output *output, box.y = state->swayc_y; box.width = state->swayc_width; box.height = state->border_thickness; - scale_box(&box, output_scale); - render_rect(output->wlr_output, output_damage, &box, color); + scale_box(&box, context.scale); + render_rect(&box, color); } -static void render_container(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, bool parent_focused); +static void render_container(struct sway_container *con, bool parent_focused); /** * Render a container's children using a L_HORIZ or L_VERT layout. @@ -650,8 +633,7 @@ static void render_container(struct sway_output *output, * Wrap child views in borders and leave child containers borderless because * they'll apply their own borders to their children. */ -static void render_container_simple(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, +static void render_container_simple(struct sway_container *con, bool parent_focused) { struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus(seat); @@ -681,16 +663,15 @@ static void render_container_simple(struct sway_output *output, } if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, state->swayc_x, - state->swayc_y, state->swayc_width, colors, + render_titlebar(child, state->swayc_x, state->swayc_y, + state->swayc_width, colors, title_texture, marks_texture); } else { - render_top_border(output, damage, child, colors); + render_top_border(child, colors); } - render_view(output, damage, child, colors); + render_view(child, colors); } else { - render_container(output, damage, child, - parent_focused || focus == child); + render_container(child, parent_focused || focus == child); } } } @@ -698,8 +679,7 @@ static void render_container_simple(struct sway_output *output, /** * Render a container's children using the L_TABBED layout. */ -static void render_container_tabbed(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, +static void render_container_tabbed(struct sway_container *con, bool parent_focused) { if (!con->current.children->length) { return; @@ -740,8 +720,8 @@ static void render_container_tabbed(struct sway_output *output, tab_width = pstate->swayc_width - tab_width * i; } - render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, - colors, title_texture, marks_texture); + render_titlebar(child, x, cstate->swayc_y, tab_width, colors, + title_texture, marks_texture); if (child == current) { current_colors = colors; @@ -751,10 +731,9 @@ static void render_container_tabbed(struct sway_output *output, // Render surface and left/right/bottom borders if (current) { if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); + render_view(current, current_colors); } else { - render_container(output, damage, current, - parent_focused || current == focus); + render_container(current, parent_focused || current == focus); } } } @@ -762,8 +741,7 @@ static void render_container_tabbed(struct sway_output *output, /** * Render a container's children using the L_STACKED layout. */ -static void render_container_stacked(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, +static void render_container_stacked(struct sway_container *con, bool parent_focused) { if (!con->current.children->length) { return; @@ -798,8 +776,8 @@ static void render_container_stacked(struct sway_output *output, } int y = pstate->swayc_y + container_titlebar_height() * i; - render_titlebar(output, damage, child, cstate->swayc_x, y, - cstate->swayc_width, colors, title_texture, marks_texture); + render_titlebar(child, cstate->swayc_x, y, cstate->swayc_width, colors, + title_texture, marks_texture); if (child == current) { current_colors = colors; @@ -809,36 +787,32 @@ static void render_container_stacked(struct sway_output *output, // Render surface and left/right/bottom borders if (current) { if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); + render_view(current, current_colors); } else { - render_container(output, damage, current, - parent_focused || current == focus); + render_container(current, parent_focused || current == focus); } } } -static void render_container(struct sway_output *output, - pixman_region32_t *damage, struct sway_container *con, - bool parent_focused) { +static void render_container(struct sway_container *con, bool parent_focused) { switch (con->current.layout) { case L_NONE: case L_HORIZ: case L_VERT: - render_container_simple(output, damage, con, parent_focused); + render_container_simple(con, parent_focused); break; case L_STACKED: - render_container_stacked(output, damage, con, parent_focused); + render_container_stacked(con, parent_focused); break; case L_TABBED: - render_container_tabbed(output, damage, con, parent_focused); + render_container_tabbed(con, parent_focused); break; case L_FLOATING: sway_assert(false, "Didn't expect to see floating here"); } } -static void render_floating_container(struct sway_output *soutput, - pixman_region32_t *damage, struct sway_container *con) { +static void render_floating_container(struct sway_container *con) { if (con->type == C_VIEW) { struct sway_view *view = con->sway_view; struct sway_seat *seat = input_manager_current_seat(input_manager); @@ -858,20 +832,19 @@ static void render_floating_container(struct sway_output *soutput, } if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, con->current.swayc_x, - con->current.swayc_y, con->current.swayc_width, colors, + render_titlebar(con, con->current.swayc_x, con->current.swayc_y, + con->current.swayc_width, colors, title_texture, marks_texture); } else if (con->current.border != B_NONE) { - render_top_border(soutput, damage, con, colors); + render_top_border(con, colors); } - render_view(soutput, damage, con, colors); + render_view(con, colors); } else { - render_container(soutput, damage, con, false); + render_container(con, false); } } -static void render_floating(struct sway_output *soutput, - pixman_region32_t *damage) { +static void render_floating() { for (int i = 0; i < root_container.current.children->length; ++i) { struct sway_container *output = root_container.current.children->items[i]; @@ -884,7 +857,7 @@ static void render_floating(struct sway_output *soutput, ws->current.ws_floating->current.children; for (int k = 0; k < floating->length; ++k) { struct sway_container *floater = floating->items[k]; - render_floating_container(soutput, damage, floater); + render_floating_container(floater); } } } @@ -910,6 +883,13 @@ void render_output(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; + memset(&context, 0, sizeof(struct render_context)); + context.output = output; + context.output_lx = output->swayc->current.swayc_x; + context.output_ly = output->swayc->current.swayc_y; + context.damage = damage; + context.scale = output->wlr_output->scale; + struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); if (!sway_assert(renderer != NULL, @@ -951,11 +931,10 @@ void render_output(struct sway_output *output, struct timespec *when, } // TODO: handle views smaller than the output - render_view_surfaces(fullscreen_view, output, damage, 1.0f); + render_view_surfaces(fullscreen_view, 1.0f); if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); + render_unmanaged(&root_container.sway_root->xwayland_unmanaged); } } else { float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; @@ -967,24 +946,19 @@ void render_output(struct sway_output *output, struct timespec *when, wlr_renderer_clear(renderer, clear_color); } - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus(seat); - render_container(output, damage, workspace, focus == workspace); - render_floating(output, damage); + render_container(workspace, focus == workspace); + render_floating(); - render_unmanaged(output, damage, - &root_container.sway_root->xwayland_unmanaged); - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); + render_unmanaged(&root_container.sway_root->xwayland_unmanaged); + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); } - render_layer(output, damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_drag_icons(output, damage, &root_container.sway_root->drag_icons); + render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); + render_drag_icons(&root_container.sway_root->drag_icons); renderer_end: if (root_container.sway_root->debug_tree) { From 8afe308be84e4dca14ff72c31b5e659399d1fb22 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 13:14:11 +1000 Subject: [PATCH 03/11] Remove output_view_for_each_surface --- sway/desktop/render.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 0de8bdd97..48c9cf817 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -122,20 +122,6 @@ static void surface_for_each_surface(struct wlr_surface *surface, wlr_surface_for_each_surface(surface, iterator, user_data); } -static void output_view_for_each_surface(struct sway_view *view, - struct root_geometry *geo, wlr_surface_iterator_func_t iterator, - void *user_data) { - geo->x = - view->swayc->current.view_x - context.output->swayc->current.swayc_x; - geo->y = - view->swayc->current.view_y - context.output->swayc->current.swayc_y; - geo->width = view->swayc->current.view_width; - geo->height = view->swayc->current.view_height; - geo->rotation = 0; // TODO - - 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) { @@ -331,8 +317,15 @@ static void render_view_surfaces(struct sway_view *view, float alpha) { .view = view, .alpha = alpha, }; - output_view_for_each_surface( - view, &data.root_geo, render_surface_iterator, &data); + data.root_geo.x = + view->swayc->current.view_x - context.output->swayc->current.swayc_x; + data.root_geo.y = + view->swayc->current.view_y - context.output->swayc->current.swayc_y; + data.root_geo.width = view->swayc->current.view_width; + data.root_geo.height = view->swayc->current.view_height; + data.root_geo.rotation = 0; // TODO + + view_for_each_surface(view, render_surface_iterator, &data); } static void render_saved_view(struct sway_view *view, float alpha) { From f16142a488b74fa7932ee6d523a7ee8a8f856d66 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 13:17:59 +1000 Subject: [PATCH 04/11] Remove unmanaged_for_each_surface --- sway/desktop/render.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 48c9cf817..91aaf7303 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -135,21 +135,6 @@ static void layer_for_each_surface(struct wl_list *layer_surfaces, } } -static void unmanaged_for_each_surface(struct wl_list *unmanaged, - 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 - context.output_lx; - double oy = unmanaged_surface->ly - context.output_ly; - - surface_for_each_surface(xsurface->surface, ox, oy, geo, - iterator, user_data); - } -} - static void drag_icons_for_each_surface(struct wl_list *drag_icons, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { @@ -262,8 +247,16 @@ static void render_unmanaged(struct wl_list *unmanaged) { struct render_data data = { .alpha = 1.0f, }; - unmanaged_for_each_surface(unmanaged, &data.root_geo, - render_surface_iterator, &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 - context.output_lx; + double oy = unmanaged_surface->ly - context.output_ly; + + surface_for_each_surface(xsurface->surface, ox, oy, &data.root_geo, + render_surface_iterator, &data); + } } static void render_drag_icons(struct wl_list *drag_icons) { From 57eb7d964360a8bc04fba24334fd4509b50ed8bd Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 13:20:23 +1000 Subject: [PATCH 05/11] Remove layer_for_each_surface --- sway/desktop/render.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 91aaf7303..e8d92cba1 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -122,19 +122,6 @@ static void surface_for_each_surface(struct wlr_surface *surface, wlr_surface_for_each_surface(surface, 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 drag_icons_for_each_surface(struct wl_list *drag_icons, struct root_geometry *geo, wlr_surface_iterator_func_t iterator, void *user_data) { @@ -239,8 +226,14 @@ static void render_layer(struct wl_list *layer_surfaces) { struct render_data data = { .alpha = 1.0f, }; - layer_for_each_surface(layer_surfaces, &data.root_geo, - render_surface_iterator, &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, &data.root_geo, + render_surface_iterator, &data); + } } static void render_unmanaged(struct wl_list *unmanaged) { From c8d4a1ae1d9004840a79eed8640b5be4c33e7de3 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 13:22:15 +1000 Subject: [PATCH 06/11] Remove drag_icons_for_each_surface --- sway/desktop/render.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index e8d92cba1..7a843278c 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -122,21 +122,6 @@ static void surface_for_each_surface(struct wlr_surface *surface, wlr_surface_for_each_surface(surface, iterator, user_data); } -static void drag_icons_for_each_surface(struct wl_list *drag_icons, - struct root_geometry *geo, wlr_surface_iterator_func_t iterator, - void *user_data) { - struct sway_drag_icon *drag_icon; - wl_list_for_each(drag_icon, drag_icons, link) { - double ox = drag_icon->x - context.output_lx; - double oy = drag_icon->y - context.output_ly; - - if (drag_icon->wlr_drag_icon->mapped) { - surface_for_each_surface(drag_icon->wlr_drag_icon->surface, - ox, oy, geo, iterator, user_data); - } - } -} - static void scale_box(struct wlr_box *box, float scale) { box->x *= scale; box->y *= scale; @@ -256,8 +241,16 @@ static void render_drag_icons(struct wl_list *drag_icons) { struct render_data data = { .alpha = 1.0f, }; - drag_icons_for_each_surface(drag_icons, &data.root_geo, - render_surface_iterator, &data); + struct sway_drag_icon *drag_icon; + wl_list_for_each(drag_icon, drag_icons, link) { + double ox = drag_icon->x - context.output_lx; + double oy = drag_icon->y - context.output_ly; + + if (drag_icon->wlr_drag_icon->mapped) { + surface_for_each_surface(drag_icon->wlr_drag_icon->surface, + ox, oy, &data.root_geo, render_surface_iterator, &data); + } + } } static void render_rect(const struct wlr_box *_box, float color[static 4]) { From 7313abe350e57bc3b9074c0e4734d3dbe0681f45 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 13:41:34 +1000 Subject: [PATCH 07/11] Remove rotation code This seems to have been copied from rootston. --- sway/desktop/render.c | 39 ++++----------------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 7a843278c..6eab71294 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -36,26 +36,6 @@ struct render_context { }; struct render_context context; -/** - * Rotate a child's position relative to a parent. The parent size is (pw, ph), - * the child position is (*sx, *sy) and its size is (sw, sh). - */ -static void rotate_child_position(double *sx, double *sy, double sw, double sh, - double pw, double ph, float rotation) { - if (rotation == 0.0f) { - return; - } - - // Coordinates relative to the center of the subsurface - double ox = *sx - pw/2 + sw/2, - oy = *sy - ph/2 + sh/2; - // Rotated coordinates - double rx = cos(-rotation)*ox - sin(-rotation)*oy, - ry = cos(-rotation)*oy + sin(-rotation)*ox; - *sx = rx + pw/2 - sw/2; - *sy = ry + ph/2 - sh/2; -} - /** * Contains a surface's root geometry information. For instance, when rendering * a popup, this will contain the parent view's position and size. @@ -63,7 +43,6 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, struct root_geometry { double x, y; int width, height; - float rotation; }; struct render_data { @@ -84,13 +63,9 @@ static bool get_surface_box(struct root_geometry *geo, int sw = surface->current->width; int sh = surface->current->height; - double _sx = sx, _sy = sy; - rotate_child_position(&_sx, &_sy, sw, sh, geo->width, geo->height, - geo->rotation); - struct wlr_box box = { - .x = geo->x + _sx, - .y = geo->y + _sy, + .x = geo->x + sx, + .y = geo->y + sy, .width = sw, .height = sh, }; @@ -98,16 +73,13 @@ static bool get_surface_box(struct root_geometry *geo, memcpy(surface_box, &box, sizeof(struct wlr_box)); } - struct wlr_box rotated_box; - wlr_box_rotated_bounds(&box, geo->rotation, &rotated_box); - struct wlr_box output_box = { .width = context.output->swayc->current.swayc_width, .height = context.output->swayc->current.swayc_height, }; struct wlr_box intersection; - return wlr_box_intersection(&output_box, &rotated_box, &intersection); + return wlr_box_intersection(&output_box, &box, &intersection); } static void surface_for_each_surface(struct wlr_surface *surface, @@ -117,7 +89,6 @@ static void surface_for_each_surface(struct wlr_surface *surface, geo->y = oy; geo->width = surface->current->width; geo->height = surface->current->height; - geo->rotation = 0; wlr_surface_for_each_surface(surface, iterator, user_data); } @@ -182,7 +153,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 = context.output->wlr_output; - float rotation = data->root_geo.rotation; float alpha = data->alpha; struct wlr_texture *texture = wlr_surface_get_texture(surface); @@ -201,7 +171,7 @@ static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, float matrix[9]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current->transform); - wlr_matrix_project_box(matrix, &box, transform, rotation, + wlr_matrix_project_box(matrix, &box, transform, 0, wlr_output->transform_matrix); render_texture(texture, &box, matrix, alpha); @@ -302,7 +272,6 @@ static void render_view_surfaces(struct sway_view *view, float alpha) { view->swayc->current.view_y - context.output->swayc->current.swayc_y; data.root_geo.width = view->swayc->current.view_width; data.root_geo.height = view->swayc->current.view_height; - data.root_geo.rotation = 0; // TODO view_for_each_surface(view, render_surface_iterator, &data); } From f6e86e65263932b5b915b3a37a27279709e0ace6 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 14:08:12 +1000 Subject: [PATCH 08/11] Render surfaces directly rather than using iterator function This means we can remove the render_data and root_geometry structs, as well as the functions get_surface_box, surface_for_each_surface and render_view_surfaces. --- sway/desktop/render.c | 143 ++++++++++++------------------------------ 1 file changed, 41 insertions(+), 102 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 6eab71294..5e91eadae 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -29,70 +29,13 @@ struct render_context { struct sway_output *output; - int output_lx; - int output_ly; + double output_lx; + double output_ly; pixman_region32_t *damage; float scale; }; struct render_context context; -/** - * Contains a surface's root geometry information. For instance, when rendering - * a popup, this will contain the parent view's position and size. - */ -struct root_geometry { - double x, y; - int width, height; -}; - -struct render_data { - struct root_geometry root_geo; - struct sway_output *output; - pixman_region32_t *damage; - struct sway_view *view; - float alpha; -}; - -static bool get_surface_box(struct root_geometry *geo, - 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; - - struct wlr_box box = { - .x = geo->x + sx, - .y = geo->y + sy, - .width = sw, - .height = sh, - }; - if (surface_box != NULL) { - memcpy(surface_box, &box, sizeof(struct wlr_box)); - } - - struct wlr_box output_box = { - .width = context.output->swayc->current.swayc_width, - .height = context.output->swayc->current.swayc_height, - }; - - struct wlr_box intersection; - return wlr_box_intersection(&output_box, &box, &intersection); -} - -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; - geo->y = oy; - geo->width = surface->current->width; - geo->height = surface->current->height; - - wlr_surface_for_each_surface(surface, iterator, user_data); -} - static void scale_box(struct wlr_box *box, float scale) { box->x *= scale; box->y *= scale; @@ -149,52 +92,66 @@ damage_finish: pixman_region32_fini(&damage); } -static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, - void *_data) { - struct render_data *data = _data; +static void render_surface(struct wlr_surface *surface, int ox, int oy, + float alpha) { struct wlr_output *wlr_output = context.output->wlr_output; - float alpha = data->alpha; struct wlr_texture *texture = wlr_surface_get_texture(surface); if (!texture) { return; } - struct wlr_box box; - bool intersects = get_surface_box(&data->root_geo, surface, sx, sy, &box); - if (!intersects) { + struct wlr_box surface_box = { + .x = ox, + .y = oy, + .width = surface->current->width, + .height = surface->current->height, + }; + struct wlr_box output_box = { + .width = context.output->swayc->current.swayc_width, + .height = context.output->swayc->current.swayc_height, + }; + struct wlr_box intersection; + if (!wlr_box_intersection(&output_box, &surface_box, &intersection)) { return; } - scale_box(&box, context.scale); + scale_box(&surface_box, context.scale); float matrix[9]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current->transform); - wlr_matrix_project_box(matrix, &box, transform, 0, + wlr_matrix_project_box(matrix, &surface_box, transform, 0, wlr_output->transform_matrix); - render_texture(texture, &box, matrix, alpha); + render_texture(texture, &surface_box, matrix, alpha); +} + +static void render_surfaces(struct wlr_surface *surface, double ox, double oy, + float alpha) { + render_surface(surface, ox, oy, alpha); + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { + struct wlr_surface_state *state = subsurface->surface->current; + int sx = state->subsurface_position.x; + int sy = state->subsurface_position.y; + + render_surfaces(subsurface->surface, ox + sx, oy + sy, alpha); + } } static void render_layer(struct wl_list *layer_surfaces) { - struct render_data data = { - .alpha = 1.0f, - }; 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, &data.root_geo, - render_surface_iterator, &data); + render_surfaces(wlr_layer_surface->surface, + layer_surface->geo.x, layer_surface->geo.y, 1.0f); } } static void render_unmanaged(struct wl_list *unmanaged) { - struct render_data data = { - .alpha = 1.0f, - }; struct sway_xwayland_unmanaged *unmanaged_surface; wl_list_for_each(unmanaged_surface, unmanaged, link) { struct wlr_xwayland_surface *xsurface = @@ -202,23 +159,18 @@ static void render_unmanaged(struct wl_list *unmanaged) { double ox = unmanaged_surface->lx - context.output_lx; double oy = unmanaged_surface->ly - context.output_ly; - surface_for_each_surface(xsurface->surface, ox, oy, &data.root_geo, - render_surface_iterator, &data); + render_surfaces(xsurface->surface, ox, oy, 1.0f); } } static void render_drag_icons(struct wl_list *drag_icons) { - struct render_data data = { - .alpha = 1.0f, - }; struct sway_drag_icon *drag_icon; wl_list_for_each(drag_icon, drag_icons, link) { double ox = drag_icon->x - context.output_lx; double oy = drag_icon->y - context.output_ly; if (drag_icon->wlr_drag_icon->mapped) { - surface_for_each_surface(drag_icon->wlr_drag_icon->surface, - ox, oy, &data.root_geo, render_surface_iterator, &data); + render_surfaces(drag_icon->wlr_drag_icon->surface, ox, oy, 1.0f); } } } @@ -261,21 +213,6 @@ static void premultiply_alpha(float color[4], float opacity) { color[2] *= color[3]; } -static void render_view_surfaces(struct sway_view *view, float alpha) { - struct render_data data = { - .view = view, - .alpha = alpha, - }; - data.root_geo.x = - view->swayc->current.view_x - context.output->swayc->current.swayc_x; - data.root_geo.y = - view->swayc->current.view_y - context.output->swayc->current.swayc_y; - data.root_geo.width = view->swayc->current.view_width; - data.root_geo.height = view->swayc->current.view_height; - - view_for_each_surface(view, render_surface_iterator, &data); -} - static void render_saved_view(struct sway_view *view, float alpha) { int width, height; struct wlr_texture *texture = @@ -319,7 +256,9 @@ static void render_view(struct sway_container *con, if (view->swayc->instructions->length) { render_saved_view(view, view->swayc->alpha); } else { - render_view_surfaces(view, view->swayc->alpha); + double ox = view->swayc->current.view_x - context.output_lx; + double oy = view->swayc->current.view_y - context.output_ly; + render_surfaces(view->surface, ox, oy, view->swayc->alpha); } struct wlr_box box; @@ -872,7 +811,7 @@ void render_output(struct sway_output *output, struct timespec *when, } // TODO: handle views smaller than the output - render_view_surfaces(fullscreen_view, 1.0f); + render_surfaces(fullscreen_view->surface, 0, 0, 1.0f); if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(&root_container.sway_root->xwayland_unmanaged); From f518036ddccc726eb7d0a734764f7833b06754a0 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 21:25:05 +1000 Subject: [PATCH 09/11] Reimplement popup rendering --- include/sway/tree/view.h | 2 ++ sway/desktop/render.c | 17 +++++++++++++++++ sway/desktop/xdg_shell.c | 9 +++++++++ sway/desktop/xdg_shell_v6.c | 10 ++++++++++ 4 files changed, 38 insertions(+) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 7dc8ac461..8786223e1 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -37,6 +37,8 @@ struct sway_view_impl { bool (*wants_floating)(struct sway_view *view); void (*for_each_surface)(struct sway_view *view, wlr_surface_iterator_func_t iterator, void *user_data); + void (*for_each_popup)(struct sway_view *view, + wlr_surface_iterator_func_t iterator, void *user_data); void (*close)(struct sway_view *view); void (*destroy)(struct sway_view *view); }; diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 5e91eadae..dc7610e41 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -247,6 +247,21 @@ static void render_saved_view(struct sway_view *view, float alpha) { render_texture(texture, &box, matrix, alpha); } +static void render_popup(struct wlr_surface *surface, int sx, int sy, + void *data) { + struct sway_view *view = data; + double ox = view->swayc->current.view_x - context.output_lx + sx; + double oy = view->swayc->current.view_y - context.output_ly + sy; + render_surface(surface, ox, oy, view->swayc->alpha); +} + +static void render_view_popups(struct sway_container *con, void *data) { + struct sway_view *view = con->sway_view; + if (view->impl->for_each_popup) { + view->impl->for_each_popup(view, render_popup, view); + } +} + /** * Render a view's surface and left/bottom/right borders. */ @@ -812,6 +827,7 @@ void render_output(struct sway_output *output, struct timespec *when, // TODO: handle views smaller than the output render_surfaces(fullscreen_view->surface, 0, 0, 1.0f); + render_view_popups(fullscreen_view->swayc, NULL); if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(&root_container.sway_root->xwayland_unmanaged); @@ -833,6 +849,7 @@ void render_output(struct sway_output *output, struct timespec *when, struct sway_container *focus = seat_get_focus(seat); render_container(workspace, focus == workspace); render_floating(); + container_descendants(workspace, C_VIEW, render_view_popups, NULL); render_unmanaged(&root_container.sway_root->xwayland_unmanaged); render_layer(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 82db40760..8683c56b1 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -147,6 +147,14 @@ static void for_each_surface(struct sway_view *view, user_data); } +static void for_each_popup(struct sway_view *view, + wlr_surface_iterator_func_t iterator, void *user_data) { + if (xdg_shell_view_from_view(view) == NULL) { + return; + } + wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data); +} + static void _close(struct sway_view *view) { if (xdg_shell_view_from_view(view) == NULL) { return; @@ -174,6 +182,7 @@ static const struct sway_view_impl view_impl = { .set_fullscreen = set_fullscreen, .wants_floating = wants_floating, .for_each_surface = for_each_surface, + .for_each_popup = for_each_popup, .close = _close, .destroy = destroy, }; diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 0d3c16443..f4a743053 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -143,6 +143,15 @@ static void for_each_surface(struct sway_view *view, user_data); } +static void for_each_popup(struct sway_view *view, + wlr_surface_iterator_func_t iterator, void *user_data) { + if (xdg_shell_v6_view_from_view(view) == NULL) { + return; + } + wlr_xdg_surface_v6_for_each_popup(view->wlr_xdg_surface_v6, iterator, + user_data); +} + static void _close(struct sway_view *view) { if (xdg_shell_v6_view_from_view(view) == NULL) { return; @@ -170,6 +179,7 @@ static const struct sway_view_impl view_impl = { .set_fullscreen = set_fullscreen, .wants_floating = wants_floating, .for_each_surface = for_each_surface, + .for_each_popup = for_each_popup, .close = _close, .destroy = destroy, }; From b9050fca6919f756beb2701a922cf99348efa6c9 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 21:47:18 +1000 Subject: [PATCH 10/11] Render subsurfaces of popups --- sway/desktop/render.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index dc7610e41..1765cce6f 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -252,7 +252,7 @@ static void render_popup(struct wlr_surface *surface, int sx, int sy, struct sway_view *view = data; double ox = view->swayc->current.view_x - context.output_lx + sx; double oy = view->swayc->current.view_y - context.output_ly + sy; - render_surface(surface, ox, oy, view->swayc->alpha); + render_surfaces(surface, ox, oy, view->swayc->alpha); } static void render_view_popups(struct sway_container *con, void *data) { From f259d24138db7c4f72fb79344f02aca6f5d58d9f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 2 Jul 2018 20:49:21 +1000 Subject: [PATCH 11/11] Implement rotation in renderer for floating containers --- include/sway/tree/container.h | 1 + sway/desktop/render.c | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 728daa847..918bf3070 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -133,6 +133,7 @@ struct sway_container { struct sway_container *parent; float alpha; + float rotation; // in radians struct wlr_texture *title_focused; struct wlr_texture *title_focused_inactive; diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 1765cce6f..a7332d8ec 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -32,6 +32,7 @@ struct render_context { double output_lx; double output_ly; pixman_region32_t *damage; + float matrix[9]; float scale; }; struct render_context context; @@ -94,8 +95,6 @@ damage_finish: static void render_surface(struct wlr_surface *surface, int ox, int oy, float alpha) { - struct wlr_output *wlr_output = context.output->wlr_output; - struct wlr_texture *texture = wlr_surface_get_texture(surface); if (!texture) { return; @@ -122,7 +121,7 @@ static void render_surface(struct wlr_surface *surface, int ox, int oy, enum wl_output_transform transform = wlr_output_transform_invert(surface->current->transform); wlr_matrix_project_box(matrix, &surface_box, transform, 0, - wlr_output->transform_matrix); + context.matrix); render_texture(texture, &surface_box, matrix, alpha); } @@ -708,6 +707,19 @@ static void render_container(struct sway_container *con, bool parent_focused) { } static void render_floating_container(struct sway_container *con) { + float saved_matrix[9]; + if (con->rotation) { + memcpy(saved_matrix, context.matrix, sizeof(saved_matrix)); + double cx = con->current.swayc_x - context.output_lx + + con->current.swayc_width / 2; + double cy = con->current.swayc_y - context.output_ly + + con->current.swayc_height / 2; + + wlr_matrix_translate(context.matrix, cx, cy); + wlr_matrix_rotate(context.matrix, con->rotation); + wlr_matrix_translate(context.matrix, -cx, -cy); + } + if (con->type == C_VIEW) { struct sway_view *view = con->sway_view; struct sway_seat *seat = input_manager_current_seat(input_manager); @@ -737,6 +749,10 @@ static void render_floating_container(struct sway_container *con) { } else { render_container(con, false); } + + if (con->rotation) { + memcpy(context.matrix, saved_matrix, sizeof(saved_matrix)); + } } static void render_floating() { @@ -784,6 +800,7 @@ void render_output(struct sway_output *output, struct timespec *when, context.output_ly = output->swayc->current.swayc_y; context.damage = damage; context.scale = output->wlr_output->scale; + memcpy(&context.matrix, wlr_output->transform_matrix, sizeof(context.matrix)); struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);