diff --git a/CMakeLists.txt b/CMakeLists.txt index 8722bcb..5af4a2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ pkg_check_modules(WLROOTS REQUIRED IMPORTED_TARGET wlroots-0.20) pkg_check_modules(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon) pkg_check_modules(OPENXR REQUIRED IMPORTED_TARGET openxr) pkg_check_modules(LUA REQUIRED IMPORTED_TARGET lua) +pkg_check_modules(PIXMAN REQUIRED IMPORTED_TARGET pixman-1) find_program(WAYLAND_SCANNER_EXECUTABLE wayland-scanner REQUIRED) message(STATUS "Found wayland-scanner at ${WAYLAND_SCANNER_EXECUTABLE}") @@ -67,6 +68,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::WLROOTS PkgConfig::OPENXR PkgConfig::LUA + PkgConfig::PIXMAN raylib ) diff --git a/src/LunarWM_types.h b/src/LunarWM_types.h index 88d9f79..1792239 100644 --- a/src/LunarWM_types.h +++ b/src/LunarWM_types.h @@ -198,6 +198,7 @@ typedef struct LunarWM { struct wlr_allocator *allocator; struct wlr_compositor *compositor; + struct wl_listener new_surface_listener; struct wlr_subcompositor *subcompositor; struct wlr_data_device_manager *data_device_manager; diff --git a/src/LunarWM_wayland.c b/src/LunarWM_wayland.c index 603c575..47eae1a 100644 --- a/src/LunarWM_wayland.c +++ b/src/LunarWM_wayland.c @@ -6,6 +6,7 @@ #include "raylib.h" #include "vec.h" +#include #include #include @@ -37,6 +38,89 @@ static inline SphericalCoord get_forward_spherical_with_nearest( return Vector3ToSpherical(vec); } +struct SurfaceDamageListener { + struct wl_listener client_commit; + struct wl_listener destroy; +}; + +static void surface_damage_client_commit(struct wl_listener *listener, void *data) +{ + (void)listener; + struct wlr_surface *surface = data; + if (!surface) { + return; + } + if (!wlr_surface_state_has_buffer(&surface->pending)) { + return; + } + if (pixman_region32_not_empty(&surface->pending.surface_damage) + || pixman_region32_not_empty(&surface->pending.buffer_damage)) { + return; + } + + int surface_width = surface->pending.width > 0 ? surface->pending.width + : surface->current.width; + int surface_height = surface->pending.height > 0 ? surface->pending.height + : surface->current.height; + int buffer_width = surface->pending.buffer_width > 0 + ? surface->pending.buffer_width + : surface->current.buffer_width; + int buffer_height = surface->pending.buffer_height > 0 + ? surface->pending.buffer_height + : surface->current.buffer_height; + + if (surface_width <= 0 || surface_height <= 0 || buffer_width <= 0 + || buffer_height <= 0) { + return; + } + + pixman_region32_union_rect(&surface->pending.surface_damage, + &surface->pending.surface_damage, 0, 0, surface_width, surface_height); + pixman_region32_union_rect(&surface->pending.buffer_damage, + &surface->pending.buffer_damage, 0, 0, buffer_width, buffer_height); +} + +static void surface_damage_destroy(struct wl_listener *listener, void *data) +{ + (void)data; + struct SurfaceDamageListener *hook + = wl_container_of(listener, hook, destroy); + wl_list_remove(&hook->client_commit.link); + wl_list_remove(&hook->destroy.link); + free(hook); +} + +static void surface_damage_track(struct wlr_surface *surface) +{ + if (!surface) { + return; + } + + struct SurfaceDamageListener *hook = calloc(1, sizeof(*hook)); + if (!hook) { + wlr_log(WLR_ERROR, "Failed to allocate surface damage listener"); + return; + } + + hook->client_commit.notify = surface_damage_client_commit; + wl_signal_add(&surface->events.client_commit, &hook->client_commit); + + hook->destroy.notify = surface_damage_destroy; + wl_signal_add(&surface->events.destroy, &hook->destroy); +} + +static void compositor_new_surface_notify( + struct wl_listener *listener, void *data) +{ + (void)listener; + struct wlr_surface *surface = data; + if (!surface) { + return; + } + + surface_damage_track(surface); +} + struct ExternalTexturePipeline { bool attempted_init; bool ready; @@ -1776,6 +1860,10 @@ bool LunarWM_wayland_init(LunarWM *this) wlr_log(WLR_ERROR, "Failed to create compositor"); return false; } + this->wayland.new_surface_listener.notify = compositor_new_surface_notify; + wl_signal_add(&this->wayland.compositor->events.new_surface, + &this->wayland.new_surface_listener); + this->wayland.subcompositor = wlr_subcompositor_create(this->wayland.display); @@ -1853,6 +1941,12 @@ void LunarWM_wayland_cleanup(LunarWM *this) this->wayland.new_output_listener.notify = NULL; } + if (this->wayland.new_surface_listener.link.prev + || this->wayland.new_surface_listener.link.next) { + wl_list_remove(&this->wayland.new_surface_listener.link); + this->wayland.new_surface_listener.notify = NULL; + } + if (this->wayland.v_outputs) { for (size_t i = 0; i < vector_size(this->wayland.v_outputs); ++i) { destroy_output(this->wayland.v_outputs[i]);