mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-12-22 18:09:49 +01:00
backend/wayland: implement output layers
This commit is contained in:
parent
3e0ce761ad
commit
cd17b18495
3 changed files with 182 additions and 12 deletions
|
@ -393,6 +393,9 @@ static void registry_global(void *data, struct wl_registry *registry,
|
|||
} else if (strcmp(iface, xdg_activation_v1_interface.name) == 0) {
|
||||
wl->activation_v1 = wl_registry_bind(registry, name,
|
||||
&xdg_activation_v1_interface, 1);
|
||||
} else if (strcmp(iface, wl_subcompositor_interface.name) == 0) {
|
||||
wl->subcompositor = wl_registry_bind(registry, name,
|
||||
&wl_subcompositor_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,6 +503,9 @@ static void backend_destroy(struct wlr_backend *backend) {
|
|||
if (wl->zwp_relative_pointer_manager_v1) {
|
||||
zwp_relative_pointer_manager_v1_destroy(wl->zwp_relative_pointer_manager_v1);
|
||||
}
|
||||
if (wl->subcompositor) {
|
||||
wl_subcompositor_destroy(wl->subcompositor);
|
||||
}
|
||||
free(wl->drm_render_name);
|
||||
free(wl->activation_token);
|
||||
xdg_wm_base_destroy(wl->xdg_wm_base);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <wlr/interfaces/wlr_output.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_matrix.h>
|
||||
#include <wlr/types/wlr_output_layer.h>
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
#include "backend/wayland.h"
|
||||
|
@ -275,6 +276,154 @@ static bool output_test(struct wlr_output *wlr_output,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_LAYERS) {
|
||||
// If we can't use a sub-surface for a layer, then we can't use a
|
||||
// sub-surface for any layer underneath
|
||||
bool supported = output->backend->subcompositor != NULL;
|
||||
for (ssize_t i = state->layers_len - 1; i >= 0; i--) {
|
||||
struct wlr_output_layer_state *layer_state = &state->layers[i];
|
||||
if (layer_state->buffer != NULL) {
|
||||
if (layer_state->x < 0 || layer_state->y < 0 ||
|
||||
layer_state->x + layer_state->buffer->width > wlr_output->width ||
|
||||
layer_state->y + layer_state->buffer->height > wlr_output->height) {
|
||||
supported = false;
|
||||
}
|
||||
supported = supported &&
|
||||
test_buffer(output->backend, layer_state->buffer);
|
||||
}
|
||||
layer_state->accepted = supported;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void output_layer_handle_addon_destroy(struct wlr_addon *addon) {
|
||||
struct wlr_wl_output_layer *layer = wl_container_of(addon, layer, addon);
|
||||
|
||||
wlr_addon_finish(&layer->addon);
|
||||
wl_subsurface_destroy(layer->subsurface);
|
||||
wl_surface_destroy(layer->surface);
|
||||
free(layer);
|
||||
}
|
||||
|
||||
static const struct wlr_addon_interface output_layer_addon_impl = {
|
||||
.name = "wlr_wl_output_layer",
|
||||
.destroy = output_layer_handle_addon_destroy,
|
||||
};
|
||||
|
||||
static struct wlr_wl_output_layer *get_or_create_output_layer(
|
||||
struct wlr_wl_output *output, struct wlr_output_layer *wlr_layer) {
|
||||
assert(output->backend->subcompositor != NULL);
|
||||
|
||||
struct wlr_wl_output_layer *layer;
|
||||
struct wlr_addon *addon = wlr_addon_find(&wlr_layer->addons, output,
|
||||
&output_layer_addon_impl);
|
||||
if (addon != NULL) {
|
||||
layer = wl_container_of(addon, layer, addon);
|
||||
return layer;
|
||||
}
|
||||
|
||||
layer = calloc(1, sizeof(*layer));
|
||||
if (layer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_addon_init(&layer->addon, &wlr_layer->addons, output,
|
||||
&output_layer_addon_impl);
|
||||
|
||||
layer->surface = wl_compositor_create_surface(output->backend->compositor);
|
||||
layer->subsurface = wl_subcompositor_get_subsurface(
|
||||
output->backend->subcompositor, layer->surface, output->surface);
|
||||
|
||||
// Set an empty input region so that input events are handled by the main
|
||||
// surface
|
||||
struct wl_region *region = wl_compositor_create_region(output->backend->compositor);
|
||||
wl_surface_set_input_region(layer->surface, region);
|
||||
wl_region_destroy(region);
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
static bool output_layer_commit(struct wlr_wl_output *output,
|
||||
struct wlr_wl_output_layer *layer,
|
||||
const struct wlr_output_layer_state *state) {
|
||||
// TODO: only do this if the layer moved
|
||||
wl_subsurface_set_position(layer->subsurface, state->x, state->y);
|
||||
|
||||
struct wlr_wl_buffer *buffer = NULL;
|
||||
if (state->buffer != NULL) {
|
||||
buffer = get_or_create_wl_buffer(output->backend, state->buffer);
|
||||
if (buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
wl_surface_attach(layer->surface, buffer ? buffer->wl_buffer : NULL, 0, 0);
|
||||
wl_surface_damage_buffer(layer->surface, 0, 0, INT32_MAX, INT32_MAX);
|
||||
|
||||
wl_surface_commit(layer->surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool commit_layers(struct wlr_wl_output *output,
|
||||
struct wlr_output_layer_state *layers, size_t layers_len) {
|
||||
if (output->backend->subcompositor == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_wl_output_layer *prev_layer = NULL;
|
||||
for (size_t i = 0; i < layers_len; i++) {
|
||||
struct wlr_wl_output_layer *layer =
|
||||
get_or_create_output_layer(output, layers[i].layer);
|
||||
if (layer == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!layers[i].accepted) {
|
||||
// Unmap the sub-surface
|
||||
// TODO: only do this once
|
||||
wl_surface_attach(layer->surface, NULL, 0, 0);
|
||||
wl_surface_commit(layer->surface);
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: only do this if layers were re-ordered
|
||||
if (prev_layer != NULL) {
|
||||
wl_subsurface_place_above(layer->subsurface,
|
||||
prev_layer->surface);
|
||||
}
|
||||
|
||||
if (!output_layer_commit(output, layer, &layers[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap any layer we haven't seen
|
||||
struct wlr_output_layer *wlr_layer;
|
||||
wl_list_for_each(wlr_layer, &output->wlr_output.layers, link) {
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < layers_len; i++) {
|
||||
if (layers[i].layer == wlr_layer) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct wlr_wl_output_layer *layer =
|
||||
get_or_create_output_layer(output, wlr_layer);
|
||||
if (layer == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: only do this once
|
||||
wl_surface_attach(layer->surface, NULL, 0, 0);
|
||||
wl_surface_commit(layer->surface);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -288,23 +437,11 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
}
|
||||
|
||||
if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
|
||||
struct wp_presentation_feedback *wp_feedback = NULL;
|
||||
if (output->backend->presentation != NULL) {
|
||||
wp_feedback = wp_presentation_feedback(output->backend->presentation,
|
||||
output->surface);
|
||||
}
|
||||
|
||||
const pixman_region32_t *damage = NULL;
|
||||
if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
|
||||
damage = &state->damage;
|
||||
}
|
||||
|
||||
if (output->frame_callback != NULL) {
|
||||
wl_callback_destroy(output->frame_callback);
|
||||
}
|
||||
output->frame_callback = wl_surface_frame(output->surface);
|
||||
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
||||
|
||||
struct wlr_buffer *wlr_buffer = state->buffer;
|
||||
struct wlr_wl_buffer *buffer =
|
||||
get_or_create_wl_buffer(output->backend, wlr_buffer);
|
||||
|
@ -327,6 +464,25 @@ static bool output_commit(struct wlr_output *wlr_output,
|
|||
r->x2 - r->x1, r->y2 - r->y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((state->committed & WLR_OUTPUT_STATE_LAYERS) &&
|
||||
!commit_layers(output, state->layers, state->layers_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state->committed & (WLR_OUTPUT_STATE_BUFFER | WLR_OUTPUT_STATE_LAYERS)) {
|
||||
if (output->frame_callback != NULL) {
|
||||
wl_callback_destroy(output->frame_callback);
|
||||
}
|
||||
output->frame_callback = wl_surface_frame(output->surface);
|
||||
wl_callback_add_listener(output->frame_callback, &frame_listener, output);
|
||||
|
||||
struct wp_presentation_feedback *wp_feedback = NULL;
|
||||
if (output->backend->presentation != NULL) {
|
||||
wp_feedback = wp_presentation_feedback(output->backend->presentation,
|
||||
output->surface);
|
||||
}
|
||||
|
||||
wl_surface_commit(output->surface);
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ struct wlr_wl_backend {
|
|||
struct wlr_drm_format_set linux_dmabuf_v1_formats;
|
||||
struct wl_drm *legacy_drm;
|
||||
struct xdg_activation_v1 *activation_v1;
|
||||
struct wl_subcompositor *subcompositor;
|
||||
char *drm_render_name;
|
||||
};
|
||||
|
||||
|
@ -65,6 +66,13 @@ struct wlr_wl_presentation_feedback {
|
|||
uint32_t commit_seq;
|
||||
};
|
||||
|
||||
struct wlr_wl_output_layer {
|
||||
struct wlr_addon addon;
|
||||
|
||||
struct wl_surface *surface;
|
||||
struct wl_subsurface *subsurface;
|
||||
};
|
||||
|
||||
struct wlr_wl_output {
|
||||
struct wlr_output wlr_output;
|
||||
|
||||
|
|
Loading…
Reference in a new issue