diff --git a/include/swaylock.h b/include/swaylock.h index 2d384884..a6492911 100644 --- a/include/swaylock.h +++ b/include/swaylock.h @@ -8,6 +8,8 @@ #include "pool-buffer.h" #include "seat.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "viewporter-client-protocol.h" +#include "single-pixel-buffer-v1-client-protocol.h" enum auth_state { AUTH_STATE_IDLE, @@ -78,6 +80,9 @@ struct swaylock_state { struct wl_display *display; struct wl_compositor *compositor; struct wl_subcompositor *subcompositor; + struct wp_viewporter *viewporter; + struct wl_buffer *background_buffer; + struct wp_single_pixel_buffer_manager_v1 *single_pixel_buffer_manager; struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager; struct wl_shm *shm; @@ -100,11 +105,13 @@ struct swaylock_surface { uint32_t output_global_name; struct wl_surface *surface; struct wl_surface *child; // surface made into subsurface + struct wp_viewport *viewport; struct wl_subsurface *subsurface; struct zwlr_layer_surface_v1 *layer_surface; struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1; struct pool_buffer buffers[2]; struct pool_buffer indicator_buffers[2]; + struct wl_buffer *backgound_buffer; bool frame_pending, dirty; uint32_t width, height; uint32_t indicator_width, indicator_height; diff --git a/main.c b/main.c index ff1b1dc8..bebb9543 100644 --- a/main.c +++ b/main.c @@ -109,6 +109,7 @@ static void destroy_surface(struct swaylock_surface *surface) { destroy_buffer(&surface->buffers[1]); destroy_buffer(&surface->indicator_buffers[0]); destroy_buffer(&surface->indicator_buffers[1]); + wp_viewport_destroy(surface->viewport); wl_output_destroy(surface->output); free(surface); } @@ -173,6 +174,11 @@ static void create_surface(struct swaylock_surface *surface) { wl_region_destroy(region); } + if (state->viewporter) { + surface->viewport = wp_viewporter_get_viewport( + state->viewporter, surface->surface); + } + if (!state->ext_session_lock_v1) { wl_surface_commit(surface->surface); } @@ -373,6 +379,13 @@ static void handle_global(void *data, struct wl_registry *registry, } else if (strcmp(interface, ext_session_lock_manager_v1_interface.name) == 0) { state->ext_session_lock_manager_v1 = wl_registry_bind(registry, name, &ext_session_lock_manager_v1_interface, 1); + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { + state->viewporter = wl_registry_bind(registry, name, + &wp_viewporter_interface, 1); + } else if (strcmp(interface, + wp_single_pixel_buffer_manager_v1_interface.name) == 0) { + state->single_pixel_buffer_manager = wl_registry_bind(registry, name, + &wp_single_pixel_buffer_manager_v1_interface, 1); } } @@ -1265,6 +1278,20 @@ int main(int argc, char **argv) { return 1; } + if (state.single_pixel_buffer_manager && state.viewporter) { + uint8_t r8 = (state.args.colors.background >> 24) & 0xFF; + uint8_t g8 = (state.args.colors.background >> 16) & 0xFF; + uint8_t b8 = (state.args.colors.background >> 8) & 0xFF; + uint8_t a8 = (state.args.colors.background >> 0) & 0xFF; + uint32_t f = 0xFFFFFFFF / 0xFF; // division result is an integer + uint32_t r32 = r8 * f; + uint32_t g32 = g8 * f; + uint32_t b32 = b8 * f; + uint32_t a32 = a8 * f; + state.background_buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer( + state.single_pixel_buffer_manager, r32, g32, b32, a32); + } + struct swaylock_surface *surface; wl_list_for_each(surface, &state.surfaces, link) { create_surface(surface); @@ -1298,6 +1325,7 @@ int main(int argc, char **argv) { wl_display_flush(state.display); } + wl_buffer_destroy(state.background_buffer); free(state.args.font); return 0; } diff --git a/meson.build b/meson.build index c00bc7f7..b2303c56 100644 --- a/meson.build +++ b/meson.build @@ -37,7 +37,7 @@ if is_freebsd endif wayland_client = dependency('wayland-client', version: '>=1.20.0') -wayland_protos = dependency('wayland-protocols', version: '>=1.25', fallback: 'wayland-protocols') +wayland_protos = dependency('wayland-protocols', version: '>=1.26', fallback: 'wayland-protocols') # use native version of wayland-scanner when cross-compiling # meson does this too: https://github.com/mesonbuild/meson/blob/c649a2b8c59c9f49affca9bd89c126bfa0f54449/mesonbuild/modules/unstable_wayland.py#L48-L53 wayland_scanner = dependency('wayland-scanner', version: '>=1.15.0', native: true) @@ -84,6 +84,8 @@ client_protos_headers = [] client_protocols = [ wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', + wl_protocol_dir / 'stable/viewporter/viewporter.xml', + wl_protocol_dir / 'staging/single-pixel-buffer/single-pixel-buffer-v1.xml', 'wlr-layer-shell-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', ] diff --git a/render.c b/render.c index 0dc84301..6144ab77 100644 --- a/render.c +++ b/render.c @@ -41,6 +41,26 @@ void render_frame_background(struct swaylock_surface *surface) { return; // not yet configured } + if (surface->viewport && state->background_buffer && + (!surface->image || state->args.mode == BACKGROUND_MODE_SOLID_COLOR)) { + // no need to carry around shm buffers if we are going to use the single + // pixel buffer + destroy_buffer(&surface->buffers[0]); + destroy_buffer(&surface->buffers[1]); + + wl_surface_set_buffer_scale(surface->surface, 1); + wl_surface_attach(surface->surface, state->background_buffer, 0, 0); + wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX); + wp_viewport_set_destination(surface->viewport, surface->width, surface->height); + + wl_surface_commit(surface->surface); + return; + } + + if (surface->viewport) { + wp_viewport_set_destination(surface->viewport, -1, -1); + } + struct pool_buffer *buffer = get_next_buffer(state->shm, surface->buffers, buffer_width, buffer_height); if (buffer == NULL) {