scaled-scene-buffer: use outputs_update signal

This fixes an issue with buffers not updating when an output is configured
for a new scale. It also supports windows being on more than 2 outputs at
once and in general simplifies the code.
This commit is contained in:
Consolatis 2025-01-09 18:39:59 +01:00
parent 1a6dd845a2
commit 6496773fd1
2 changed files with 13 additions and 56 deletions

View file

@ -34,8 +34,7 @@ struct scaled_scene_buffer {
/* cached wlr_buffers for each scale */ /* cached wlr_buffers for each scale */
struct wl_list cache; /* struct scaled_buffer_cache_entry.link */ struct wl_list cache; /* struct scaled_buffer_cache_entry.link */
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener output_enter; struct wl_listener outputs_update;
struct wl_listener output_leave;
const struct scaled_scene_buffer_impl *impl; const struct scaled_scene_buffer_impl *impl;
/* /*
* Pointer to the per-implementation list of scaled-scene-buffers. * Pointer to the per-implementation list of scaled-scene-buffers.

View file

@ -8,33 +8,11 @@
#include <wlr/types/wlr_scene.h> #include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include "buffer.h" #include "buffer.h"
#include "common/macros.h"
#include "common/mem.h" #include "common/mem.h"
#include "common/scaled-scene-buffer.h" #include "common/scaled-scene-buffer.h"
#include "node.h" #include "node.h"
/**
* TODO
*
* This implementation does not react to output scale changes itself but only
* to movement of scene nodes to different outputs. To also handle output scale
* changes we'd need to keep a list of struct wlr_outputs * in sync and listen
* to their commit signals.
*
* The detection of the max output scale is also not 100% robust for all use
* cases as on output_enter we only compare the new output scale with the
* primary_output scale. In specific conditions the primary output may be the
* same as the new output even though a smaller part of the buffer node is
* still visible on an output with a bigger scale. This could be solved the
* same way as the previous point in keeping a list of outputs in sync.
*
* Most of this would be easier when wlroots would instead provide a
* max_scale_changed event because it already touches all the relevant parts
* when calculating the primary_output and inform wlr_scene_buffers about
* output changes.
*
* See wlroots/types/scene/wlr_scene.c scene_buffer_update_outputs()
*/
/* Internal API */ /* Internal API */
static void static void
_cache_entry_destroy(struct scaled_scene_buffer_cache_entry *cache_entry, bool drop_buffer) _cache_entry_destroy(struct scaled_scene_buffer_cache_entry *cache_entry, bool drop_buffer)
@ -162,8 +140,7 @@ _handle_node_destroy(struct wl_listener *listener, void *data)
struct scaled_scene_buffer *self = wl_container_of(listener, self, destroy); struct scaled_scene_buffer *self = wl_container_of(listener, self, destroy);
wl_list_remove(&self->destroy.link); wl_list_remove(&self->destroy.link);
wl_list_remove(&self->output_enter.link); wl_list_remove(&self->outputs_update.link);
wl_list_remove(&self->output_leave.link);
wl_list_for_each_safe(cache_entry, cache_entry_tmp, &self->cache, link) { wl_list_for_each_safe(cache_entry, cache_entry_tmp, &self->cache, link) {
_cache_entry_destroy(cache_entry, self->drop_buffer); _cache_entry_destroy(cache_entry, self->drop_buffer);
@ -178,38 +155,21 @@ _handle_node_destroy(struct wl_listener *listener, void *data)
} }
static void static void
_handle_output_enter(struct wl_listener *listener, void *data) _handle_outputs_update(struct wl_listener *listener, void *data)
{ {
struct scaled_scene_buffer *self = struct scaled_scene_buffer *self =
wl_container_of(listener, self, output_enter); wl_container_of(listener, self, outputs_update);
/* primary_output is the output most of the node area is in */
struct wlr_scene_output *primary = self->scene_buffer->primary_output;
/* scene_output is the output we just entered */
struct wlr_scene_output *scene_output = data;
double max_scale = scene_output->output->scale;
if (primary && primary->output->scale > max_scale) { double max_scale = 0;
max_scale = primary->output->scale; struct wlr_scene_outputs_update_event *event = data;
for (size_t i = 0; i < event->size; i++) {
max_scale = MAX(max_scale, event->active[i]->output->scale);
} }
if (max_scale && self->active_scale != max_scale) {
if (self->active_scale != max_scale) {
_update_buffer(self, max_scale); _update_buffer(self, max_scale);
} }
} }
static void
_handle_output_leave(struct wl_listener *listener, void *data)
{
struct scaled_scene_buffer *self =
wl_container_of(listener, self, output_leave);
/* primary_output is the output most of the node area is in */
struct wlr_scene_output *primary = self->scene_buffer->primary_output;
if (primary && primary->output->scale != self->active_scale) {
_update_buffer(self, primary->output->scale);
}
}
/* Public API */ /* Public API */
struct scaled_scene_buffer * struct scaled_scene_buffer *
scaled_scene_buffer_create(struct wlr_scene_tree *parent, scaled_scene_buffer_create(struct wlr_scene_tree *parent,
@ -247,11 +207,9 @@ scaled_scene_buffer_create(struct wlr_scene_tree *parent,
wl_list_init(&self->link); wl_list_init(&self->link);
} }
/* Listen to output enter/leave so we get notified about scale changes */ /* Listen to outputs_update so we get notified about scale changes */
self->output_enter.notify = _handle_output_enter; self->outputs_update.notify = _handle_outputs_update;
wl_signal_add(&self->scene_buffer->events.output_enter, &self->output_enter); wl_signal_add(&self->scene_buffer->events.outputs_update, &self->outputs_update);
self->output_leave.notify = _handle_output_leave;
wl_signal_add(&self->scene_buffer->events.output_leave, &self->output_leave);
/* Let it destroy automatically when the scene node destroys */ /* Let it destroy automatically when the scene node destroys */
self->destroy.notify = _handle_node_destroy; self->destroy.notify = _handle_node_destroy;