From d5cc474aef6bf5a23694053ab9c8770ea3f21e6f Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 27 Apr 2023 11:19:58 +0200 Subject: [PATCH 01/34] render: pass rendering state together in a struct This lets us easily add rendering state that we need in the future --- include/sway/input/seat.h | 7 +- include/sway/output.h | 11 +- sway/desktop/output.c | 14 +- sway/desktop/render.c | 269 +++++++++++++++----------------- sway/input/seat.c | 5 +- sway/input/seatop_move_tiling.c | 9 +- 6 files changed, 156 insertions(+), 159 deletions(-) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 7b2d3d07..6d29cf3b 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -12,6 +12,7 @@ #include "sway/input/text_input.h" struct sway_seat; +struct render_context; struct sway_seatop_impl { void (*button)(struct sway_seat *seat, uint32_t time_msec, @@ -49,8 +50,7 @@ struct sway_seatop_impl { uint32_t time_msec, enum wlr_tablet_tool_tip_state state); void (*end)(struct sway_seat *seat); void (*unref)(struct sway_seat *seat, struct sway_container *con); - void (*render)(struct sway_seat *seat, struct sway_output *output, - const pixman_region32_t *damage); + void (*render)(struct sway_seat *seat, struct render_context *ctx); bool allow_set_cursor; }; @@ -356,8 +356,7 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con); * Instructs a seatop to render anything that it needs to render * (eg. dropzone for move-tiling) */ -void seatop_render(struct sway_seat *seat, struct sway_output *output, - const pixman_region32_t *damage); +void seatop_render(struct sway_seat *seat, struct render_context *ctx); bool seatop_allows_set_cursor(struct sway_seat *seat); diff --git a/include/sway/output.h b/include/sway/output.h index 04202976..b397c8e2 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -65,6 +65,12 @@ struct sway_output_non_desktop { struct wl_listener destroy; }; +struct render_context { + struct sway_output *output; + struct wlr_renderer *renderer; + const pixman_region32_t *output_damage; +}; + struct sway_output *output_create(struct wlr_output *wlr_output); void output_destroy(struct sway_output *output); @@ -115,7 +121,7 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output); struct sway_workspace *output_get_active_workspace(struct sway_output *output); -void output_render(struct sway_output *output, pixman_region32_t *damage); +void output_render(struct render_context *ctx); void output_surface_for_each_surface(struct sway_output *output, struct wlr_surface *surface, double ox, double oy, @@ -168,8 +174,7 @@ void output_get_box(struct sway_output *output, struct wlr_box *box); enum sway_container_layout output_get_default_layout( struct sway_output *output); -void render_rect(struct sway_output *output, - const pixman_region32_t *output_damage, const struct wlr_box *_box, +void render_rect(struct render_context *ctx, const struct wlr_box *_box, float color[static 4]); void premultiply_alpha(float color[4], float opacity); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 2255b551..02e08bd2 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -613,10 +613,22 @@ static int output_repaint_timer_handler(void *data) { pixman_region32_init(&damage); wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage); + if (debug.damage == DAMAGE_RERENDER) { + int width, height; + wlr_output_transformed_resolution(wlr_output, &width, &height); + pixman_region32_union_rect(&damage, &damage, 0, 0, width, height); + } + + struct render_context ctx = { + .output_damage = &damage, + .renderer = wlr_output->renderer, + .output = output, + }; + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - output_render(output, &damage); + output_render(&ctx); pixman_region32_fini(&damage); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index a4d633e0..f011e0ff 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -32,6 +32,7 @@ #endif struct render_data { + struct render_context *ctx; const pixman_region32_t *damage; float alpha; struct wlr_box *clip_box; @@ -101,18 +102,17 @@ static void set_scale_filter(struct wlr_output *wlr_output, #endif } -static void render_texture(struct wlr_output *wlr_output, - const pixman_region32_t *output_damage, struct wlr_texture *texture, +static void render_texture(struct render_context *ctx, struct wlr_texture *texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9], float alpha) { - struct wlr_renderer *renderer = wlr_output->renderer; - struct sway_output *output = wlr_output->data; + struct wlr_renderer *renderer = ctx->renderer; + struct sway_output *output = ctx->output; pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, dst_box->width, dst_box->height); - pixman_region32_intersect(&damage, &damage, output_damage); + pixman_region32_intersect(&damage, &damage, ctx->output_damage); bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { goto damage_finish; @@ -121,8 +121,8 @@ static void render_texture(struct wlr_output *wlr_output, int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - set_scale_filter(wlr_output, texture, output->scale_filter); + scissor_output(output->wlr_output, &rects[i]); + set_scale_filter(output->wlr_output, texture, output->scale_filter); if (src_box != NULL) { wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, alpha); } else { @@ -139,7 +139,6 @@ static void render_surface_iterator(struct sway_output *output, struct wlr_box *_box, void *_data) { struct render_data *data = _data; struct wlr_output *wlr_output = output->wlr_output; - const pixman_region32_t *output_damage = data->damage; float alpha = data->alpha; struct wlr_texture *texture = wlr_surface_get_texture(surface); @@ -167,73 +166,68 @@ static void render_surface_iterator(struct sway_output *output, } scale_box(&dst_box, wlr_output->scale); - render_texture(wlr_output, output_damage, texture, + render_texture(data->ctx, texture, &src_box, &dst_box, matrix, alpha); wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_output); } -static void render_layer_toplevel(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *layer_surfaces) { +static void render_layer_toplevel(struct render_context *ctx, struct wl_list *layer_surfaces) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_layer_for_each_toplevel_surface(output, layer_surfaces, + output_layer_for_each_toplevel_surface(ctx->output, layer_surfaces, render_surface_iterator, &data); } -static void render_layer_popups(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *layer_surfaces) { +static void render_layer_popups(struct render_context *ctx, struct wl_list *layer_surfaces) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_layer_for_each_popup_surface(output, layer_surfaces, + output_layer_for_each_popup_surface(ctx->output, layer_surfaces, render_surface_iterator, &data); } #if HAVE_XWAYLAND -static void render_unmanaged(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *unmanaged) { +static void render_unmanaged(struct render_context *ctx, struct wl_list *unmanaged) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_unmanaged_for_each_surface(output, unmanaged, + output_unmanaged_for_each_surface(ctx->output, unmanaged, render_surface_iterator, &data); } #endif -static void render_drag_icons(struct sway_output *output, - const pixman_region32_t *damage, struct wl_list *drag_icons) { +static void render_drag_icons(struct render_context *ctx, struct wl_list *drag_icons) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; - output_drag_icons_for_each_surface(output, drag_icons, + output_drag_icons_for_each_surface(ctx->output, drag_icons, render_surface_iterator, &data); } // _box.x and .y are expected to be layout-local // _box.width and .height are expected to be output-buffer-local -void render_rect(struct sway_output *output, - const pixman_region32_t *output_damage, const struct wlr_box *_box, +void render_rect(struct render_context *ctx, const struct wlr_box *_box, float color[static 4]) { - struct wlr_output *wlr_output = output->wlr_output; - struct wlr_renderer *renderer = wlr_output->renderer; + struct wlr_output *wlr_output = ctx->output->wlr_output; + struct wlr_renderer *renderer = ctx->renderer; struct wlr_box box; memcpy(&box, _box, sizeof(struct wlr_box)); - box.x -= output->lx * wlr_output->scale; - box.y -= output->ly * wlr_output->scale; + box.x -= ctx->output->lx * wlr_output->scale; + box.y -= ctx->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); + pixman_region32_intersect(&damage, &damage, ctx->output_damage); bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { goto damage_finish; @@ -258,11 +252,11 @@ void premultiply_alpha(float color[4], float opacity) { color[2] *= color[3]; } -static void render_view_toplevels(struct sway_view *view, - struct sway_output *output, const pixman_region32_t *damage, float alpha) { +static void render_view_toplevels(struct render_context *ctx, + struct sway_view *view, float alpha) { struct render_data data = { - .damage = damage, .alpha = alpha, + .ctx = ctx, }; struct wlr_box clip_box; if (!container_is_current_floating(view->container)) { @@ -274,25 +268,26 @@ static void render_view_toplevels(struct sway_view *view, } // Render all toplevels without descending into popups double ox = view->container->surface_x - - output->lx - view->geometry.x; + ctx->output->lx - view->geometry.x; double oy = view->container->surface_y - - output->ly - view->geometry.y; - output_surface_for_each_surface(output, view->surface, ox, oy, + ctx->output->ly - view->geometry.y; + output_surface_for_each_surface(ctx->output, view->surface, ox, oy, render_surface_iterator, &data); } -static void render_view_popups(struct sway_view *view, - struct sway_output *output, const pixman_region32_t *damage, float alpha) { +static void render_view_popups(struct render_context *ctx, struct sway_view *view, + float alpha) { struct render_data data = { - .damage = damage, .alpha = alpha, + .ctx = ctx, }; - output_view_for_each_popup_surface(output, view, + output_view_for_each_popup_surface(ctx->output, view, render_surface_iterator, &data); } -static void render_saved_view(struct sway_view *view, - struct sway_output *output, const pixman_region32_t *damage, float alpha) { +static void render_saved_view(struct render_context *ctx, struct sway_view *view, + float alpha) { + struct sway_output *output = ctx->output; struct wlr_output *wlr_output = output->wlr_output; if (wl_list_empty(&view->saved_buffers)) { @@ -343,7 +338,7 @@ static void render_saved_view(struct sway_view *view, } scale_box(&dst_box, wlr_output->scale); - render_texture(wlr_output, damage, saved_buf->buffer->texture, + render_texture(ctx, saved_buf->buffer->texture, &saved_buf->source_box, &dst_box, matrix, alpha); } @@ -355,13 +350,13 @@ static void render_saved_view(struct sway_view *view, /** * Render a view's surface and left/bottom/right borders. */ -static void render_view(struct sway_output *output, const pixman_region32_t *damage, +static void render_view(struct render_context *ctx, struct sway_container *con, struct border_colors *colors) { struct sway_view *view = con->view; if (!wl_list_empty(&view->saved_buffers)) { - render_saved_view(view, output, damage, view->container->alpha); + render_saved_view(ctx, view, view->container->alpha); } else if (view->surface) { - render_view_toplevels(view, output, damage, view->container->alpha); + render_view_toplevels(ctx, view, view->container->alpha); } if (con->current.border == B_NONE || con->current.border == B_CSD) { @@ -369,7 +364,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam } struct wlr_box box; - float output_scale = output->wlr_output->scale; + float output_scale = ctx->output->wlr_output->scale; float color[4]; struct sway_container_state *state = &con->current; @@ -381,7 +376,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam box.width = state->border_thickness; box.height = state->content_height; scale_box(&box, output_scale); - render_rect(output, damage, &box, color); + render_rect(ctx, &box, color); } list_t *siblings = container_get_current_siblings(con); @@ -400,7 +395,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam box.width = state->border_thickness; box.height = state->content_height; scale_box(&box, output_scale); - render_rect(output, damage, &box, color); + render_rect(ctx, &box, color); } if (state->border_bottom) { @@ -415,7 +410,7 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam box.width = state->width; box.height = state->border_thickness; scale_box(&box, output_scale); - render_rect(output, damage, &box, color); + render_rect(ctx, &box, color); } } @@ -428,13 +423,13 @@ static void render_view(struct sway_output *output, const pixman_region32_t *dam * The height is: 1px border, 3px padding, font height, 3px padding, 1px border * The left side is: 1px border, 2px padding, title */ -static void render_titlebar(struct sway_output *output, - const pixman_region32_t *output_damage, struct sway_container *con, +static void render_titlebar(struct render_context *ctx, 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_output *output = ctx->output; float output_scale = output->wlr_output->scale; double output_x = output->lx; double output_y = output->ly; @@ -451,7 +446,7 @@ static void render_titlebar(struct sway_output *output, box.width = width; box.height = titlebar_border_thickness; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Single pixel bar below title box.x = x; @@ -459,7 +454,7 @@ static void render_titlebar(struct sway_output *output, box.width = width; box.height = titlebar_border_thickness; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Single pixel left edge box.x = x; @@ -467,7 +462,7 @@ 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, output_damage, &box, color); + render_rect(ctx, &box, color); // Single pixel right edge box.x = x + width - titlebar_border_thickness; @@ -475,7 +470,7 @@ 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, output_damage, &box, color); + render_rect(ctx, &box, color); int inner_x = x - output_x + titlebar_h_padding; int bg_y = y + titlebar_border_thickness; @@ -524,7 +519,7 @@ static void render_titlebar(struct sway_output *output, if (ob_inner_width < texture_box.width) { texture_box.width = ob_inner_width; } - render_texture(output->wlr_output, output_damage, marks_texture, + render_texture(ctx, marks_texture, NULL, &texture_box, matrix, con->alpha); // Padding above @@ -534,12 +529,12 @@ static void render_titlebar(struct sway_output *output, box.y = roundf((y + titlebar_border_thickness) * output_scale); box.width = texture_box.width; box.height = ob_padding_above; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Padding below box.y += ob_padding_above + texture_box.height; box.height = ob_padding_below; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } // Title text @@ -600,7 +595,7 @@ static void render_titlebar(struct sway_output *output, texture_box.width = ob_inner_width - ob_marks_width; } - render_texture(output->wlr_output, output_damage, title_texture, + render_texture(ctx, title_texture, NULL, &texture_box, matrix, con->alpha); // Padding above @@ -610,12 +605,12 @@ static void render_titlebar(struct sway_output *output, box.y = roundf((y + titlebar_border_thickness) * output_scale); box.width = texture_box.width; box.height = ob_padding_above; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Padding below box.y += ob_padding_above + texture_box.height; box.height = ob_padding_below; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } // Determine the left + right extends of the textures (output-buffer local) @@ -649,7 +644,7 @@ static void render_titlebar(struct sway_output *output, box.x = ob_left_x + ob_left_width + round(output_x * output_scale); box.y = roundf(bg_y * output_scale); box.height = ob_bg_height; - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } // Padding on left side @@ -663,7 +658,7 @@ static void render_titlebar(struct sway_output *output, if (box.x + box.width < left_x) { box.width += left_x - box.x - box.width; } - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); // Padding on right side box.x = x + width - titlebar_h_padding; @@ -677,14 +672,13 @@ static void render_titlebar(struct sway_output *output, box.width += box.x - right_rx; box.x = right_rx; } - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } /** * Render the top border line for a view using "border pixel". */ -static void render_top_border(struct sway_output *output, - const pixman_region32_t *output_damage, struct sway_container *con, +static void render_top_border(struct render_context *ctx, struct sway_container *con, struct border_colors *colors) { struct sway_container_state *state = &con->current; if (!state->border_top) { @@ -692,7 +686,7 @@ static void render_top_border(struct sway_output *output, } struct wlr_box box; float color[4]; - float output_scale = output->wlr_output->scale; + float output_scale = ctx->output->wlr_output->scale; // Child border - top edge memcpy(&color, colors->child_border, sizeof(float) * 4); @@ -702,7 +696,7 @@ static void render_top_border(struct sway_output *output, box.width = state->width; box.height = state->border_thickness; scale_box(&box, output_scale); - render_rect(output, output_damage, &box, color); + render_rect(ctx, &box, color); } struct parent_data { @@ -713,8 +707,8 @@ struct parent_data { struct sway_container *active_child; }; -static void render_container(struct sway_output *output, - const pixman_region32_t *damage, struct sway_container *con, bool parent_focused); +static void render_container(struct render_context *ctx, + struct sway_container *con, bool parent_focused); /** * Render a container's children using a L_HORIZ or L_VERT layout. @@ -722,8 +716,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_containers_linear(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers_linear(struct render_context *ctx, struct parent_data *parent) { for (int i = 0; i < parent->children->length; ++i) { struct sway_container *child = parent->children->items[i]; @@ -753,15 +746,15 @@ static void render_containers_linear(struct sway_output *output, } if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, floor(state->x), + render_titlebar(ctx, child, floor(state->x), floor(state->y), state->width, colors, title_texture, marks_texture); } else if (state->border == B_PIXEL) { - render_top_border(output, damage, child, colors); + render_top_border(ctx, child, colors); } - render_view(output, damage, child, colors); + render_view(ctx, child, colors); } else { - render_container(output, damage, child, + render_container(ctx, child, parent->focused || child->current.focused); } } @@ -778,8 +771,7 @@ static bool container_has_focused_child(struct sway_container *con) { /** * Render a container's children using the L_TABBED layout. */ -static void render_containers_tabbed(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers_tabbed(struct render_context *ctx, struct parent_data *parent) { if (!parent->children->length) { return; } @@ -827,7 +819,7 @@ static void render_containers_tabbed(struct sway_output *output, tab_width = parent->box.width - tab_width * i; } - render_titlebar(output, damage, child, x, parent->box.y, tab_width, + render_titlebar(ctx, child, x, parent->box.y, tab_width, colors, title_texture, marks_texture); if (child == current) { @@ -837,9 +829,9 @@ static void render_containers_tabbed(struct sway_output *output, // Render surface and left/right/bottom borders if (current->view) { - render_view(output, damage, current, current_colors); + render_view(ctx, current, current_colors); } else { - render_container(output, damage, current, + render_container(ctx, current, parent->focused || current->current.focused); } } @@ -847,8 +839,7 @@ static void render_containers_tabbed(struct sway_output *output, /** * Render a container's children using the L_STACKED layout. */ -static void render_containers_stacked(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers_stacked(struct render_context *ctx, struct parent_data *parent) { if (!parent->children->length) { return; } @@ -890,7 +881,7 @@ static void render_containers_stacked(struct sway_output *output, } int y = parent->box.y + titlebar_height * i; - render_titlebar(output, damage, child, parent->box.x, y, + render_titlebar(ctx, child, parent->box.x, y, parent->box.width, colors, title_texture, marks_texture); if (child == current) { @@ -900,19 +891,18 @@ static void render_containers_stacked(struct sway_output *output, // Render surface and left/right/bottom borders if (current->view) { - render_view(output, damage, current, current_colors); + render_view(ctx, current, current_colors); } else { - render_container(output, damage, current, + render_container(ctx, current, parent->focused || current->current.focused); } } -static void render_containers(struct sway_output *output, - const pixman_region32_t *damage, struct parent_data *parent) { +static void render_containers(struct render_context *ctx, struct parent_data *parent) { if (config->hide_lone_tab && parent->children->length == 1) { struct sway_container *child = parent->children->items[0]; if (child->view) { - render_containers_linear(output,damage, parent); + render_containers_linear(ctx, parent); return; } } @@ -921,19 +911,19 @@ static void render_containers(struct sway_output *output, case L_NONE: case L_HORIZ: case L_VERT: - render_containers_linear(output, damage, parent); + render_containers_linear(ctx, parent); break; case L_STACKED: - render_containers_stacked(output, damage, parent); + render_containers_stacked(ctx, parent); break; case L_TABBED: - render_containers_tabbed(output, damage, parent); + render_containers_tabbed(ctx, parent); break; } } -static void render_container(struct sway_output *output, - const pixman_region32_t *damage, struct sway_container *con, bool focused) { +static void render_container(struct render_context *ctx, + struct sway_container *con, bool focused) { struct parent_data data = { .layout = con->current.layout, .box = { @@ -946,11 +936,11 @@ static void render_container(struct sway_output *output, .focused = focused, .active_child = con->current.focused_inactive_child, }; - render_containers(output, damage, &data); + render_containers(ctx, &data); } -static void render_workspace(struct sway_output *output, - const pixman_region32_t *damage, struct sway_workspace *ws, bool focused) { +static void render_workspace(struct render_context *ctx, + struct sway_workspace *ws, bool focused) { struct parent_data data = { .layout = ws->current.layout, .box = { @@ -963,11 +953,11 @@ static void render_workspace(struct sway_output *output, .focused = focused, .active_child = ws->current.focused_inactive_child, }; - render_containers(output, damage, &data); + render_containers(ctx, &data); } -static void render_floating_container(struct sway_output *soutput, - const pixman_region32_t *damage, struct sway_container *con) { +static void render_floating_container(struct render_context *ctx, + struct sway_container *con) { if (con->view) { struct sway_view *view = con->view; struct border_colors *colors; @@ -989,20 +979,19 @@ static void render_floating_container(struct sway_output *soutput, } if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, floor(con->current.x), + render_titlebar(ctx, con, floor(con->current.x), floor(con->current.y), con->current.width, colors, title_texture, marks_texture); } else if (con->current.border == B_PIXEL) { - render_top_border(soutput, damage, con, colors); + render_top_border(ctx, con, colors); } - render_view(soutput, damage, con, colors); + render_view(ctx, con, colors); } else { - render_container(soutput, damage, con, con->current.focused); + render_container(ctx, con, con->current.focused); } } -static void render_floating(struct sway_output *soutput, - const pixman_region32_t *damage) { +static void render_floating(struct render_context *ctx) { for (int i = 0; i < root->outputs->length; ++i) { struct sway_output *output = root->outputs->items[i]; for (int j = 0; j < output->current.workspaces->length; ++j) { @@ -1015,23 +1004,24 @@ static void render_floating(struct sway_output *soutput, if (floater->current.fullscreen_mode != FULLSCREEN_NONE) { continue; } - render_floating_container(soutput, damage, floater); + render_floating_container(ctx, floater); } } } } -static void render_seatops(struct sway_output *output, - const pixman_region32_t *damage) { +static void render_seatops(struct render_context *ctx) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { - seatop_render(seat, output, damage); + seatop_render(seat, ctx); } } -void output_render(struct sway_output *output, pixman_region32_t *damage) { - struct wlr_output *wlr_output = output->wlr_output; - struct wlr_renderer *renderer = output->server->renderer; +void output_render(struct render_context *ctx) { + struct wlr_output *wlr_output = ctx->output->wlr_output; + struct wlr_renderer *renderer = ctx->renderer; + struct sway_output *output = ctx->output; + const pixman_region32_t *damage = ctx->output_damage; struct sway_workspace *workspace = output->current.active_workspace; if (workspace == NULL) { @@ -1047,12 +1037,6 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { return; } - if (debug.damage == DAMAGE_RERENDER) { - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - pixman_region32_union_rect(damage, damage, 0, 0, width, height); - } - if (!pixman_region32_not_empty(damage)) { // Output isn't damaged but needs buffer swap goto renderer_end; @@ -1077,8 +1061,8 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { if (server.session_lock.lock != NULL) { struct render_data data = { - .damage = damage, .alpha = 1.0f, + .ctx = ctx, }; struct wlr_session_lock_surface_v1 *lock_surface; @@ -1113,13 +1097,12 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { if (fullscreen_con->view) { if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) { - render_saved_view(fullscreen_con->view, output, damage, 1.0f); + render_saved_view(ctx, fullscreen_con->view, 1.0f); } else if (fullscreen_con->view->surface) { - render_view_toplevels(fullscreen_con->view, - output, damage, 1.0f); + render_view_toplevels(ctx, fullscreen_con->view, 1.0f); } } else { - render_container(output, damage, fullscreen_con, + render_container(ctx, fullscreen_con, fullscreen_con->current.focused); } @@ -1127,11 +1110,11 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { struct sway_container *floater = workspace->current.floating->items[i]; if (container_is_transient_for(floater, fullscreen_con)) { - render_floating_container(output, damage, floater); + render_floating_container(ctx, floater); } } #if HAVE_XWAYLAND - render_unmanaged(output, damage, &root->xwayland_unmanaged); + render_unmanaged(ctx, &root->xwayland_unmanaged); #endif } else { float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; @@ -1143,41 +1126,41 @@ void output_render(struct sway_output *output, pixman_region32_t *damage) { wlr_renderer_clear(renderer, clear_color); } - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - render_workspace(output, damage, workspace, workspace->current.focused); - render_floating(output, damage); + render_workspace(ctx, workspace, workspace->current.focused); + render_floating(ctx); #if HAVE_XWAYLAND - render_unmanaged(output, damage, &root->xwayland_unmanaged); + render_unmanaged(ctx, &root->xwayland_unmanaged); #endif - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); } - render_seatops(output, damage); + render_seatops(ctx); struct sway_seat *seat = input_manager_current_seat(); struct sway_container *focus = seat_get_focused_container(seat); if (focus && focus->view) { - render_view_popups(focus->view, output, damage, focus->alpha); + render_view_popups(ctx, focus->view, focus->alpha); } render_overlay: - render_layer_toplevel(output, damage, + render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_layer_popups(output, damage, + render_layer_popups(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - render_drag_icons(output, damage, &root->drag_icons); + render_drag_icons(ctx, &root->drag_icons); renderer_end: wlr_renderer_scissor(renderer, NULL); diff --git a/sway/input/seat.c b/sway/input/seat.c index 14931ce0..6b95e46a 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1726,10 +1726,9 @@ void seatop_end(struct sway_seat *seat) { seat->seatop_impl = NULL; } -void seatop_render(struct sway_seat *seat, struct sway_output *output, - const pixman_region32_t *damage) { +void seatop_render(struct sway_seat *seat, struct render_context *ctx) { if (seat->seatop_impl->render) { - seat->seatop_impl->render(seat, output, damage); + seat->seatop_impl->render(seat, ctx); } } diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 5498e909..26704d0d 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -31,21 +31,20 @@ struct seatop_move_tiling_event { bool insert_after_target; }; -static void handle_render(struct sway_seat *seat, - struct sway_output *output, const pixman_region32_t *damage) { +static void handle_render(struct sway_seat *seat, struct render_context *ctx) { struct seatop_move_tiling_event *e = seat->seatop_data; if (!e->threshold_reached) { return; } - if (e->target_node && node_get_output(e->target_node) == output) { + if (e->target_node && node_get_output(e->target_node) == ctx->output) { float color[4]; memcpy(&color, config->border_colors.focused.indicator, sizeof(float) * 4); premultiply_alpha(color, 0.5); struct wlr_box box; memcpy(&box, &e->drop_box, sizeof(struct wlr_box)); - scale_box(&box, output->wlr_output->scale); - render_rect(output, damage, &box, color); + scale_box(&box, ctx->output->wlr_output->scale); + render_rect(ctx, &box, color); } } From 07cdf6ccd06e7bf1a7b828ea2a80d9db6e25263b Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 27 Apr 2023 11:28:57 +0200 Subject: [PATCH 02/34] render: Don't pass matrix into render_texture --- sway/desktop/render.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index f011e0ff..a3ae5efc 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -104,10 +104,18 @@ static void set_scale_filter(struct wlr_output *wlr_output, static void render_texture(struct render_context *ctx, struct wlr_texture *texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, - const float matrix[static 9], float alpha) { + enum wl_output_transform transform, float alpha) { struct wlr_renderer *renderer = ctx->renderer; struct sway_output *output = ctx->output; + struct wlr_box proj_box = *dst_box; + scale_box(&proj_box, output->wlr_output->scale); + + float matrix[9]; + enum wl_output_transform inv_transform = wlr_output_transform_invert(transform); + wlr_matrix_project_box(matrix, &proj_box, inv_transform, 0, + output->wlr_output->transform_matrix); + pixman_region32_t damage; pixman_region32_init(&damage); pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, @@ -152,12 +160,6 @@ static void render_surface_iterator(struct sway_output *output, struct wlr_box proj_box = *_box; scale_box(&proj_box, wlr_output->scale); - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &proj_box, transform, 0.0, - wlr_output->transform_matrix); - struct wlr_box dst_box = *_box; struct wlr_box *clip_box = data->clip_box; if (clip_box != NULL) { @@ -167,7 +169,7 @@ static void render_surface_iterator(struct sway_output *output, scale_box(&dst_box, wlr_output->scale); render_texture(data->ctx, texture, - &src_box, &dst_box, matrix, alpha); + &src_box, &dst_box, surface->current.transform, alpha); wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_output); @@ -323,11 +325,6 @@ static void render_saved_view(struct render_context *ctx, struct sway_view *view struct wlr_box dst_box = proj_box; scale_box(&proj_box, wlr_output->scale); - float matrix[9]; - enum wl_output_transform transform = wlr_output_transform_invert(saved_buf->transform); - wlr_matrix_project_box(matrix, &proj_box, transform, 0, - wlr_output->transform_matrix); - if (!floating) { dst_box.width = fmin(dst_box.width, view->container->current.content_width - @@ -339,7 +336,7 @@ static void render_saved_view(struct render_context *ctx, struct sway_view *view scale_box(&dst_box, wlr_output->scale); render_texture(ctx, saved_buf->buffer->texture, - &saved_buf->source_box, &dst_box, matrix, alpha); + &saved_buf->source_box, &dst_box, saved_buf->transform, alpha); } // FIXME: we should set the surface that this saved buffer originates from @@ -511,16 +508,11 @@ static void render_titlebar(struct render_context *ctx, struct sway_container *c texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - if (ob_inner_width < texture_box.width) { texture_box.width = ob_inner_width; } render_texture(ctx, marks_texture, - NULL, &texture_box, matrix, con->alpha); + NULL, &texture_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); @@ -586,17 +578,12 @@ static void render_titlebar(struct render_context *ctx, struct sway_container *c texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; - float matrix[9]; - wlr_matrix_project_box(matrix, &texture_box, - WL_OUTPUT_TRANSFORM_NORMAL, - 0.0, output->wlr_output->transform_matrix); - if (ob_inner_width - ob_marks_width < texture_box.width) { texture_box.width = ob_inner_width - ob_marks_width; } render_texture(ctx, title_texture, - NULL, &texture_box, matrix, con->alpha); + NULL, &texture_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); From 029b99b4829148ef3e899f21bba4fe2a1d4d0db9 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 2 May 2023 11:43:44 -0400 Subject: [PATCH 03/34] render: Use wlr_render_pass --- include/sway/output.h | 2 + sway/desktop/output.c | 26 ++++++- sway/desktop/render.c | 171 ++++++++++++++++++++---------------------- 3 files changed, 109 insertions(+), 90 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index b397c8e2..f6dc6af2 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -69,6 +69,8 @@ struct render_context { struct sway_output *output; struct wlr_renderer *renderer; const pixman_region32_t *output_damage; + + struct wlr_render_pass *pass; }; struct sway_output *output_create(struct wlr_output *wlr_output); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 02e08bd2..01bc87bb 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -604,9 +605,21 @@ static int output_repaint_timer_handler(void *data) { } } + if (!wlr_output_configure_primary_swapchain(wlr_output, NULL, &wlr_output->swapchain)) { + return false; + } + int buffer_age; - if (!wlr_output_attach_render(output->wlr_output, &buffer_age)) { - return 0; + struct wlr_buffer *buffer = wlr_swapchain_acquire(wlr_output->swapchain, &buffer_age); + if (buffer == NULL) { + return false; + } + + struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass( + wlr_output->renderer, buffer); + if (render_pass == NULL) { + wlr_buffer_unlock(buffer); + return false; } pixman_region32_t damage; @@ -623,6 +636,7 @@ static int output_repaint_timer_handler(void *data) { .output_damage = &damage, .renderer = wlr_output->renderer, .output = output, + .pass = render_pass, }; struct timespec now; @@ -632,6 +646,14 @@ static int output_repaint_timer_handler(void *data) { pixman_region32_fini(&damage); + if (!wlr_render_pass_submit(render_pass)) { + wlr_buffer_unlock(buffer); + return false; + } + + wlr_output_attach_buffer(wlr_output, buffer); + wlr_buffer_unlock(buffer); + if (!wlr_output_commit(wlr_output)) { return 0; } diff --git a/sway/desktop/render.c b/sway/desktop/render.c index a3ae5efc..37e84647 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -38,6 +38,23 @@ struct render_data { struct wlr_box *clip_box; }; +static void transform_output_damage(pixman_region32_t *damage, struct wlr_output *output) { + int ow, oh; + wlr_output_transformed_resolution(output, &ow, &oh); + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); + wlr_region_transform(damage, damage, transform, ow, oh); +} + +static void transform_output_box(struct wlr_box *box, struct wlr_output *output) { + int ow, oh; + wlr_output_transformed_resolution(output, &ow, &oh); + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); + wlr_box_transform(box, box, transform, ow, oh); +} + + /** * Apply scale to a width or height. * @@ -54,28 +71,6 @@ static int scale_length(int length, int offset, float scale) { return roundf((offset + length) * scale) - roundf(offset * scale); } -static void scissor_output(struct wlr_output *wlr_output, - pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_output->renderer; - 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, &box, transform, ow, oh); - - wlr_renderer_scissor(renderer, &box); -} - static void set_scale_filter(struct wlr_output *wlr_output, struct wlr_texture *texture, enum scale_filter_mode scale_filter) { #if WLR_HAS_GLES2_RENDERER @@ -103,40 +98,39 @@ static void set_scale_filter(struct wlr_output *wlr_output, } static void render_texture(struct render_context *ctx, struct wlr_texture *texture, - const struct wlr_fbox *src_box, const struct wlr_box *dst_box, + const struct wlr_fbox *_src_box, const struct wlr_box *dst_box, enum wl_output_transform transform, float alpha) { - struct wlr_renderer *renderer = ctx->renderer; struct sway_output *output = ctx->output; struct wlr_box proj_box = *dst_box; - scale_box(&proj_box, output->wlr_output->scale); - float matrix[9]; - enum wl_output_transform inv_transform = wlr_output_transform_invert(transform); - wlr_matrix_project_box(matrix, &proj_box, inv_transform, 0, - output->wlr_output->transform_matrix); + struct wlr_fbox src_box = {0}; + if (_src_box) { + src_box = *_src_box; + } pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, - dst_box->width, dst_box->height); + pixman_region32_init_rect(&damage, proj_box.x, proj_box.y, + proj_box.width, proj_box.height); pixman_region32_intersect(&damage, &damage, ctx->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(output->wlr_output, &rects[i]); - set_scale_filter(output->wlr_output, texture, output->scale_filter); - if (src_box != NULL) { - wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, alpha); - } else { - wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); - } - } + transform_output_box(&proj_box, output->wlr_output); + transform_output_damage(&damage, output->wlr_output); + transform = wlr_output_transform_compose(transform, output->wlr_output->transform); + + set_scale_filter(output->wlr_output, texture, output->scale_filter); + wlr_render_pass_add_texture(ctx->pass, &(struct wlr_render_texture_options) { + .texture = texture, + .src_box = src_box, + .dst_box = proj_box, + .transform = transform, + .alpha = &alpha, + .clip = &damage, + }); damage_finish: pixman_region32_fini(&damage); @@ -218,16 +212,13 @@ static void render_drag_icons(struct render_context *ctx, struct wl_list *drag_i void render_rect(struct render_context *ctx, const struct wlr_box *_box, float color[static 4]) { struct wlr_output *wlr_output = ctx->output->wlr_output; - struct wlr_renderer *renderer = ctx->renderer; - struct wlr_box box; - memcpy(&box, _box, sizeof(struct wlr_box)); + struct wlr_box box = *_box; box.x -= ctx->output->lx * wlr_output->scale; box.y -= ctx->output->ly * wlr_output->scale; pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, box.x, box.y, + pixman_region32_init_rect(&damage, box.x, box.y, box.width, box.height); pixman_region32_intersect(&damage, &damage, ctx->output_damage); bool damaged = pixman_region32_not_empty(&damage); @@ -235,13 +226,19 @@ void render_rect(struct render_context *ctx, const struct wlr_box *_box, 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); - } + transform_output_damage(&damage, wlr_output); + transform_output_box(&box, wlr_output); + + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = box, + .color = { + .r = color[0], + .g = color[1], + .b = color[2], + .a = color[3], + }, + .clip = &damage, + }); damage_finish: pixman_region32_fini(&damage); @@ -1006,7 +1003,6 @@ static void render_seatops(struct render_context *ctx) { void output_render(struct render_context *ctx) { struct wlr_output *wlr_output = ctx->output->wlr_output; - struct wlr_renderer *renderer = ctx->renderer; struct sway_output *output = ctx->output; const pixman_region32_t *damage = ctx->output_damage; @@ -1020,32 +1016,38 @@ void output_render(struct render_context *ctx) { fullscreen_con = workspace->current.fullscreen; } - if (!wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height)) { - return; - } - if (!pixman_region32_not_empty(damage)) { // Output isn't damaged but needs buffer swap goto renderer_end; } if (debug.damage == DAMAGE_HIGHLIGHT) { - wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = output->width, .height = output->height }, + .color = { .r = 1, .g = 1, .b = 0, .a = 1 }, + }); } + pixman_region32_t transformed_damage; + pixman_region32_init(&transformed_damage); + pixman_region32_copy(&transformed_damage, damage); + transform_output_damage(&transformed_damage, wlr_output); + if (server.session_lock.locked) { - float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + struct wlr_render_color clear_color = { + .a = 1.0f + }; if (server.session_lock.lock == NULL) { // abandoned lock -> red BG - clear_color[0] = 1.f; - } - 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); + clear_color.r = 1.f; } + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = output->width, .height = output->height }, + .color = clear_color, + .clip = &transformed_damage, + }); + if (server.session_lock.lock != NULL) { struct render_data data = { .alpha = 1.0f, @@ -1073,14 +1075,11 @@ void output_render(struct render_context *ctx) { } if (fullscreen_con) { - 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); - } + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = output->width, .height = output->height }, + .color = { .r = 0, .g = 0, .b = 0, .a = 1 }, + .clip = &transformed_damage, + }); if (fullscreen_con->view) { if (!wl_list_empty(&fullscreen_con->view->saved_buffers)) { @@ -1104,14 +1103,11 @@ void output_render(struct render_context *ctx) { render_unmanaged(ctx, &root->xwayland_unmanaged); #endif } 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); - } + wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ + .box = { .width = output->width, .height = output->height }, + .color = { .r = 0.25f, .g = 0.25f, .b = 0.25f, .a = 1 }, + .clip = &transformed_damage, + }); render_layer_toplevel(ctx, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); @@ -1150,7 +1146,6 @@ render_overlay: render_drag_icons(ctx, &root->drag_icons); renderer_end: - wlr_renderer_scissor(renderer, NULL); - wlr_output_render_software_cursors(wlr_output, damage); - wlr_renderer_end(renderer); + pixman_region32_fini(&transformed_damage); + wlr_output_add_software_cursors_to_render_pass(wlr_output, ctx->pass, damage); } From db7638a0e515635e3aa36fa8bef58f3e44b177d8 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 2 May 2023 17:12:21 -0400 Subject: [PATCH 04/34] Don't crash if there is no damage during render --- 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 37e84647..92ccfd09 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -1018,7 +1018,7 @@ void output_render(struct render_context *ctx) { if (!pixman_region32_not_empty(damage)) { // Output isn't damaged but needs buffer swap - goto renderer_end; + return; } if (debug.damage == DAMAGE_HIGHLIGHT) { From e8f7551e46052a8df04b630bf06565ca77f830fb Mon Sep 17 00:00:00 2001 From: hrdl <31923882+hrdl-github@users.noreply.github.com> Date: Thu, 4 May 2023 01:13:33 +0200 Subject: [PATCH 05/34] Add support for touch cancel events --- include/sway/input/cursor.h | 1 + include/sway/input/seat.h | 5 +++++ sway/input/cursor.c | 22 ++++++++++++++++++++++ sway/input/seat.c | 6 ++++++ sway/input/seatop_down.c | 19 +++++++++++++++++++ 5 files changed, 53 insertions(+) diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 4a3774d9..c7da8829 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -53,6 +53,7 @@ struct sway_cursor { struct wl_listener touch_down; struct wl_listener touch_up; + struct wl_listener touch_cancel; struct wl_listener touch_motion; struct wl_listener touch_frame; bool simulating_pointer_from_touch; diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 6d29cf3b..5ef8e2f3 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -44,6 +44,8 @@ struct sway_seatop_impl { struct wlr_touch_up_event *event); void (*touch_down)(struct sway_seat *seat, struct wlr_touch_down_event *event, double lx, double ly); + void (*touch_cancel)(struct sway_seat *seat, + struct wlr_touch_cancel_event *event); void (*tablet_tool_motion)(struct sway_seat *seat, struct sway_tablet_tool *tool, uint32_t time_msec); void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool, @@ -338,6 +340,9 @@ void seatop_touch_up(struct sway_seat *seat, void seatop_touch_down(struct sway_seat *seat, struct wlr_touch_down_event *event, double lx, double ly); +void seatop_touch_cancel(struct sway_seat *seat, + struct wlr_touch_cancel_event *event); + void seatop_rebase(struct sway_seat *seat, uint32_t time_msec); /** diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 75d055cd..d8ec11ac 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -509,6 +509,24 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { } } +static void handle_touch_cancel(struct wl_listener *listener, void *data) { + struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_cancel); + struct wlr_touch_cancel_event *event = data; + cursor_handle_activity_from_device(cursor, &event->touch->base); + + struct sway_seat *seat = cursor->seat; + + if (cursor->simulating_pointer_from_touch) { + if (cursor->pointer_touch_id == cursor->seat->touch_id) { + cursor->pointer_touch_up = true; + dispatch_cursor_button(cursor, &event->touch->base, + event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED); + } + } else { + seatop_touch_cancel(seat, event); + } +} + static void handle_touch_motion(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_motion); @@ -1100,6 +1118,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) { wl_list_remove(&cursor->frame.link); wl_list_remove(&cursor->touch_down.link); wl_list_remove(&cursor->touch_up.link); + wl_list_remove(&cursor->touch_cancel.link); wl_list_remove(&cursor->touch_motion.link); wl_list_remove(&cursor->touch_frame.link); wl_list_remove(&cursor->tool_axis.link); @@ -1181,6 +1200,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up); cursor->touch_up.notify = handle_touch_up; + wl_signal_add(&wlr_cursor->events.touch_cancel, &cursor->touch_cancel); + cursor->touch_cancel.notify = handle_touch_cancel; + wl_signal_add(&wlr_cursor->events.touch_motion, &cursor->touch_motion); cursor->touch_motion.notify = handle_touch_motion; diff --git a/sway/input/seat.c b/sway/input/seat.c index 6b95e46a..bcb89b48 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1638,6 +1638,12 @@ void seatop_touch_down(struct sway_seat *seat, struct wlr_touch_down_event *even } } +void seatop_touch_cancel(struct sway_seat *seat, struct wlr_touch_cancel_event *event) { + if (seat->seatop_impl->touch_cancel) { + seat->seatop_impl->touch_cancel(seat, event); + } +} + void seatop_tablet_tool_tip(struct sway_seat *seat, struct sway_tablet_tool *tool, uint32_t time_msec, enum wlr_tablet_tool_tip_state state) { diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index 6447134e..c5901f6a 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -104,6 +104,24 @@ static void handle_touch_down(struct sway_seat *seat, } } +static void handle_touch_cancel(struct sway_seat *seat, + struct wlr_touch_cancel_event *event) { + struct seatop_down_event *e = seat->seatop_data; + struct seatop_touch_point_event *point_event, *tmp; + + wl_list_for_each_safe(point_event, tmp, &e->point_events, link) { + if (point_event->touch_id == event->touch_id) { + wl_list_remove(&point_event->link); + free(point_event); + break; + } + } + + if (e->surface) { + wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface); + } +} + static void handle_pointer_axis(struct sway_seat *seat, struct wlr_pointer_axis_event *event) { struct sway_input_device *input_device = @@ -189,6 +207,7 @@ static const struct sway_seatop_impl seatop_impl = { .touch_motion = handle_touch_motion, .touch_up = handle_touch_up, .touch_down = handle_touch_down, + .touch_cancel = handle_touch_cancel, .unref = handle_unref, .end = handle_end, .allow_set_cursor = true, From 3cd7c7178079bf61bb7967690e7767442b369782 Mon Sep 17 00:00:00 2001 From: hrdl <31923882+hrdl-github@users.noreply.github.com> Date: Thu, 4 May 2023 17:26:15 +0200 Subject: [PATCH 06/34] handle_touch_cancel: fix begin default I forgot to call seatop_begin_default in e8f7551e46052a8df04b630bf06565ca77f830fb. --- sway/input/seatop_down.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index c5901f6a..81e8d0a7 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -117,6 +117,10 @@ static void handle_touch_cancel(struct sway_seat *seat, } } + if (wl_list_empty(&e->point_events)) { + seatop_begin_default(seat); + } + if (e->surface) { wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface); } From a79994e11961ae24d7a418a18d43bfdd48d1f44b Mon Sep 17 00:00:00 2001 From: Mukundan314 <30190448+Mukundan314@users.noreply.github.com> Date: Thu, 4 May 2023 14:57:20 +0530 Subject: [PATCH 07/34] swaybar: always subscribe to mode and workspace always subscribe to mode and workspace events, since we might need them after bar config updates even if we don't need them initially. --- swaybar/ipc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 9d81a9fb..33ae6544 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -426,12 +426,9 @@ bool ipc_initialize(struct swaybar *bar) { } free(res); - struct swaybar_config *config = bar->config; - char subscribe[128]; // suitably large buffer - len = snprintf(subscribe, 128, - "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]", - config->binding_mode_indicator ? ", \"mode\"" : "", - config->workspace_buttons ? ", \"workspace\"" : ""); + char *subscribe = + "[ \"barconfig_update\", \"bar_state_update\", \"mode\", \"workspace\" ]"; + len = strlen(subscribe); free(ipc_single_command(bar->ipc_event_socketfd, IPC_SUBSCRIBE, subscribe, &len)); return true; From 393c29fc591b6e0fb85328b638607d8b5784a0e3 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 9 May 2023 15:08:47 +0200 Subject: [PATCH 08/34] render: Apply clip to rendered texture correctly The new wlr_render_pass API provides src_box, dst_box and clip parameters for texture rendition. Rather than clipping the dst_box, which control the projection matrix and leads to compression, intersect the damage and clip box and pass these as a clip parameter. Fixes: https://github.com/swaywm/sway/issues/7579 Regressed by: https://github.com/swaywm/sway/pull/7552 --- sway/desktop/render.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 92ccfd09..552502aa 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -99,7 +99,7 @@ static void set_scale_filter(struct wlr_output *wlr_output, static void render_texture(struct render_context *ctx, struct wlr_texture *texture, const struct wlr_fbox *_src_box, const struct wlr_box *dst_box, - enum wl_output_transform transform, float alpha) { + const struct wlr_box *clip_box, enum wl_output_transform transform, float alpha) { struct sway_output *output = ctx->output; struct wlr_box proj_box = *dst_box; @@ -113,6 +113,12 @@ static void render_texture(struct render_context *ctx, struct wlr_texture *textu pixman_region32_init_rect(&damage, proj_box.x, proj_box.y, proj_box.width, proj_box.height); pixman_region32_intersect(&damage, &damage, ctx->output_damage); + + if (clip_box) { + pixman_region32_intersect_rect(&damage, &damage, + clip_box->x, clip_box->y, clip_box->width, clip_box->height); + } + bool damaged = pixman_region32_not_empty(&damage); if (!damaged) { goto damage_finish; @@ -151,19 +157,17 @@ static void render_surface_iterator(struct sway_output *output, struct wlr_fbox src_box; wlr_surface_get_buffer_source_box(surface, &src_box); - struct wlr_box proj_box = *_box; - scale_box(&proj_box, wlr_output->scale); - struct wlr_box dst_box = *_box; - struct wlr_box *clip_box = data->clip_box; - if (clip_box != NULL) { - dst_box.width = fmin(dst_box.width, clip_box->width); - dst_box.height = fmin(dst_box.height, clip_box->height); + struct wlr_box clip_box = *_box; + if (data->clip_box != NULL) { + clip_box.width = fmin(dst_box.width, data->clip_box->width); + clip_box.height = fmin(dst_box.height, data->clip_box->height); } scale_box(&dst_box, wlr_output->scale); + scale_box(&clip_box, wlr_output->scale); render_texture(data->ctx, texture, - &src_box, &dst_box, surface->current.transform, alpha); + &src_box, &dst_box, &clip_box, surface->current.transform, alpha); wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_output); @@ -320,20 +324,20 @@ static void render_saved_view(struct render_context *ctx, struct sway_view *view } struct wlr_box dst_box = proj_box; - scale_box(&proj_box, wlr_output->scale); - + struct wlr_box clip_box = proj_box; if (!floating) { - dst_box.width = fmin(dst_box.width, + clip_box.width = fmin(dst_box.width, view->container->current.content_width - (saved_buf->x - view->container->current.content_x) + view->saved_geometry.x); - dst_box.height = fmin(dst_box.height, + clip_box.height = fmin(dst_box.height, view->container->current.content_height - (saved_buf->y - view->container->current.content_y) + view->saved_geometry.y); } scale_box(&dst_box, wlr_output->scale); + scale_box(&clip_box, wlr_output->scale); render_texture(ctx, saved_buf->buffer->texture, - &saved_buf->source_box, &dst_box, saved_buf->transform, alpha); + &saved_buf->source_box, &dst_box, &clip_box, saved_buf->transform, alpha); } // FIXME: we should set the surface that this saved buffer originates from @@ -509,7 +513,7 @@ static void render_titlebar(struct render_context *ctx, struct sway_container *c texture_box.width = ob_inner_width; } render_texture(ctx, marks_texture, - NULL, &texture_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); + NULL, &texture_box, NULL, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); @@ -580,7 +584,7 @@ static void render_titlebar(struct render_context *ctx, struct sway_container *c } render_texture(ctx, title_texture, - NULL, &texture_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); + NULL, &texture_box, NULL, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); From 0a951517aed2375b972bbd70cb164bf7acb25e00 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 9 May 2023 15:13:39 +0200 Subject: [PATCH 09/34] render: Clear using wlr_output dimensions Clear was done using sway_output's logical dimensions, instead of the wlr_output physical dimensions. This meant that when output scaling was applied, only a part of the screen would be cleared. Use the wlr_output dimensions instead. Regressed by: https://github.com/swaywm/sway/pull/7552 --- sway/desktop/render.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 552502aa..edefa658 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -1027,7 +1027,7 @@ void output_render(struct render_context *ctx) { if (debug.damage == DAMAGE_HIGHLIGHT) { wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ - .box = { .width = output->width, .height = output->height }, + .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = { .r = 1, .g = 1, .b = 0, .a = 1 }, }); } @@ -1047,7 +1047,7 @@ void output_render(struct render_context *ctx) { } wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ - .box = { .width = output->width, .height = output->height }, + .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = clear_color, .clip = &transformed_damage, }); @@ -1080,7 +1080,7 @@ void output_render(struct render_context *ctx) { if (fullscreen_con) { wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ - .box = { .width = output->width, .height = output->height }, + .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = { .r = 0, .g = 0, .b = 0, .a = 1 }, .clip = &transformed_damage, }); @@ -1108,7 +1108,7 @@ void output_render(struct render_context *ctx) { #endif } else { wlr_render_pass_add_rect(ctx->pass, &(struct wlr_render_rect_options){ - .box = { .width = output->width, .height = output->height }, + .box = { .width = wlr_output->width, .height = wlr_output->height }, .color = { .r = 0.25f, .g = 0.25f, .b = 0.25f, .a = 1 }, .clip = &transformed_damage, }); From 19cc36accc0d5a9997fd264c98df92b8b0ed8bea Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 9 May 2023 16:39:48 +0200 Subject: [PATCH 10/34] render: fix titlebar texture clipping We need to provide an unclipped dst_box. Fixes: https://github.com/swaywm/sway/issues/7573 Regressed by: https://github.com/swaywm/sway/pull/7552 --- sway/desktop/render.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index edefa658..223457b2 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -509,23 +509,24 @@ static void render_titlebar(struct render_context *ctx, struct sway_container *c texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; - if (ob_inner_width < texture_box.width) { - texture_box.width = ob_inner_width; + struct wlr_box clip_box = texture_box; + if (ob_inner_width < clip_box.width) { + clip_box.width = ob_inner_width; } render_texture(ctx, marks_texture, - NULL, &texture_box, NULL, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); + NULL, &texture_box, &clip_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = texture_box.x + round(output_x * output_scale); + box.x = clip_box.x + round(output_x * output_scale); box.y = roundf((y + titlebar_border_thickness) * output_scale); - box.width = texture_box.width; + box.width = clip_box.width; box.height = ob_padding_above; render_rect(ctx, &box, color); // Padding below - box.y += ob_padding_above + texture_box.height; + box.y += ob_padding_above + clip_box.height; box.height = ob_padding_below; render_rect(ctx, &box, color); } @@ -579,24 +580,25 @@ static void render_titlebar(struct render_context *ctx, struct sway_container *c texture_box.y = round((bg_y - output_y) * output_scale) + ob_padding_above; - if (ob_inner_width - ob_marks_width < texture_box.width) { - texture_box.width = ob_inner_width - ob_marks_width; + struct wlr_box clip_box = texture_box; + if (ob_inner_width - ob_marks_width < clip_box.width) { + clip_box.width = ob_inner_width - ob_marks_width; } render_texture(ctx, title_texture, - NULL, &texture_box, NULL, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); + NULL, &texture_box, &clip_box, WL_OUTPUT_TRANSFORM_NORMAL, con->alpha); // Padding above memcpy(&color, colors->background, sizeof(float) * 4); premultiply_alpha(color, con->alpha); - box.x = texture_box.x + round(output_x * output_scale); + box.x = clip_box.x + round(output_x * output_scale); box.y = roundf((y + titlebar_border_thickness) * output_scale); - box.width = texture_box.width; + box.width = clip_box.width; box.height = ob_padding_above; render_rect(ctx, &box, color); // Padding below - box.y += ob_padding_above + texture_box.height; + box.y += ob_padding_above + clip_box.height; box.height = ob_padding_below; render_rect(ctx, &box, color); } From 01b0c11394b88fea2ec8ac691e30504f1e0800f5 Mon Sep 17 00:00:00 2001 From: hrdl <31923882+hrdl-github@users.noreply.github.com> Date: Thu, 11 May 2023 11:16:51 +0200 Subject: [PATCH 11/34] seatop_down: Call seatop_begin_default after sending touch events This is consistent with pointer tablet and button events. Fixes #7577. --- sway/input/seatop_down.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index 81e8d0a7..36f9bb60 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -64,11 +64,11 @@ static void handle_touch_up(struct sway_seat *seat, } } + wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec, event->touch_id); + if (wl_list_empty(&e->point_events)) { seatop_begin_default(seat); } - - wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec, event->touch_id); } static void handle_touch_down(struct sway_seat *seat, @@ -117,13 +117,13 @@ static void handle_touch_cancel(struct sway_seat *seat, } } - if (wl_list_empty(&e->point_events)) { - seatop_begin_default(seat); - } - if (e->surface) { wlr_seat_touch_notify_cancel(seat->wlr_seat, e->surface); } + + if (wl_list_empty(&e->point_events)) { + seatop_begin_default(seat); + } } static void handle_pointer_axis(struct sway_seat *seat, From 48d6eda3cb0f79d2190756af44f01d028696bf0e Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Sat, 20 May 2023 15:04:11 +0200 Subject: [PATCH 12/34] Fix layer old damage not being offset by the monitor layout coords --- sway/desktop/layer_shell.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index e16bee78..cf795dc7 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -312,6 +312,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { bool extent_changed = memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0; if (extent_changed || layer_changed) { + old_extent.x += output->lx; + old_extent.y += output->ly; output_damage_box(output, &old_extent); output_damage_surface(output, layer->geo.x, layer->geo.y, layer_surface->surface, true); From 72881b5d120442e3a6f9c5b022c8d9cc05cb27c0 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 9 Mar 2023 13:02:13 +0300 Subject: [PATCH 13/34] xwayland: don't rely on event source being data This pattern is being slowly removed from wlroots. --- sway/desktop/xwayland.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 9c29f66b..bcefc4fd 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -125,7 +125,9 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { } static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) { - struct wlr_xwayland_surface *xsurface = data; + struct sway_xwayland_unmanaged *surface = + wl_container_of(listener, surface, request_activate); + struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; if (!xsurface->mapped) { return; } @@ -495,8 +497,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) { static void handle_map(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, map); - struct wlr_xwayland_surface *xsurface = data; struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; view->natural_width = xsurface->width; view->natural_height = xsurface->height; @@ -515,8 +517,8 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_override_redirect(struct wl_listener *listener, void *data) { struct sway_xwayland_view *xwayland_view = wl_container_of(listener, xwayland_view, override_redirect); - struct wlr_xwayland_surface *xsurface = data; struct sway_view *view = &xwayland_view->view; + struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; bool mapped = xsurface->mapped; if (mapped) { From c9e1dab3187d22ada0232d699e759a628e0ed185 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sun, 5 Mar 2023 23:49:45 +0300 Subject: [PATCH 14/34] chore: chase wlroots map logic unification --- include/sway/tree/view.h | 4 ++ sway/desktop/layer_shell.c | 22 +++++----- sway/desktop/output.c | 4 +- sway/desktop/render.c | 2 +- sway/desktop/xdg_shell.c | 10 ++--- sway/desktop/xwayland.c | 87 ++++++++++++++++++++++++++------------ sway/input/seat.c | 8 ++-- sway/lock.c | 2 +- sway/xdg_activation_v1.c | 2 +- 9 files changed, 90 insertions(+), 51 deletions(-) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 7fc2d95d..960f9d71 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -160,6 +160,8 @@ struct sway_xwayland_view { struct wl_listener set_window_type; struct wl_listener set_hints; struct wl_listener set_decorations; + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; @@ -177,6 +179,8 @@ struct sway_xwayland_unmanaged { struct wl_listener request_fullscreen; struct wl_listener commit; struct wl_listener set_geometry; + struct wl_listener associate; + struct wl_listener dissociate; struct wl_listener map; struct wl_listener unmap; struct wl_listener destroy; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index cf795dc7..50aa6938 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -219,7 +219,7 @@ void arrange_layers(struct sway_output *output) { wl_list_for_each_reverse(layer, &output->layers[layers_above_shell[i]], link) { if (layer->layer_surface->current.keyboard_interactive && - layer->layer_surface->mapped) { + layer->layer_surface->surface->mapped) { topmost = layer; break; } @@ -253,7 +253,7 @@ static struct sway_layer_surface *find_mapped_layer_by_client( &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) { struct wl_resource *resource = lsurface->layer_surface->resource; if (wl_resource_get_client(resource) == client - && lsurface->layer_surface->mapped) { + && lsurface->layer_surface->surface->mapped) { return lsurface; } } @@ -293,8 +293,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { bool layer_changed = false; if (layer_surface->current.committed != 0 - || layer->mapped != layer_surface->mapped) { - layer->mapped = layer_surface->mapped; + || layer->mapped != layer_surface->surface->mapped) { + layer->mapped = layer_surface->surface->mapped; layer_changed = layer->layer != layer_surface->current.layer; if (layer_changed) { wl_list_remove(&layer->link); @@ -349,7 +349,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, sway_layer, destroy); sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)", sway_layer->layer_surface->namespace); - if (sway_layer->layer_surface->mapped) { + if (sway_layer->layer_surface->surface->mapped) { unmap(sway_layer); } @@ -454,9 +454,9 @@ static struct sway_layer_subsurface *create_subsurface( wl_list_insert(&layer_surface->subsurfaces, &subsurface->link); subsurface->map.notify = subsurface_handle_map; - wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); + wl_signal_add(&wlr_subsurface->surface->events.map, &subsurface->map); subsurface->unmap.notify = subsurface_handle_unmap; - wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap); + wl_signal_add(&wlr_subsurface->surface->events.unmap, &subsurface->unmap); subsurface->destroy.notify = subsurface_handle_destroy; wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); subsurface->commit.notify = subsurface_handle_commit; @@ -571,9 +571,9 @@ static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup, popup->parent_layer = parent; popup->map.notify = popup_handle_map; - wl_signal_add(&wlr_popup->base->events.map, &popup->map); + wl_signal_add(&wlr_popup->base->surface->events.map, &popup->map); popup->unmap.notify = popup_handle_unmap; - wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); + wl_signal_add(&wlr_popup->base->surface->events.unmap, &popup->unmap); popup->destroy.notify = popup_handle_destroy; wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); popup->commit.notify = popup_handle_commit; @@ -661,9 +661,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { sway_layer->destroy.notify = handle_destroy; wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy); sway_layer->map.notify = handle_map; - wl_signal_add(&layer_surface->events.map, &sway_layer->map); + wl_signal_add(&layer_surface->surface->events.map, &sway_layer->map); sway_layer->unmap.notify = handle_unmap; - wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap); + wl_signal_add(&layer_surface->surface->events.unmap, &sway_layer->unmap); sway_layer->new_popup.notify = handle_new_popup; wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup); sway_layer->new_subsurface.notify = handle_new_subsurface; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 01bc87bb..fe1fa8af 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -265,7 +265,7 @@ void output_drag_icons_for_each_surface(struct sway_output *output, double ox = drag_icon->x - output->lx; double oy = drag_icon->y - output->ly; - if (drag_icon->wlr_drag_icon->mapped) { + if (drag_icon->wlr_drag_icon->surface->mapped) { output_surface_for_each_surface(output, drag_icon->wlr_drag_icon->surface, ox, oy, iterator, user_data); @@ -295,7 +295,7 @@ static void output_for_each_surface(struct sway_output *output, if (lock_surface->output != output->wlr_output) { continue; } - if (!lock_surface->mapped) { + if (!lock_surface->surface->mapped) { continue; } diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 223457b2..21014042 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -1065,7 +1065,7 @@ void output_render(struct render_context *ctx) { if (lock_surface->output != wlr_output) { continue; } - if (!lock_surface->mapped) { + if (!lock_surface->surface->mapped) { continue; } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 9b6456da..377a0f1c 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -104,8 +104,8 @@ static struct sway_xdg_popup *popup_create( wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&xdg_surface->events.map, &popup->child.surface_map); - wl_signal_add(&xdg_surface->events.unmap, &popup->child.surface_unmap); + wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map); + wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap); popup_unconstrain(popup); @@ -344,7 +344,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel; struct sway_view *view = &xdg_shell_view->view; - if (!toplevel->base->mapped) { + if (!toplevel->base->surface->mapped) { return; } @@ -529,10 +529,10 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel; xdg_shell_view->map.notify = handle_map; - wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map); + wl_signal_add(&xdg_surface->surface->events.map, &xdg_shell_view->map); xdg_shell_view->unmap.notify = handle_unmap; - wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap); + wl_signal_add(&xdg_surface->surface->events.unmap, &xdg_shell_view->unmap); xdg_shell_view->destroy.notify = handle_destroy; wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index bcefc4fd..bb4340f1 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -128,7 +128,7 @@ static void unmanaged_handle_request_activate(struct wl_listener *listener, void struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, request_activate); struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } struct sway_seat *seat = input_manager_current_seat(); @@ -140,12 +140,29 @@ static void unmanaged_handle_request_activate(struct wl_listener *listener, void seat_set_focus_surface(seat, xsurface->surface, false); } +static void unmanaged_handle_associate(struct wl_listener *listener, void *data) { + struct sway_xwayland_unmanaged *surface = + wl_container_of(listener, surface, associate); + struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; + wl_signal_add(&xsurface->surface->events.map, &surface->map); + surface->map.notify = unmanaged_handle_map; + wl_signal_add(&xsurface->surface->events.unmap, &surface->unmap); + surface->unmap.notify = unmanaged_handle_unmap; +} + +static void unmanaged_handle_dissociate(struct wl_listener *listener, void *data) { + struct sway_xwayland_unmanaged *surface = + wl_container_of(listener, surface, dissociate); + wl_list_remove(&surface->map.link); + wl_list_remove(&surface->unmap.link); +} + static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) { struct sway_xwayland_unmanaged *surface = wl_container_of(listener, surface, destroy); wl_list_remove(&surface->request_configure.link); - wl_list_remove(&surface->map.link); - wl_list_remove(&surface->unmap.link); + wl_list_remove(&surface->associate.link); + wl_list_remove(&surface->dissociate.link); wl_list_remove(&surface->destroy.link); wl_list_remove(&surface->override_redirect.link); wl_list_remove(&surface->request_activate.link); @@ -161,7 +178,7 @@ static void unmanaged_handle_override_redirect(struct wl_listener *listener, voi wl_container_of(listener, surface, override_redirect); struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - bool mapped = xsurface->mapped; + bool mapped = xsurface->surface != NULL || xsurface->surface->mapped; if (mapped) { unmanaged_handle_unmap(&surface->unmap, NULL); } @@ -188,10 +205,10 @@ static struct sway_xwayland_unmanaged *create_unmanaged( wl_signal_add(&xsurface->events.request_configure, &surface->request_configure); surface->request_configure.notify = unmanaged_handle_request_configure; - wl_signal_add(&xsurface->events.map, &surface->map); - surface->map.notify = unmanaged_handle_map; - wl_signal_add(&xsurface->events.unmap, &surface->unmap); - surface->unmap.notify = unmanaged_handle_unmap; + wl_signal_add(&xsurface->events.associate, &surface->associate); + surface->associate.notify = unmanaged_handle_associate; + wl_signal_add(&xsurface->events.dissociate, &surface->dissociate); + surface->dissociate.notify = unmanaged_handle_dissociate; wl_signal_add(&xsurface->events.destroy, &surface->destroy); surface->destroy.notify = unmanaged_handle_destroy; wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect); @@ -474,8 +491,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&xwayland_view->set_window_type.link); wl_list_remove(&xwayland_view->set_hints.link); wl_list_remove(&xwayland_view->set_decorations.link); - wl_list_remove(&xwayland_view->map.link); - wl_list_remove(&xwayland_view->unmap.link); + wl_list_remove(&xwayland_view->associate.link); + wl_list_remove(&xwayland_view->dissociate.link); wl_list_remove(&xwayland_view->override_redirect.link); view_begin_destroy(&xwayland_view->view); } @@ -520,7 +537,7 @@ static void handle_override_redirect(struct wl_listener *listener, void *data) { struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - bool mapped = xsurface->mapped; + bool mapped = xsurface->surface != NULL || xsurface->surface->mapped; if (mapped) { handle_unmap(&xwayland_view->unmap, NULL); } @@ -539,7 +556,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { struct wlr_xwayland_surface_configure_event *ev = data; struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, ev->width, ev->height); return; @@ -568,7 +585,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) wl_container_of(listener, xwayland_view, request_fullscreen); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } container_set_fullscreen(view->container, xsurface->fullscreen); @@ -582,7 +599,7 @@ static void handle_request_minimize(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_minimize); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } @@ -597,7 +614,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_move); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } if (!container_is_floating(view->container) || @@ -613,7 +630,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_resize); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } if (!container_is_floating(view->container)) { @@ -629,7 +646,7 @@ static void handle_request_activate(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, request_activate); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_request_activate(view, NULL); @@ -642,7 +659,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_title); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_update_title(view, false); @@ -654,7 +671,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_class); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_execute_criteria(view); @@ -665,7 +682,7 @@ static void handle_set_role(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_role); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_execute_criteria(view); @@ -701,7 +718,7 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_window_type); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } view_execute_criteria(view); @@ -712,7 +729,7 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { wl_container_of(listener, xwayland_view, set_hints); struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - if (!xsurface->mapped) { + if (xsurface->surface == NULL || !xsurface->surface->mapped) { return; } const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints); @@ -727,6 +744,24 @@ static void handle_set_hints(struct wl_listener *listener, void *data) { } } +static void handle_associate(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, associate); + struct wlr_xwayland_surface *xsurface = + xwayland_view->view.wlr_xwayland_surface; + wl_signal_add(&xsurface->surface->events.unmap, &xwayland_view->unmap); + xwayland_view->unmap.notify = handle_unmap; + wl_signal_add(&xsurface->surface->events.map, &xwayland_view->map); + xwayland_view->map.notify = handle_map; +} + +static void handle_dissociate(struct wl_listener *listener, void *data) { + struct sway_xwayland_view *xwayland_view = + wl_container_of(listener, xwayland_view, dissociate); + wl_list_remove(&xwayland_view->map.link); + wl_list_remove(&xwayland_view->unmap.link); +} + struct sway_view *view_from_wlr_xwayland_surface( struct wlr_xwayland_surface *xsurface) { return xsurface->data; @@ -796,11 +831,11 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu &xwayland_view->set_decorations); xwayland_view->set_decorations.notify = handle_set_decorations; - wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); - xwayland_view->unmap.notify = handle_unmap; + wl_signal_add(&xsurface->events.associate, &xwayland_view->associate); + xwayland_view->associate.notify = handle_associate; - wl_signal_add(&xsurface->events.map, &xwayland_view->map); - xwayland_view->map.notify = handle_map; + wl_signal_add(&xsurface->events.dissociate, &xwayland_view->dissociate); + xwayland_view->dissociate.notify = handle_dissociate; wl_signal_add(&xsurface->events.set_override_redirect, &xwayland_view->override_redirect); diff --git a/sway/input/seat.c b/sway/input/seat.c index bcb89b48..5795f40f 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -367,7 +367,7 @@ static void handle_new_node(struct wl_listener *listener, void *data) { } static void drag_icon_damage_whole(struct sway_drag_icon *icon) { - if (!icon->wlr_drag_icon->mapped) { + if (!icon->wlr_drag_icon->surface->mapped) { return; } desktop_damage_surface(icon->wlr_drag_icon->surface, icon->x, icon->y, true); @@ -511,9 +511,9 @@ static void handle_start_drag(struct wl_listener *listener, void *data) { icon->surface_commit.notify = drag_icon_handle_surface_commit; wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); icon->unmap.notify = drag_icon_handle_unmap; - wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); + wl_signal_add(&wlr_drag_icon->surface->events.unmap, &icon->unmap); icon->map.notify = drag_icon_handle_map; - wl_signal_add(&wlr_drag_icon->events.map, &icon->map); + wl_signal_add(&wlr_drag_icon->surface->events.map, &icon->map); icon->destroy.notify = drag_icon_handle_destroy; wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); @@ -1350,7 +1350,7 @@ void seat_set_focus_layer(struct sway_seat *seat, } else if (!layer || seat->focused_layer == layer) { return; } - assert(layer->mapped); + assert(layer->surface->mapped); seat_set_focus_surface(seat, layer->surface, true); if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { seat->focused_layer = layer; diff --git a/sway/lock.c b/sway/lock.c index 6d9e991b..ae44aa40 100644 --- a/sway/lock.c +++ b/sway/lock.c @@ -60,7 +60,7 @@ static void destroy_lock_surface(struct sway_session_lock_surface *surf) { struct wlr_session_lock_surface_v1 *other; wl_list_for_each(other, &server.session_lock.lock->surfaces, link) { - if (other != surf->lock_surface && other->mapped) { + if (other != surf->lock_surface && other->surface->mapped) { next_focus = other->surface; break; } diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c index e97989c8..c26ee19a 100644 --- a/sway/xdg_activation_v1.c +++ b/sway/xdg_activation_v1.c @@ -17,7 +17,7 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, return; } - if (!xdg_surface->mapped) { + if (!xdg_surface->surface->mapped) { // This is a startup notification. If we are tracking it, the data // field is a launcher_ctx. struct launcher_ctx *ctx = event->token->data; From c001a57e8bb2912bfce293e71d32fdbe246eae74 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Fri, 2 Jun 2023 23:18:39 +0300 Subject: [PATCH 15/34] lock: listen to the correct map signal --- sway/lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/lock.c b/sway/lock.c index ae44aa40..53456172 100644 --- a/sway/lock.c +++ b/sway/lock.c @@ -104,7 +104,7 @@ static void handle_new_surface(struct wl_listener *listener, void *data) { surf->surface = lock_surface->surface; surf->output = output; surf->map.notify = handle_surface_map; - wl_signal_add(&lock_surface->events.map, &surf->map); + wl_signal_add(&lock_surface->surface->events.map, &surf->map); surf->destroy.notify = handle_surface_destroy; wl_signal_add(&lock_surface->events.destroy, &surf->destroy); surf->surface_commit.notify = handle_surface_commit; From b5cb49bce90bd4d37f08da6a65aba6a99cb7c608 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 3 Jun 2023 07:43:13 +0300 Subject: [PATCH 16/34] xwayland: fix mapped state check in OR handlers --- sway/desktop/xwayland.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index bb4340f1..a52cf4ad 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -178,7 +178,7 @@ static void unmanaged_handle_override_redirect(struct wl_listener *listener, voi wl_container_of(listener, surface, override_redirect); struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface; - bool mapped = xsurface->surface != NULL || xsurface->surface->mapped; + bool mapped = xsurface->surface != NULL && xsurface->surface->mapped; if (mapped) { unmanaged_handle_unmap(&surface->unmap, NULL); } @@ -537,7 +537,7 @@ static void handle_override_redirect(struct wl_listener *listener, void *data) { struct sway_view *view = &xwayland_view->view; struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; - bool mapped = xsurface->surface != NULL || xsurface->surface->mapped; + bool mapped = xsurface->surface != NULL && xsurface->surface->mapped; if (mapped) { handle_unmap(&xwayland_view->unmap, NULL); } From 7ab8cb2ee6f11693987d9f24abec708144807b53 Mon Sep 17 00:00:00 2001 From: Artturin Date: Mon, 5 Jun 2023 23:52:11 +0300 Subject: [PATCH 17/34] chase wlroots wlr_renderer_begin_buffer_pass change https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4159 > ../sway/desktop/output.c:618:47: error: too few arguments to function 'wlr_renderer_begin_buffer_pass' > 618 | struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass( > | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- sway/desktop/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index fe1fa8af..43ce2d70 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -616,7 +616,7 @@ static int output_repaint_timer_handler(void *data) { } struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass( - wlr_output->renderer, buffer); + wlr_output->renderer, buffer, NULL); if (render_pass == NULL) { wlr_buffer_unlock(buffer); return false; From 913a7679cbde98df0722b326d8c3cfc0f0576f6d Mon Sep 17 00:00:00 2001 From: Erik Reider <35975961+ErikReider@users.noreply.github.com> Date: Mon, 5 Jun 2023 15:31:16 +0200 Subject: [PATCH 18/34] Add support for wlr-layer-shell ON_DEMAND keyboard interactivity This allows for layer shell surfaces to receive focus while the surface is explicitly focused, i.e allowing text fields to receive keyboard input just like a regular surface. --- include/sway/input/seat.h | 3 ++- include/sway/layers.h | 4 ++++ sway/desktop/layer_shell.c | 40 +++++++++++++++++++++++++++++++++++-- sway/input/seat.c | 20 ++++++++++++++----- sway/input/seatop_default.c | 24 ++++++++++++++++++---- sway/server.c | 2 +- 6 files changed, 80 insertions(+), 13 deletions(-) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 5ef8e2f3..35a96ace 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -104,8 +104,9 @@ struct sway_seat { struct sway_workspace *workspace; char *prev_workspace_name; // for workspace back_and_forth - // If the focused layer is set, views cannot receive keyboard focus struct wlr_layer_surface_v1 *focused_layer; + // If the exclusive layer is set, views cannot receive keyboard focus + bool has_exclusive_layer; // If exclusive_client is set, no other clients will receive input events struct wl_client *exclusive_client; diff --git a/include/sway/layers.h b/include/sway/layers.h index f8508493..9220bdb5 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h @@ -55,6 +55,10 @@ struct sway_layer_subsurface { }; struct sway_output; + +struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( + struct wlr_surface *surface); + void arrange_layers(struct sway_output *output); struct sway_layer_surface *layer_from_wlr_layer_surface_v1( diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 50aa6938..d990d92a 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -17,6 +17,39 @@ #include "sway/tree/arrange.h" #include "sway/tree/workspace.h" +struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( + struct wlr_surface *surface) { + struct wlr_layer_surface_v1 *layer; + do { + if (!surface) { + return NULL; + } + // Topmost layer surface + if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) { + return layer; + } + // Layer subsurface + if (wlr_subsurface_try_from_wlr_surface(surface)) { + surface = wlr_surface_get_root_surface(surface); + continue; + } + + // Layer surface popup + struct wlr_xdg_surface * xdg_popup = NULL; + if ((xdg_popup = wlr_xdg_surface_try_from_wlr_surface(surface)) && + xdg_popup->role == WLR_XDG_SURFACE_ROLE_POPUP) { + if (!xdg_popup->popup->parent) { + return NULL; + } + surface = wlr_surface_get_root_surface(xdg_popup->popup->parent); + continue; + } + + // Return early if the surface is not a layer/xdg_popup/sub surface + return NULL; + } while (true); +} + static void apply_exclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, int32_t margin_top, int32_t margin_right, @@ -218,7 +251,8 @@ void arrange_layers(struct sway_output *output) { for (size_t i = 0; i < nlayers; ++i) { wl_list_for_each_reverse(layer, &output->layers[layers_above_shell[i]], link) { - if (layer->layer_surface->current.keyboard_interactive && + if (layer->layer_surface->current.keyboard_interactive + == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE && layer->layer_surface->surface->mapped) { topmost = layer; break; @@ -231,10 +265,12 @@ void arrange_layers(struct sway_output *output) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { + seat->has_exclusive_layer = false; if (topmost != NULL) { seat_set_focus_layer(seat, topmost->layer_surface); } else if (seat->focused_layer && - !seat->focused_layer->current.keyboard_interactive) { + seat->focused_layer->current.keyboard_interactive + != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { seat_set_focus_layer(seat, NULL); } } diff --git a/sway/input/seat.c b/sway/input/seat.c index 5795f40f..fdd21057 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1295,11 +1295,15 @@ static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *n } void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { - if (seat->focused_layer) { + // Prevents the layer from losing focus if it has keyboard exclusivity + if (seat->has_exclusive_layer) { struct wlr_layer_surface_v1 *layer = seat->focused_layer; seat_set_focus_layer(seat, NULL); seat_set_workspace_focus(seat, node); seat_set_focus_layer(seat, layer); + } else if (seat->focused_layer) { + seat_set_focus_layer(seat, NULL); + seat_set_workspace_focus(seat, node); } else { seat_set_workspace_focus(seat, node); } @@ -1347,14 +1351,20 @@ void seat_set_focus_layer(struct sway_seat *seat, seat_set_focus(seat, previous); } return; - } else if (!layer || seat->focused_layer == layer) { + } else if (!layer) { return; } assert(layer->surface->mapped); - seat_set_focus_surface(seat, layer->surface, true); - if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { - seat->focused_layer = layer; + if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && + layer->current.keyboard_interactive + == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { + seat->has_exclusive_layer = true; } + if (seat->focused_layer == layer) { + return; + } + seat_set_focus_surface(seat, layer->surface, true); + seat->focused_layer = layer; } void seat_set_exclusive_client(struct sway_seat *seat, diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index 5a55c186..f4c63808 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include "gesture.h" @@ -9,6 +10,7 @@ #include "sway/input/cursor.h" #include "sway/input/seat.h" #include "sway/input/tablet.h" +#include "sway/layers.h" #include "sway/output.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -365,10 +367,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, return; } - // Handle clicking a layer surface - struct wlr_layer_surface_v1 *layer; - if (surface && - (layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) { + // Handle clicking a layer surface and its popups/subsurfaces + struct wlr_layer_surface_v1 *layer = NULL; + if ((layer = toplevel_layer_surface_from_surface(surface))) { if (layer->current.keyboard_interactive) { seat_set_focus_layer(seat, layer); transaction_commit_dirty(); @@ -544,6 +545,21 @@ static void check_focus_follows_mouse(struct sway_seat *seat, if (wlr_output == NULL) { return; } + + struct wlr_surface *surface = NULL; + double sx, sy; + node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y, + &surface, &sx, &sy); + + // Focus topmost layer surface + struct wlr_layer_surface_v1 *layer = NULL; + if ((layer = toplevel_layer_surface_from_surface(surface)) && + layer->current.keyboard_interactive) { + seat_set_focus_layer(seat, layer); + transaction_commit_dirty(); + return; + } + struct sway_output *hovered_output = wlr_output->data; if (focus && hovered_output != node_get_output(focus)) { struct sway_workspace *ws = output_get_active_workspace(hovered_output); diff --git a/sway/server.c b/sway/server.c index 0cf767b7..c87e30fd 100644 --- a/sway/server.c +++ b/sway/server.c @@ -55,7 +55,7 @@ #endif #define SWAY_XDG_SHELL_VERSION 2 -#define SWAY_LAYER_SHELL_VERSION 3 +#define SWAY_LAYER_SHELL_VERSION 4 #if WLR_HAS_DRM_BACKEND static void handle_drm_lease_request(struct wl_listener *listener, void *data) { From b1b3563d5483482e19616aec0e70de970a591580 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 6 Mar 2023 17:17:05 +0100 Subject: [PATCH 19/34] Handle gamma-control-v1 set_gamma events References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4046 --- include/sway/output.h | 3 +++ include/sway/server.h | 3 +++ sway/desktop/output.c | 25 +++++++++++++++++++++++++ sway/server.c | 6 +++++- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/sway/output.h b/include/sway/output.h index f6dc6af2..50d90d25 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -57,6 +57,7 @@ struct sway_output { uint32_t refresh_nsec; int max_render_time; // In milliseconds struct wl_event_source *repaint_timer; + bool gamma_lut_changed; }; struct sway_output_non_desktop { @@ -187,6 +188,8 @@ enum wlr_direction opposite_direction(enum wlr_direction d); void handle_output_layout_change(struct wl_listener *listener, void *data); +void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data); + void handle_output_manager_apply(struct wl_listener *listener, void *data); void handle_output_manager_test(struct wl_listener *listener, void *data); diff --git a/include/sway/server.h b/include/sway/server.h index a65843ce..aaa8781b 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -91,6 +91,9 @@ struct sway_server { struct wl_listener output_manager_apply; struct wl_listener output_manager_test; + struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1; + struct wl_listener gamma_control_set_gamma; + struct { bool locked; struct wlr_session_lock_manager_v1 *manager; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 43ce2d70..09353c15 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -564,6 +565,7 @@ static int output_repaint_timer_handler(void *data) { wlr_output->frame_pending = false; if (!wlr_output->needs_frame && + !output->gamma_lut_changed && !pixman_region32_not_empty(&output->damage_ring.current)) { return 0; } @@ -578,6 +580,19 @@ static int output_repaint_timer_handler(void *data) { fullscreen_con = workspace->current.fullscreen; } + if (output->gamma_lut_changed) { + struct wlr_gamma_control_v1 *gamma_control = + wlr_gamma_control_manager_v1_get_control( + server.gamma_control_manager_v1, wlr_output); + if (!wlr_gamma_control_v1_apply(gamma_control, &wlr_output->pending)) { + return 0; + } + if (!wlr_output_test(wlr_output)) { + wlr_output_rollback(wlr_output); + wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); + } + } + pixman_region32_t frame_damage; get_frame_damage(output, &frame_damage); wlr_output_set_damage(wlr_output, &frame_damage); @@ -1076,6 +1091,16 @@ void handle_output_layout_change(struct wl_listener *listener, update_output_manager_config(server); } +void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { + struct sway_server *server = + wl_container_of(listener, server, gamma_control_set_gamma); + const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; + + struct sway_output *output = event->output->data; + output->gamma_lut_changed = true; + wlr_output_schedule_frame(output->wlr_output); +} + static void output_manager_apply(struct sway_server *server, struct wlr_output_configuration_v1 *config, bool test_only) { // TODO: perform atomic tests on the whole backend atomically diff --git a/sway/server.c b/sway/server.c index c87e30fd..9797cf60 100644 --- a/sway/server.c +++ b/sway/server.c @@ -114,7 +114,11 @@ bool server_init(struct sway_server *server) { server->data_device_manager = wlr_data_device_manager_create(server->wl_display); - wlr_gamma_control_manager_v1_create(server->wl_display); + server->gamma_control_manager_v1 = + wlr_gamma_control_manager_v1_create(server->wl_display); + server->gamma_control_set_gamma.notify = handle_gamma_control_set_gamma; + wl_signal_add(&server->gamma_control_manager_v1->events.set_gamma, + &server->gamma_control_set_gamma); server->new_output.notify = handle_new_output; wl_signal_add(&server->backend->events.new_output, &server->new_output); From f3b8c9feeed9f79fc8f06e7f1dcfaadde522ce90 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 5 Jun 2023 14:35:15 +0200 Subject: [PATCH 20/34] desktop/output: use detached output state for page-flips This avoids relying on the implicit wlr_output.pending state. --- sway/desktop/output.c | 48 +++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 09353c15..9934576c 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -458,7 +458,7 @@ static void count_surface_iterator(struct sway_output *output, } static bool scan_out_fullscreen_view(struct sway_output *output, - struct sway_view *view) { + struct wlr_output_state *pending, struct sway_view *view) { struct wlr_output *wlr_output = output->wlr_output; struct sway_workspace *workspace = output->current.active_workspace; if (!sway_assert(workspace, "Expected an active workspace")) { @@ -524,15 +524,16 @@ static bool scan_out_fullscreen_view(struct sway_output *output, return false; } - wlr_output_attach_buffer(wlr_output, &surface->buffer->base); - if (!wlr_output_test(wlr_output)) { + wlr_output_state_set_buffer(pending, &surface->buffer->base); + + if (!wlr_output_test_state(wlr_output, pending)) { return false; } wlr_presentation_surface_sampled_on_output(server.presentation, surface, wlr_output); - return wlr_output_commit(wlr_output); + return wlr_output_commit_state(wlr_output, pending); } static void get_frame_damage(struct sway_output *output, @@ -580,29 +581,30 @@ static int output_repaint_timer_handler(void *data) { fullscreen_con = workspace->current.fullscreen; } + struct wlr_output_state pending = {0}; + if (output->gamma_lut_changed) { struct wlr_gamma_control_v1 *gamma_control = wlr_gamma_control_manager_v1_get_control( server.gamma_control_manager_v1, wlr_output); - if (!wlr_gamma_control_v1_apply(gamma_control, &wlr_output->pending)) { - return 0; + if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) { + goto out; } - if (!wlr_output_test(wlr_output)) { - wlr_output_rollback(wlr_output); + if (!wlr_output_test_state(wlr_output, &pending)) { + wlr_output_state_finish(&pending); + pending = (struct wlr_output_state){0}; wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); } } - pixman_region32_t frame_damage; - get_frame_damage(output, &frame_damage); - wlr_output_set_damage(wlr_output, &frame_damage); - pixman_region32_fini(&frame_damage); + pending.committed |= WLR_OUTPUT_STATE_BUFFER; + get_frame_damage(output, &pending.damage); if (fullscreen_con && fullscreen_con->view && !debug.noscanout) { // Try to scan-out the fullscreen view static bool last_scanned_out = false; bool scanned_out = - scan_out_fullscreen_view(output, fullscreen_con->view); + scan_out_fullscreen_view(output, &pending, fullscreen_con->view); if (scanned_out && !last_scanned_out) { sway_log(SWAY_DEBUG, "Scanning out fullscreen view on %s", @@ -616,25 +618,25 @@ static int output_repaint_timer_handler(void *data) { last_scanned_out = scanned_out; if (scanned_out) { - return 0; + goto out; } } - if (!wlr_output_configure_primary_swapchain(wlr_output, NULL, &wlr_output->swapchain)) { - return false; + if (!wlr_output_configure_primary_swapchain(wlr_output, &pending, &wlr_output->swapchain)) { + goto out; } int buffer_age; struct wlr_buffer *buffer = wlr_swapchain_acquire(wlr_output->swapchain, &buffer_age); if (buffer == NULL) { - return false; + goto out; } struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass( wlr_output->renderer, buffer, NULL); if (render_pass == NULL) { wlr_buffer_unlock(buffer); - return false; + goto out; } pixman_region32_t damage; @@ -663,19 +665,21 @@ static int output_repaint_timer_handler(void *data) { if (!wlr_render_pass_submit(render_pass)) { wlr_buffer_unlock(buffer); - return false; + goto out; } - wlr_output_attach_buffer(wlr_output, buffer); + wlr_output_state_set_buffer(&pending, buffer); wlr_buffer_unlock(buffer); - if (!wlr_output_commit(wlr_output)) { - return 0; + if (!wlr_output_commit_state(wlr_output, &pending)) { + goto out; } wlr_damage_ring_rotate(&output->damage_ring); output->last_frame = now; +out: + wlr_output_state_finish(&pending); return 0; } From 65b1a6964c81efd84832c80ec9fc0273c8975225 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 9 Jun 2023 11:27:41 +0200 Subject: [PATCH 21/34] desktop/output: fix damage bitfield in wlr_output_state --- sway/desktop/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 9934576c..2bd8d6da 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -597,7 +597,7 @@ static int output_repaint_timer_handler(void *data) { } } - pending.committed |= WLR_OUTPUT_STATE_BUFFER; + pending.committed |= WLR_OUTPUT_STATE_DAMAGE; get_frame_damage(output, &pending.damage); if (fullscreen_con && fullscreen_con->view && !debug.noscanout) { From 6a1c176d14232a235ec30ce67ce87f3e549a6121 Mon Sep 17 00:00:00 2001 From: Shaked Flur Date: Fri, 9 Jun 2023 11:23:05 +0100 Subject: [PATCH 22/34] man: add --inhibited and --no-repeat to bindsym and bindcode usage --- sway/sway.5.scd | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 25082c41..78d7d231 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -389,8 +389,8 @@ runtime. for_window move container to output *bindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \ -[--to-code] [--input-device=] [--no-warn] [--no-repeat] [Group<1-4>+] \ - +[--to-code] [--input-device=] [--no-warn] [--no-repeat] [--inhibited] \ +[Group<1-4>+] Binds _key combo_ to execute the sway command _command_ when pressed. You may use XKB key names here (*wev*(1) is a good tool for discovering these). With the flag _--release_, the command is executed when the key combo is @@ -454,7 +454,8 @@ runtime. ``` *bindcode* [--whole-window] [--border] [--exclude-titlebar] [--release] \ -[--locked] [--input-device=] [--no-warn] [Group<1-4>+] +[--locked] [--input-device=] [--no-warn] [--no-repeat] [--inhibited] \ +[Group<1-4>+] is also available for binding with key/button codes instead of key/button names. *bindswitch* [--locked] [--no-warn] [--reload] : From be14cd96cd81270b3a34742f9a25fe21adf4f595 Mon Sep 17 00:00:00 2001 From: 33KK Date: Sun, 11 Jun 2023 11:36:30 +0200 Subject: [PATCH 23/34] Fix `bindsym --to-code` not respecting input configs Fixes #7535 --- sway/input/input-manager.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 1115ba5e..5f7dfb42 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -532,6 +532,18 @@ static void retranslate_keysyms(struct input_config *input_config) { return; } } + + for (int i = 0; i < config->input_type_configs->length; ++i) { + struct input_config *ic = config->input_type_configs->items[i]; + if (ic->xkb_layout || ic->xkb_file) { + // this is the first config with xkb_layout or xkb_file + if (ic->identifier == input_config->identifier) { + translate_keysyms(ic); + } + + return; + } + } } static void input_manager_configure_input( From 59c27c94d3981ae65136942288dbf0e9d28b3a24 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 11 Jun 2023 10:11:38 -0400 Subject: [PATCH 24/34] gamma_control_v1: Reset dirty flag --- sway/desktop/output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 2bd8d6da..6b65768d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -584,6 +584,7 @@ static int output_repaint_timer_handler(void *data) { struct wlr_output_state pending = {0}; if (output->gamma_lut_changed) { + output->gamma_lut_changed = false; struct wlr_gamma_control_v1 *gamma_control = wlr_gamma_control_manager_v1_get_control( server.gamma_control_manager_v1, wlr_output); From 8b4b65d66552d782d2c38a17756baf928b90e670 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Wed, 14 Jun 2023 08:45:58 +0200 Subject: [PATCH 25/34] gamma_control_v1: handle destroyed output In case a display is unplugged, the sway output may be removed from the userdata before the gamma_control can be reset. In this case we can't schedule a commit on the output, simply return within the function. backtrace full: #0 handle_gamma_control_set_gamma (listener=0x4856a8 , data=0x7ffce1ed59c0) at ../sway/desktop/output.c:1105 server = 0x485440 event = 0x7ffce1ed59c0 output = 0x0 #1 0x00007f430d1dca0c in wl_signal_emit_mutable () from /nix/store/ky1g6ylzr2m4bq8fy0gzrnqmjr6948k5-wayland-1.22.0/lib/libwayland-server.so.0 No symbol table info available. #2 0x00007f430d142370 in gamma_control_destroy (gamma_control=0x29eb9b0) at ../types/wlr_gamma_control_v1.c:37 manager = 0x27e33e0 output = 0x2a10770 event = {output = 0x2a10770, control = 0x0} #3 0x00007f430d14239b in gamma_control_handle_output_destroy (listener=, data=) at ../types/wlr_gamma_control_v1.c:59 gamma_control = #4 0x00007f430d1dca0c in wl_signal_emit_mutable () from /nix/store/ky1g6ylzr2m4bq8fy0gzrnqmjr6948k5-wayland-1.22.0/lib/libwayland-server.so.0 No symbol table info available. #5 0x00007f430d12a0e0 in wlr_output_destroy (output=output@entry=0x2a10770) at ../types/output/output.c:384 cursor = tmp_cursor = layer = tmp_layer = #6 0x00007f430d114ecf in disconnect_drm_connector (conn=conn@entry=0x2a10770) at ../backend/drm/drm.c:1757 __PRETTY_FUNCTION__ = "disconnect_drm_connector" #7 0x00007f430d117078 in scan_drm_connectors (drm=drm@entry=0x1eebab0, event=event@entry=0x7ffce1ed5c1c) at ../backend/drm/drm.c:1597 c = wlr_conn = 0x2a10770 drm_conn = 0x2e760d0 conn_id = index = 4 i = 4 res = 0x2e761f0 seen_len = 5 seen = {true, true, true, true, true, false} new_outputs_len = 0 new_outputs = 0x7ffce1ed5ab0 conn = tmp_conn = index = #8 0x00007f430d113425 in handle_dev_change (listener=0x1eebbb0, data=0x7ffce1ed5c18) at ../backend/drm/backend.c:157 drm = 0x1eebab0 change = 0x7ffce1ed5c18 #9 0x00007f430d1dca0c in wl_signal_emit_mutable () from /nix/store/ky1g6ylzr2m4bq8fy0gzrnqmjr6948k5-wayland-1.22.0/lib/libwayland-server.so.0 No symbol table info available. #10 0x00007f430d111696 in handle_udev_event (fd=, mask=, data=) at ../backend/session/session.c:213 event = {type = WLR_DEVICE_HOTPLUG, {hotplug = {connector_id = 0, prop_id = 0}}} devnum = dev = 0x1ed9460 session = udev_dev = 0x2e70db0 sysname = 0x2e73c60 "card0" devnode = action = 0x7f430d6677b5 "change" seat = __PRETTY_FUNCTION__ = "handle_udev_event" #11 0x00007f430d1de8e2 in wl_event_loop_dispatch () from /nix/store/ky1g6ylzr2m4bq8fy0gzrnqmjr6948k5-wayland-1.22.0/lib/libwayland-server.so.0 No symbol table info available. #12 0x00007f430d1dc445 in wl_display_run () from /nix/store/ky1g6ylzr2m4bq8fy0gzrnqmjr6948k5-wayland-1.22.0/lib/libwayland-server.so.0 No symbol table info available. #13 0x000000000041daa5 in server_run (server=server@entry=0x485440 ) at ../sway/server.c:338 No locals. #14 0x000000000041cf4d in main (argc=, argv=0x7ffce1ed5fe8) at ../sway/main.c:415 verbose = false debug = false validate = false allow_unsupported_gpu = false config_path = 0x0 c = where event->output->data is NULL: (gdb) p event->output->data $5 = (void *) 0x0 --- sway/desktop/output.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 6b65768d..476bfd25 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -1102,6 +1102,11 @@ void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) { const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data; struct sway_output *output = event->output->data; + + if(!output) { + return; + } + output->gamma_lut_changed = true; wlr_output_schedule_frame(output->wlr_output); } From c08762901e9840d8dca008dcc8d0b5602602fd0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cezary=20Dro=C5=BCak?= Date: Fri, 16 Jun 2023 11:28:30 +0200 Subject: [PATCH 26/34] input/libinput: add scroll_button_lock method Closes https://github.com/swaywm/sway/issues/6987 Co-authored-by: JJGadgets Co-authored-by: DeltaWhy --- include/sway/commands.h | 1 + include/sway/config.h | 1 + sway/commands/input.c | 1 + sway/commands/input/scroll_button_lock.c | 26 ++++++++++++++++++++++++ sway/config/input.c | 4 ++++ sway/input/libinput.c | 15 ++++++++++++++ sway/ipc-json.c | 11 ++++++++++ sway/meson.build | 1 + sway/sway-input.5.scd | 3 +++ sway/sway-ipc.7.scd | 3 +++ 10 files changed, 66 insertions(+) create mode 100644 sway/commands/input/scroll_button_lock.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 3212c2cf..27058587 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -266,6 +266,7 @@ sway_cmd input_cmd_scroll_factor; sway_cmd input_cmd_repeat_delay; sway_cmd input_cmd_repeat_rate; sway_cmd input_cmd_scroll_button; +sway_cmd input_cmd_scroll_button_lock; sway_cmd input_cmd_scroll_method; sway_cmd input_cmd_tap; sway_cmd input_cmd_tap_button_map; diff --git a/include/sway/config.h b/include/sway/config.h index aa58da53..f9da1967 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -161,6 +161,7 @@ struct input_config { int repeat_delay; int repeat_rate; int scroll_button; + int scroll_button_lock; int scroll_method; int send_events; int tap; diff --git a/sway/commands/input.c b/sway/commands/input.c index 3075b5f4..306c40f7 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -27,6 +27,7 @@ static const struct cmd_handler input_handlers[] = { { "repeat_rate", input_cmd_repeat_rate }, { "rotation_angle", input_cmd_rotation_angle }, { "scroll_button", input_cmd_scroll_button }, + { "scroll_button_lock", input_cmd_scroll_button_lock }, { "scroll_factor", input_cmd_scroll_factor }, { "scroll_method", input_cmd_scroll_method }, { "tap", input_cmd_tap }, diff --git a/sway/commands/input/scroll_button_lock.c b/sway/commands/input/scroll_button_lock.c new file mode 100644 index 00000000..f96b6514 --- /dev/null +++ b/sway/commands/input/scroll_button_lock.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/input-manager.h" +#include "util.h" + +struct cmd_results *input_cmd_scroll_button_lock(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "scroll_button_lock", EXPECTED_AT_LEAST, 1))) { + return error; + } + struct input_config *ic = config->handler_context.input_config; + if (!ic) { + return cmd_results_new(CMD_FAILURE, "No input device defined."); + } + + if (parse_boolean(argv[0], true)) { + ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED; + } else { + ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config/input.c b/sway/config/input.c index 2ee165c9..44c2be28 100644 --- a/sway/config/input.c +++ b/sway/config/input.c @@ -35,6 +35,7 @@ struct input_config *new_input_config(const char* identifier) { input->pointer_accel = FLT_MIN; input->scroll_factor = FLT_MIN; input->scroll_button = INT_MIN; + input->scroll_button_lock = INT_MIN; input->scroll_method = INT_MIN; input->left_handed = INT_MIN; input->repeat_delay = INT_MIN; @@ -96,6 +97,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { if (src->scroll_button != INT_MIN) { dst->scroll_button = src->scroll_button; } + if (src->scroll_button_lock != INT_MIN) { + dst->scroll_button_lock = src->scroll_button_lock; + } if (src->send_events != INT_MIN) { dst->send_events = src->send_events; } diff --git a/sway/input/libinput.c b/sway/input/libinput.c index dd4fc0be..43875634 100644 --- a/sway/input/libinput.c +++ b/sway/input/libinput.c @@ -166,6 +166,18 @@ static bool set_scroll_button(struct libinput_device *dev, uint32_t button) { return true; } +static bool set_scroll_button_lock(struct libinput_device *dev, + enum libinput_config_scroll_button_lock_state lock) { + uint32_t scroll = libinput_device_config_scroll_get_methods(dev); + if ((scroll & ~LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0 || + libinput_device_config_scroll_get_button_lock(dev) == lock) { + return false; + } + sway_log(SWAY_DEBUG, "scroll_set_button_lock(%" PRIu32 ")", lock); + log_status(libinput_device_config_scroll_set_button_lock(dev, lock)); + return true; +} + static bool set_dwt(struct libinput_device *device, bool dwt) { if (!libinput_device_config_dwt_is_available(device) || libinput_device_config_dwt_get_enabled(device) == dwt) { @@ -276,6 +288,9 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device if (ic->scroll_button != INT_MIN) { changed |= set_scroll_button(device, ic->scroll_button); } + if (ic->scroll_button_lock != INT_MIN) { + changed |= set_scroll_button_lock(device, ic->scroll_button_lock); + } if (ic->dwt != INT_MIN) { changed |= set_dwt(device, ic->dwt); } diff --git a/sway/ipc-json.c b/sway/ipc-json.c index c7cbea01..58356d4e 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -1019,6 +1019,17 @@ static json_object *describe_libinput_device(struct libinput_device *device) { uint32_t button = libinput_device_config_scroll_get_button(device); json_object_object_add(object, "scroll_button", json_object_new_int(button)); + const char *lock = "unknown"; + switch (libinput_device_config_scroll_get_button_lock(device)) { + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED: + lock = "enabled"; + break; + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED: + lock = "disabled"; + break; + } + json_object_object_add(object, "scroll_button_lock", + json_object_new_string(lock)); } } diff --git a/sway/meson.build b/sway/meson.build index c6a27434..bc193bf9 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -171,6 +171,7 @@ sway_sources = files( 'commands/input/repeat_delay.c', 'commands/input/repeat_rate.c', 'commands/input/scroll_button.c', + 'commands/input/scroll_button_lock.c', 'commands/input/scroll_factor.c', 'commands/input/scroll_method.c', 'commands/input/tap.c', diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 1662d55a..082b68c2 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -185,6 +185,9 @@ The following commands may only be used in the configuration file. debug-events*, or as a x11 mouse button (button[1-3,8,9]). If set to _disable_, it disables the scroll_method on_button_down. +*input* scroll_button_lock enabled|disabled + Enables or disables scroll button lock for specified input device. + *input* scroll_factor Changes the scroll factor for the specified input device. Scroll speed will be scaled by the given value, which must be non-negative. diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index 42aaaab6..f4a5ccff 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -1195,6 +1195,9 @@ following properties will be included for devices that support them: : int : The scroll button to use when _scroll_method_ is _on_button_down_. This will be given as an input event code +|- scroll_button_lock +: string +: Whether scroll button lock is enabled. It can be _enabled_ or _disabled_ |- dwt : string : Whether disable-while-typing is enabled. It can be _enabled_ or _disabled_ From 876687000d4de503cdb01fcd8fa14f1b05dd9a1e Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 19 Jun 2023 13:05:12 -0400 Subject: [PATCH 27/34] render: Use wlroots scale filter --- meson.build | 2 -- sway/desktop/render.c | 33 +++++++-------------------------- sway/meson.build | 1 - 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/meson.build b/meson.build index 559ee962..eeee39cd 100644 --- a/meson.build +++ b/meson.build @@ -48,7 +48,6 @@ wlroots = dependency('wlroots', version: wlroots_version) wlroots_features = { 'xwayland': false, 'libinput_backend': false, - 'gles2_renderer': false, 'session': false, } foreach name, _ : wlroots_features @@ -75,7 +74,6 @@ pango = dependency('pango') pangocairo = dependency('pangocairo') gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) pixman = dependency('pixman-1') -glesv2 = wlroots_features['gles2_renderer'] ? dependency('glesv2') : null_dep libevdev = dependency('libevdev') libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep xcb = dependency('xcb', required: get_option('xwayland')) diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 21014042..f08e2c6c 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -27,10 +27,6 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" -#if WLR_HAS_GLES2_RENDERER -#include -#endif - struct render_data { struct render_context *ctx; const pixman_region32_t *damage; @@ -71,30 +67,15 @@ static int scale_length(int length, int offset, float scale) { return roundf((offset + length) * scale) - roundf(offset * scale); } -static void set_scale_filter(struct wlr_output *wlr_output, - struct wlr_texture *texture, enum scale_filter_mode scale_filter) { -#if WLR_HAS_GLES2_RENDERER - if (!wlr_texture_is_gles2(texture)) { - return; - } - - struct wlr_gles2_texture_attribs attribs; - wlr_gles2_texture_get_attribs(texture, &attribs); - - glBindTexture(attribs.target, attribs.tex); - - switch (scale_filter) { +static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output) { + switch (output->scale_filter) { case SCALE_FILTER_LINEAR: - glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - break; + return WLR_SCALE_FILTER_BILINEAR; case SCALE_FILTER_NEAREST: - glTexParameteri(attribs.target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - break; - case SCALE_FILTER_DEFAULT: - case SCALE_FILTER_SMART: - assert(false); // unreachable + return WLR_SCALE_FILTER_NEAREST; + default: + abort(); // unreachable } -#endif } static void render_texture(struct render_context *ctx, struct wlr_texture *texture, @@ -128,7 +109,6 @@ static void render_texture(struct render_context *ctx, struct wlr_texture *textu transform_output_damage(&damage, output->wlr_output); transform = wlr_output_transform_compose(transform, output->wlr_output->transform); - set_scale_filter(output->wlr_output, texture, output->scale_filter); wlr_render_pass_add_texture(ctx->pass, &(struct wlr_render_texture_options) { .texture = texture, .src_box = src_box, @@ -136,6 +116,7 @@ static void render_texture(struct render_context *ctx, struct wlr_texture *textu .transform = transform, .alpha = &alpha, .clip = &damage, + .filter_mode = get_scale_filter(output), }); damage_finish: diff --git a/sway/meson.build b/sway/meson.build index bc193bf9..3abd778d 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -223,7 +223,6 @@ sway_deps = [ math, pango, pcre2, - glesv2, pixman, threads, wayland_server, From 6f1a3b6652b94b568b32f2875e5dc3c61a14d71c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 15 Jun 2023 18:43:09 +0200 Subject: [PATCH 28/34] Use wlr_cursor_set_xcursor() wlr_xcursor_manager_set_cursor_image() is deprecated. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4170 --- sway/input/cursor.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index d8ec11ac..684bb1d3 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -1070,8 +1070,7 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image, if (!image) { wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); } else if (!current_image || strcmp(current_image, image) != 0) { - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image, - cursor->cursor); + wlr_cursor_set_xcursor(cursor->cursor, cursor->xcursor_manager, image); } } From 5411ed4ef0fa84f0622149bbe2305910be9f0b67 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 15 Jun 2023 18:44:40 +0200 Subject: [PATCH 29/34] Use wlr_cursor_unset_image() A bit cleaner. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4209 --- sway/input/cursor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 684bb1d3..abc6c554 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -252,7 +252,7 @@ void cursor_update_image(struct sway_cursor *cursor, } static void cursor_hide(struct sway_cursor *cursor) { - wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); + wlr_cursor_unset_image(cursor->cursor); cursor->hidden = true; wlr_seat_pointer_notify_clear_focus(cursor->seat->wlr_seat); } @@ -1068,7 +1068,7 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image, } if (!image) { - wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); + wlr_cursor_unset_image(cursor->cursor); } else if (!current_image || strcmp(current_image, image) != 0) { wlr_cursor_set_xcursor(cursor->cursor, cursor->xcursor_manager, image); } From b762f455d942e81e076a4a4d475fb9926372da16 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 19 Jun 2023 21:16:23 +0200 Subject: [PATCH 30/34] idle-inhibit-v1: simplify with server global We only have a single running server, no need to keep track of multiple server instances. Also no need to support multiple idle inhibit managers. --- include/sway/desktop/idle_inhibit_v1.h | 11 ++---- include/sway/server.h | 3 +- sway/commands/inhibit_idle.c | 2 +- sway/desktop/idle_inhibit_v1.c | 46 +++++++++++--------------- sway/desktop/transaction.c | 2 +- sway/server.c | 3 +- 6 files changed, 28 insertions(+), 39 deletions(-) diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h index 58d54c68..6dda1af9 100644 --- a/include/sway/desktop/idle_inhibit_v1.h +++ b/include/sway/desktop/idle_inhibit_v1.h @@ -2,7 +2,6 @@ #define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H #include #include -#include "sway/server.h" enum sway_idle_inhibit_mode { INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible) @@ -16,12 +15,9 @@ struct sway_idle_inhibit_manager_v1 { struct wlr_idle_inhibit_manager_v1 *wlr_manager; struct wl_listener new_idle_inhibitor_v1; struct wl_list inhibitors; - - struct wlr_idle *idle; }; struct sway_idle_inhibitor_v1 { - struct sway_idle_inhibit_manager_v1 *manager; struct wlr_idle_inhibitor_v1 *wlr_inhibitor; struct sway_view *view; enum sway_idle_inhibit_mode mode; @@ -33,8 +29,7 @@ struct sway_idle_inhibitor_v1 { bool sway_idle_inhibit_v1_is_active( struct sway_idle_inhibitor_v1 *inhibitor); -void sway_idle_inhibit_v1_check_active( - struct sway_idle_inhibit_manager_v1 *manager); +void sway_idle_inhibit_v1_check_active(void); void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, enum sway_idle_inhibit_mode mode); @@ -48,6 +43,6 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi void sway_idle_inhibit_v1_user_inhibitor_destroy( struct sway_idle_inhibitor_v1 *inhibitor); -struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( - struct wl_display *wl_display, struct wlr_idle *idle); +bool sway_idle_inhibit_manager_v1_init(void); + #endif diff --git a/include/sway/server.h b/include/sway/server.h index aaa8781b..0e4ec2be 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -21,6 +21,7 @@ #include #include "config.h" #include "list.h" +#include "sway/desktop/idle_inhibit_v1.h" #if HAVE_XWAYLAND #include "sway/xwayland.h" #endif @@ -53,7 +54,7 @@ struct sway_server { struct wlr_idle *idle; struct wlr_idle_notifier_v1 *idle_notifier_v1; - struct sway_idle_inhibit_manager_v1 *idle_inhibit_manager_v1; + struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1; struct wlr_layer_shell_v1 *layer_shell; struct wl_listener layer_shell_surface; diff --git a/sway/commands/inhibit_idle.c b/sway/commands/inhibit_idle.c index aebc2bf9..6125736a 100644 --- a/sway/commands/inhibit_idle.c +++ b/sway/commands/inhibit_idle.c @@ -41,7 +41,7 @@ struct cmd_results *cmd_inhibit_idle(int argc, char **argv) { sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor); } else { inhibitor->mode = mode; - sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); + sway_idle_inhibit_v1_check_active(); } } else if (!clear) { sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode); diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index 3a4d0b87..1fa058e3 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -12,7 +12,7 @@ static void destroy_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor) { wl_list_remove(&inhibitor->link); wl_list_remove(&inhibitor->destroy.link); - sway_idle_inhibit_v1_check_active(inhibitor->manager); + sway_idle_inhibit_v1_check_active(); free(inhibitor); } @@ -35,7 +35,6 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { return; } - inhibitor->manager = manager; inhibitor->mode = INHIBIT_IDLE_APPLICATION; inhibitor->wlr_inhibitor = wlr_inhibitor; wl_list_insert(&manager->inhibitors, &inhibitor->link); @@ -43,33 +42,34 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { inhibitor->destroy.notify = handle_destroy; wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy); - sway_idle_inhibit_v1_check_active(manager); + sway_idle_inhibit_v1_check_active(); } void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, enum sway_idle_inhibit_mode mode) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; + struct sway_idle_inhibitor_v1 *inhibitor = calloc(1, sizeof(struct sway_idle_inhibitor_v1)); if (!inhibitor) { return; } - inhibitor->manager = server.idle_inhibit_manager_v1; inhibitor->mode = mode; inhibitor->view = view; - wl_list_insert(&inhibitor->manager->inhibitors, &inhibitor->link); + wl_list_insert(&manager->inhibitors, &inhibitor->link); inhibitor->destroy.notify = handle_destroy; wl_signal_add(&view->events.unmap, &inhibitor->destroy); - sway_idle_inhibit_v1_check_active(inhibitor->manager); + sway_idle_inhibit_v1_check_active(); } struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( struct sway_view *view) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; struct sway_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, - link) { + wl_list_for_each(inhibitor, &manager->inhibitors, link) { if (inhibitor->mode != INHIBIT_IDLE_APPLICATION && inhibitor->view == view) { return inhibitor; @@ -80,9 +80,9 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_view( struct sway_view *view) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; struct sway_idle_inhibitor_v1 *inhibitor; - wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, - link) { + wl_list_for_each(inhibitor, &manager->inhibitors, link) { if (inhibitor->mode == INHIBIT_IDLE_APPLICATION && view_from_wlr_surface(inhibitor->wlr_inhibitor->surface) == view) { return inhibitor; @@ -131,8 +131,8 @@ bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { return false; } -void sway_idle_inhibit_v1_check_active( - struct sway_idle_inhibit_manager_v1 *manager) { +void sway_idle_inhibit_v1_check_active(void) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; struct sway_idle_inhibitor_v1 *inhibitor; bool inhibited = false; wl_list_for_each(inhibitor, &manager->inhibitors, link) { @@ -140,28 +140,22 @@ void sway_idle_inhibit_v1_check_active( break; } } - wlr_idle_set_enabled(manager->idle, NULL, !inhibited); + wlr_idle_set_enabled(server.idle, NULL, !inhibited); wlr_idle_notifier_v1_set_inhibited(server.idle_notifier_v1, inhibited); } -struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( - struct wl_display *wl_display, struct wlr_idle *idle) { - struct sway_idle_inhibit_manager_v1 *manager = - calloc(1, sizeof(struct sway_idle_inhibit_manager_v1)); - if (!manager) { - return NULL; +bool sway_idle_inhibit_manager_v1_init(void) { + struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; + + manager->wlr_manager = wlr_idle_inhibit_v1_create(server.wl_display); + if (!manager->wlr_manager) { + return false; } - manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display); - if (!manager->wlr_manager) { - free(manager); - return NULL; - } - manager->idle = idle; wl_signal_add(&manager->wlr_manager->events.new_inhibitor, &manager->new_idle_inhibitor_v1); manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1; wl_list_init(&manager->inhibitors); - return manager; + return true; } diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index f5a3a053..6947e138 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -344,7 +344,7 @@ static void transaction_progress(void) { server.queued_transaction = NULL; if (!server.pending_transaction) { - sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); + sway_idle_inhibit_v1_check_active(); return; } diff --git a/sway/server.c b/sway/server.c index 9797cf60..cc4719d7 100644 --- a/sway/server.c +++ b/sway/server.c @@ -130,8 +130,7 @@ bool server_init(struct sway_server *server) { server->idle = wlr_idle_create(server->wl_display); server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); - server->idle_inhibit_manager_v1 = - sway_idle_inhibit_manager_v1_create(server->wl_display, server->idle); + sway_idle_inhibit_manager_v1_init(); server->layer_shell = wlr_layer_shell_v1_create(server->wl_display, SWAY_LAYER_SHELL_VERSION); From 7fbd9fbf2825f1c41468ac996aced9ba4b152992 Mon Sep 17 00:00:00 2001 From: Hodong <111117126+hodong-kim@users.noreply.github.com> Date: Sat, 24 Jun 2023 00:54:08 +0900 Subject: [PATCH 31/34] swaybar: remove the argument of StatusNotifierHostRegistered According to https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierWatcher/ there is no argument for the StatusNotifierHostRegistered signal. --- swaybar/tray/watcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swaybar/tray/watcher.c b/swaybar/tray/watcher.c index 551e1d12..2458a8c2 100644 --- a/swaybar/tray/watcher.c +++ b/swaybar/tray/watcher.c @@ -106,7 +106,7 @@ static int register_host(sd_bus_message *msg, void *data, sd_bus_error *error) { sway_log(SWAY_DEBUG, "Registering Status Notifier Host '%s'", service); list_add(watcher->hosts, strdup(service)); sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface, - "StatusNotifierHostRegistered", "s", service); + "StatusNotifierHostRegistered", ""); } else { sway_log(SWAY_DEBUG, "Status Notifier Host '%s' already registered", service); } From 974a8629a8f0f403028332543e4bd31d98f611c1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 23 Jun 2023 12:28:15 +0200 Subject: [PATCH 32/34] Use "default" XCursor instead of "left_ptr" "left_ptr" is the legacy XCursor name. "default" is the cursor spec name. --- sway/input/cursor.c | 4 ++-- sway/input/seat.c | 6 +++--- swaybar/input.c | 2 +- swaynag/swaynag.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index abc6c554..7a4dd19f 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -236,7 +236,7 @@ void cursor_update_image(struct sway_cursor *cursor, // Try a node's resize edge enum wlr_edges edge = find_resize_edge(node->sway_container, NULL, cursor); if (edge == WLR_EDGE_NONE) { - cursor_set_image(cursor, "left_ptr", NULL); + cursor_set_image(cursor, "default", NULL); } else if (container_is_floating(node->sway_container)) { cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL); } else { @@ -247,7 +247,7 @@ void cursor_update_image(struct sway_cursor *cursor, } } } else { - cursor_set_image(cursor, "left_ptr", NULL); + cursor_set_image(cursor, "default", NULL); } } diff --git a/sway/input/seat.c b/sway/input/seat.c index fdd21057..82f4eb5f 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -671,7 +671,7 @@ static void seat_update_capabilities(struct sway_seat *seat) { } else { wlr_seat_set_capabilities(seat->wlr_seat, caps); if ((previous_caps & WL_SEAT_CAPABILITY_POINTER) == 0) { - cursor_set_image(seat->cursor, "left_ptr", NULL); + cursor_set_image(seat->cursor, "default", NULL); } } } @@ -1039,7 +1039,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { wlr_xcursor_manager_load(server.xwayland.xcursor_manager, 1); struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( - server.xwayland.xcursor_manager, "left_ptr", 1); + server.xwayland.xcursor_manager, "default", 1); if (xcursor != NULL) { struct wlr_xcursor_image *image = xcursor->images[0]; wlr_xwayland_set_cursor( @@ -1082,7 +1082,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { // Reset the cursor so that we apply it to outputs that just appeared cursor_set_image(seat->cursor, NULL, NULL); - cursor_set_image(seat->cursor, "left_ptr", NULL); + cursor_set_image(seat->cursor, "default", NULL); wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, seat->cursor->cursor->y); } diff --git a/swaybar/input.c b/swaybar/input.c index 8eccf542..f8f0672e 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -82,7 +82,7 @@ void update_cursor(struct swaybar_seat *seat) { pointer->cursor_theme = wl_cursor_theme_load( cursor_theme, cursor_size * scale, seat->bar->shm); struct wl_cursor *cursor; - cursor = wl_cursor_theme_get_cursor(pointer->cursor_theme, "left_ptr"); + cursor = wl_cursor_theme_get_cursor(pointer->cursor_theme, "default"); pointer->cursor_image = cursor->images[0]; wl_surface_set_buffer_scale(pointer->cursor_surface, scale); wl_surface_attach(pointer->cursor_surface, diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c index 08e26127..1b114e28 100644 --- a/swaynag/swaynag.c +++ b/swaynag/swaynag.c @@ -154,7 +154,7 @@ static void update_cursor(struct swaynag_seat *seat) { pointer->cursor_theme = wl_cursor_theme_load( cursor_theme, cursor_size * swaynag->scale, swaynag->shm); struct wl_cursor *cursor = - wl_cursor_theme_get_cursor(pointer->cursor_theme, "left_ptr"); + wl_cursor_theme_get_cursor(pointer->cursor_theme, "default"); pointer->cursor_image = cursor->images[0]; wl_surface_set_buffer_scale(pointer->cursor_surface, swaynag->scale); From 20c91335f6ba515e43b444fafd52b822bd460eda Mon Sep 17 00:00:00 2001 From: Mark Bolhuis Date: Mon, 26 Jun 2023 21:43:13 +0100 Subject: [PATCH 33/34] input: Move wlr_pointer_gestures_v1 to sway_input_manager On multi-seat configurations a zwp_pointer_gestures_v1 global was created for every seat. Instead, create the global once in the input manager, to be shared across all seats. --- include/sway/input/cursor.h | 1 - include/sway/input/input-manager.h | 1 + sway/input/cursor.c | 3 --- sway/input/input-manager.c | 2 ++ sway/input/seatop_default.c | 16 ++++++++-------- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index c7da8829..1636588a 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -35,7 +35,6 @@ struct sway_cursor { pixman_region32_t confine; // invalid if active_constraint == NULL bool active_confine_requires_warp; - struct wlr_pointer_gestures_v1 *pointer_gestures; struct wl_listener hold_begin; struct wl_listener hold_end; struct wl_listener pinch_begin; diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index c9bd08f0..b651e3dd 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -25,6 +25,7 @@ struct sway_input_manager { struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit; struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; struct wlr_virtual_pointer_manager_v1 *virtual_pointer; + struct wlr_pointer_gestures_v1 *pointer_gestures; struct wl_listener new_input; struct wl_listener inhibit_activate; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 7a4dd19f..f970e6a2 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -1154,9 +1154,6 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { wl_list_init(&cursor->image_surface_destroy.link); cursor->image_surface_destroy.notify = handle_image_surface_destroy; - // gesture events - cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display); - wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin); cursor->hold_begin.notify = handle_pointer_hold_begin; wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end); diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 5f7dfb42..db82bb4c 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -495,6 +495,8 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) { wl_signal_add(&input->keyboard_shortcuts_inhibit->events.new_inhibitor, &input->keyboard_shortcuts_inhibit_new_inhibitor); + input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display); + return input; } diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index f4c63808..1dce6dae 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -949,7 +949,7 @@ static void handle_hold_begin(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_hold_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); } } @@ -961,7 +961,7 @@ static void handle_hold_end(struct sway_seat *seat, if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) { struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_hold_end( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); return; } @@ -994,7 +994,7 @@ static void handle_pinch_begin(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_pinch_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); } } @@ -1010,7 +1010,7 @@ static void handle_pinch_update(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_pinch_update( - cursor->pointer_gestures, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->dx, event->dy, event->scale, event->rotation); @@ -1024,7 +1024,7 @@ static void handle_pinch_end(struct sway_seat *seat, if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) { struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_pinch_end( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); return; } @@ -1057,7 +1057,7 @@ static void handle_swipe_begin(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_swipe_begin( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); } } @@ -1074,7 +1074,7 @@ static void handle_swipe_update(struct sway_seat *seat, // ... otherwise forward to client struct sway_cursor *cursor = seat->cursor; wlr_pointer_gestures_v1_send_swipe_update( - cursor->pointer_gestures, cursor->seat->wlr_seat, + server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->dx, event->dy); } } @@ -1085,7 +1085,7 @@ static void handle_swipe_end(struct sway_seat *seat, struct seatop_default_event *seatop = seat->seatop_data; if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) { struct sway_cursor *cursor = seat->cursor; - wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures, + wlr_pointer_gestures_v1_send_swipe_end(server.input->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); return; } From 20ffe545bab3fe518d8d1be00949943f7d39cfe0 Mon Sep 17 00:00:00 2001 From: llyyr Date: Tue, 27 Jun 2023 22:50:25 +0530 Subject: [PATCH 34/34] swaybar: don't set current workspace as not visible When `wrap_scroll yes` is configured and there's only one workspace open, swaybar will mark it as not visible if the user scrolls on it and eventually incorrectly fail the `active->visible` assert. Fix this by making sure that new and current workspace aren't the same. --- swaybar/input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swaybar/input.c b/swaybar/input.c index f8f0672e..358c69cb 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -207,7 +207,7 @@ static void workspace_next(struct swaybar *bar, struct swaybar_output *output, } } - if (new) { + if (new && new != active) { ipc_send_workspace_command(bar, new->name); // Since we're asking Sway to switch to 'new', it should become visible.