diff --git a/include/swaylock.h b/include/swaylock.h index 0324936..23e3408 100644 --- a/include/swaylock.h +++ b/include/swaylock.h @@ -69,6 +69,7 @@ struct swaylock_state { struct loop_timer *clear_password_timer; // clears the password buffer struct wl_display *display; struct wl_compositor *compositor; + struct wl_subcompositor *subcompositor; struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager; struct wl_shm *shm; @@ -90,8 +91,11 @@ struct swaylock_surface { uint32_t output_global_name; struct zxdg_output_v1 *xdg_output; struct wl_surface *surface; + struct wl_surface *child; // surface made into subsurface + struct wl_subsurface *subsurface; struct zwlr_layer_surface_v1 *layer_surface; struct pool_buffer buffers[2]; + struct pool_buffer indicator_buffers[2]; struct pool_buffer *current_buffer; bool frame_pending, dirty; uint32_t width, height; @@ -111,6 +115,7 @@ struct swaylock_image { void swaylock_handle_key(struct swaylock_state *state, xkb_keysym_t keysym, uint32_t codepoint); +void render_frame_background(struct swaylock_surface *surface); void render_frame(struct swaylock_surface *surface); void render_frames(struct swaylock_state *state); void damage_surface(struct swaylock_surface *surface); diff --git a/main.c b/main.c index 6160377..b80fdbb 100644 --- a/main.c +++ b/main.c @@ -126,6 +126,12 @@ static void create_layer_surface(struct swaylock_surface *surface) { surface->surface = wl_compositor_create_surface(state->compositor); assert(surface->surface); + surface->child = wl_compositor_create_surface(state->compositor); + assert(surface->child); + surface->subsurface = wl_subcompositor_get_subsurface(state->subcompositor, surface->child, surface->surface); + assert(surface->subsurface); + wl_subsurface_set_sync(surface->subsurface); + surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface( state->layer_shell, surface->surface, surface->output, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen"); @@ -163,6 +169,7 @@ static void layer_surface_configure(void *data, surface->width = width; surface->height = height; zwlr_layer_surface_v1_ack_configure(layer_surface, serial); + render_frame_background(surface); render_frame(surface); } @@ -297,6 +304,9 @@ static void handle_global(void *data, struct wl_registry *registry, if (strcmp(interface, wl_compositor_interface.name) == 0) { state->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 3); + } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { + state->subcompositor = wl_registry_bind(registry, name, + &wl_subcompositor_interface, 1); } else if (strcmp(interface, wl_shm_interface.name) == 0) { state->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); diff --git a/render.c b/render.c index a209f21..47d3824 100644 --- a/render.c +++ b/render.c @@ -32,7 +32,7 @@ static void set_color_for_state(cairo_t *cairo, struct swaylock_state *state, } } -void render_frame(struct swaylock_surface *surface) { +void render_frame_background(struct swaylock_surface *surface) { struct swaylock_state *state = surface->state; int buffer_width = surface->width * surface->scale; @@ -49,13 +49,6 @@ void render_frame(struct swaylock_surface *surface) { cairo_t *cairo = surface->current_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); - cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); - cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(surface->subpixel)); - cairo_set_font_options(cairo, fo); - cairo_font_options_destroy(fo); - cairo_identity_matrix(cairo); cairo_save(cairo); cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); @@ -64,20 +57,64 @@ void render_frame(struct swaylock_surface *surface) { if (surface->image && state->args.mode != BACKGROUND_MODE_SOLID_COLOR) { cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); render_background_image(cairo, surface->image, - state->args.mode, buffer_width, buffer_height); + state->args.mode, buffer_width, buffer_height); } cairo_restore(cairo); 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_damage(surface->surface, 0, 0, surface->width, surface->height); + wl_surface_commit(surface->surface); +} + +void render_frame(struct swaylock_surface *surface) { + struct swaylock_state *state = surface->state; + int arc_radius = state->args.radius * surface->scale; int arc_thickness = state->args.thickness * surface->scale; + int buffer_diameter = (arc_radius + arc_thickness) * 2; + int buffer_height = buffer_diameter * 2; + + int indicator_radius = (state->args.radius + state->args.thickness) * surface->scale; + int subsurf_xpos = surface->width / 2 - indicator_radius; + int subsurf_ypos = surface->height / 2 - indicator_radius; + wl_subsurface_set_position(surface->subsurface, subsurf_xpos, subsurf_ypos); + + surface->current_buffer = get_next_buffer(state->shm, + surface->indicator_buffers, buffer_diameter, buffer_height); + if (surface->current_buffer == NULL) { + return; + } + + // Hide subsurface until we want it visible + wl_surface_attach(surface->child, NULL, 0, 0); + wl_surface_commit(surface->child); + + cairo_t *cairo = surface->current_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); + cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(surface->subpixel)); + cairo_set_font_options(cairo, fo); + cairo_font_options_destroy(fo); + cairo_identity_matrix(cairo); + + // Clear + cairo_save(cairo); + cairo_set_source_rgba(cairo, 0, 0, 0, 0); + cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); + cairo_paint(cairo); + cairo_restore(cairo); + float type_indicator_border_thickness = TYPE_INDICATOR_BORDER_THICKNESS * surface->scale; if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) { // Draw circle cairo_set_line_width(cairo, arc_thickness); - cairo_arc(cairo, buffer_width / 2, buffer_height / 2, arc_radius, + cairo_arc(cairo, buffer_diameter / 2, buffer_diameter / 2, arc_radius, 0, 2 * M_PI); set_color_for_state(cairo, state, &state->args.colors.inside); cairo_fill_preserve(cairo); @@ -142,9 +179,9 @@ void render_frame(struct swaylock_surface *surface) { double x, y; cairo_text_extents(cairo, text, &extents); cairo_font_extents(cairo, &fe); - x = (buffer_width / 2) - + x = (buffer_diameter / 2) - (extents.width / 2 + extents.x_bearing); - y = (buffer_height / 2) + + y = (buffer_diameter / 2) + (fe.height / 2 - fe.descent); cairo_move_to(cairo, x, y); @@ -159,7 +196,7 @@ void render_frame(struct swaylock_surface *surface) { static double highlight_start = 0; highlight_start += (rand() % (int)(M_PI * 100)) / 100.0 + M_PI * 0.5; - cairo_arc(cairo, buffer_width / 2, buffer_height / 2, + cairo_arc(cairo, buffer_diameter / 2, buffer_diameter / 2, arc_radius, highlight_start, highlight_start + TYPE_INDICATOR_RANGE); if (state->auth_state == AUTH_STATE_INPUT) { @@ -179,12 +216,12 @@ void render_frame(struct swaylock_surface *surface) { // Draw borders cairo_set_source_u32(cairo, state->args.colors.separator); - cairo_arc(cairo, buffer_width / 2, buffer_height / 2, + cairo_arc(cairo, buffer_diameter / 2, buffer_diameter / 2, arc_radius, highlight_start, highlight_start + type_indicator_border_thickness); cairo_stroke(cairo); - cairo_arc(cairo, buffer_width / 2, buffer_height / 2, + cairo_arc(cairo, buffer_diameter / 2, buffer_diameter / 2, arc_radius, highlight_start + TYPE_INDICATOR_RANGE, highlight_start + TYPE_INDICATOR_RANGE + type_indicator_border_thickness); @@ -194,10 +231,10 @@ void render_frame(struct swaylock_surface *surface) { // Draw inner + outer border of the circle set_color_for_state(cairo, state, &state->args.colors.line); cairo_set_line_width(cairo, 2.0 * surface->scale); - cairo_arc(cairo, buffer_width / 2, buffer_height / 2, + cairo_arc(cairo, buffer_diameter / 2, buffer_diameter / 2, arc_radius - arc_thickness / 2, 0, 2 * M_PI); cairo_stroke(cairo); - cairo_arc(cairo, buffer_width / 2, buffer_height / 2, + cairo_arc(cairo, buffer_diameter / 2, buffer_diameter / 2, arc_radius + arc_thickness / 2, 0, 2 * M_PI); cairo_stroke(cairo); @@ -210,8 +247,8 @@ void render_frame(struct swaylock_surface *surface) { cairo_text_extents(cairo, layout_text, &extents); cairo_font_extents(cairo, &fe); // upper left coordinates for box - x = (buffer_width / 2) - (extents.width / 2) - box_padding; - y = (buffer_height / 2) + arc_radius + arc_thickness/2 + + x = (buffer_diameter / 2) - (extents.width / 2) - box_padding; + y = (buffer_diameter / 2) + arc_radius + arc_thickness/2 + box_padding; // use box_padding also as gap to indicator // background box @@ -235,9 +272,11 @@ void render_frame(struct swaylock_surface *surface) { } } - wl_surface_set_buffer_scale(surface->surface, surface->scale); - wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); - wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height); + wl_surface_set_buffer_scale(surface->child, surface->scale); + wl_surface_attach(surface->child, surface->current_buffer->buffer, 0, 0); + wl_surface_damage(surface->child, 0, 0, surface->current_buffer->width, surface->current_buffer->height); + wl_surface_commit(surface->child); + wl_surface_commit(surface->surface); }