mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-03-16 05:34:23 -04:00
scene: avoid redundant wl_surface.enter/leave events
Currently we send wl_surface.enter/leave when a surface is hidden and shown again on the same output. In practice, this happens very often since compositors like river and sway enable and disable the scene nodes of surfaces as part of their atomic transaction strategy involving rendering saved buffers while waiting for clients to submit new buffers of the desired size. The new strategy documented in the new comments avoids sending redundant events in this case.
This commit is contained in:
parent
736c0f3f25
commit
39e918edc8
2 changed files with 31 additions and 29 deletions
|
|
@ -131,8 +131,6 @@ struct wlr_scene_surface {
|
|||
struct wlr_addon addon;
|
||||
|
||||
struct wl_listener outputs_update;
|
||||
struct wl_listener output_enter;
|
||||
struct wl_listener output_leave;
|
||||
struct wl_listener output_sample;
|
||||
struct wl_listener frame_done;
|
||||
struct wl_listener surface_destroy;
|
||||
|
|
|
|||
|
|
@ -94,14 +94,44 @@ static void handle_scene_buffer_outputs_update(
|
|||
struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, outputs_update);
|
||||
struct wlr_scene_outputs_update_event *event = data;
|
||||
struct wlr_scene *scene = scene_node_get_root(&surface->buffer->node);
|
||||
|
||||
// If the surface is no longer visible on any output, keep the last sent
|
||||
// preferred configuration to avoid unnecessary redraws
|
||||
if (wl_list_empty(&surface->surface->current_outputs)) {
|
||||
if (event->size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// To avoid sending redundant leave/enter events when a surface is hidden and then shown
|
||||
// without moving to a different output the following policy is implemented:
|
||||
//
|
||||
// 1. When a surface transitions from being visible on >0 outputs to being visible on 0 outputs
|
||||
// don't send any leave events.
|
||||
//
|
||||
// 2. When a surface transitions from being visible on 0 outputs to being visible on >0 outputs
|
||||
// send leave events for all entered outputs on which the surface is no longer visible as
|
||||
// well as enter events for any outputs not already entered.
|
||||
struct wlr_surface_output *entered_output;
|
||||
wl_list_for_each(entered_output, &surface->surface->current_outputs, link) {
|
||||
bool active = false;
|
||||
for (size_t i = 0; i < event->size; i++) {
|
||||
if (entered_output->output == event->active[i]->output) {
|
||||
active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!active) {
|
||||
wlr_surface_send_leave(surface->surface, entered_output->output);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < event->size; i++) {
|
||||
// This function internally checks if an enter event was already sent for the output
|
||||
// to avoid sending redundant events.
|
||||
wlr_surface_send_enter(surface->surface, event->active[i]->output);
|
||||
}
|
||||
|
||||
double scale = get_surface_preferred_buffer_scale(surface->surface);
|
||||
wlr_fractional_scale_v1_notify_scale(surface->surface, scale);
|
||||
wlr_surface_set_preferred_buffer_scale(surface->surface, ceil(scale));
|
||||
|
|
@ -114,24 +144,6 @@ static void handle_scene_buffer_outputs_update(
|
|||
}
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_output_enter(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, output_enter);
|
||||
struct wlr_scene_output *output = data;
|
||||
|
||||
wlr_surface_send_enter(surface->surface, output->output);
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_output_leave(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene_surface *surface =
|
||||
wl_container_of(listener, surface, output_leave);
|
||||
struct wlr_scene_output *output = data;
|
||||
|
||||
wlr_surface_send_leave(surface->surface, output->output);
|
||||
}
|
||||
|
||||
static void handle_scene_buffer_output_sample(
|
||||
struct wl_listener *listener, void *data) {
|
||||
struct wlr_scene_surface *surface =
|
||||
|
|
@ -380,8 +392,6 @@ static void surface_addon_destroy(struct wlr_addon *addon) {
|
|||
wlr_addon_finish(&surface->addon);
|
||||
|
||||
wl_list_remove(&surface->outputs_update.link);
|
||||
wl_list_remove(&surface->output_enter.link);
|
||||
wl_list_remove(&surface->output_leave.link);
|
||||
wl_list_remove(&surface->output_sample.link);
|
||||
wl_list_remove(&surface->frame_done.link);
|
||||
wl_list_remove(&surface->surface_destroy.link);
|
||||
|
|
@ -427,12 +437,6 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent
|
|||
surface->outputs_update.notify = handle_scene_buffer_outputs_update;
|
||||
wl_signal_add(&scene_buffer->events.outputs_update, &surface->outputs_update);
|
||||
|
||||
surface->output_enter.notify = handle_scene_buffer_output_enter;
|
||||
wl_signal_add(&scene_buffer->events.output_enter, &surface->output_enter);
|
||||
|
||||
surface->output_leave.notify = handle_scene_buffer_output_leave;
|
||||
wl_signal_add(&scene_buffer->events.output_leave, &surface->output_leave);
|
||||
|
||||
surface->output_sample.notify = handle_scene_buffer_output_sample;
|
||||
wl_signal_add(&scene_buffer->events.output_sample, &surface->output_sample);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue