diff --git a/include/swaylock.h b/include/swaylock.h index e49c716c..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,12 +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 pool_buffer *current_buffer; + 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 b37cd8fe..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); } } @@ -1226,8 +1239,18 @@ int main(int argc, char **argv) { wl_registry_add_listener(registry, ®istry_listener, &state); wl_display_roundtrip(state.display); - if (!state.compositor || !state.shm) { - swaylock_log(LOG_ERROR, "Missing wl_compositor or wl_shm"); + if (!state.compositor) { + swaylock_log(LOG_ERROR, "Missing wl_compositor"); + return 1; + } + + if (!state.subcompositor) { + swaylock_log(LOG_ERROR, "Missing wl_subcompositor"); + return 1; + } + + if (!state.shm) { + swaylock_log(LOG_ERROR, "Missing wl_shm"); return 1; } @@ -1255,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); @@ -1288,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 6f6f99ae..6144ab77 100644 --- a/render.c +++ b/render.c @@ -41,13 +41,33 @@ void render_frame_background(struct swaylock_surface *surface) { return; // not yet configured } - surface->current_buffer = get_next_buffer(state->shm, + 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 (surface->current_buffer == NULL) { + if (buffer == NULL) { return; } - cairo_t *cairo = surface->current_buffer->cairo; + cairo_t *cairo = buffer->cairo; cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_save(cairo); @@ -63,7 +83,7 @@ void render_frame_background(struct swaylock_surface *surface) { cairo_identity_matrix(cairo); wl_surface_set_buffer_scale(surface->surface, surface->scale); - wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); + wl_surface_attach(surface->surface, buffer->buffer, 0, 0); wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(surface->surface); } @@ -102,9 +122,9 @@ void render_frame(struct swaylock_surface *surface) { wl_subsurface_set_position(surface->subsurface, subsurf_xpos, subsurf_ypos); - surface->current_buffer = get_next_buffer(state->shm, + struct pool_buffer *buffer = get_next_buffer(state->shm, surface->indicator_buffers, buffer_width, buffer_height); - if (surface->current_buffer == NULL) { + if (buffer == NULL) { return; } @@ -112,7 +132,7 @@ void render_frame(struct swaylock_surface *surface) { wl_surface_attach(surface->child, NULL, 0, 0); wl_surface_commit(surface->child); - cairo_t *cairo = surface->current_buffer->cairo; + cairo_t *cairo = buffer->cairo; cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_font_options_t *fo = cairo_font_options_create(); cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); @@ -317,7 +337,7 @@ void render_frame(struct swaylock_surface *surface) { new_width += surface->scale - (new_width % surface->scale); if (buffer_width != new_width || buffer_height != new_height) { - destroy_buffer(surface->current_buffer); + destroy_buffer(buffer); surface->indicator_width = new_width; surface->indicator_height = new_height; render_frame(surface); @@ -325,7 +345,7 @@ void render_frame(struct swaylock_surface *surface) { } wl_surface_set_buffer_scale(surface->child, surface->scale); - wl_surface_attach(surface->child, surface->current_buffer->buffer, 0, 0); + wl_surface_attach(surface->child, buffer->buffer, 0, 0); wl_surface_damage_buffer(surface->child, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(surface->child);