Decouple the drawing of the background from drawing the indicator.

* Render background only once in main wl_surface
* Render indicator on subsurface
This commit is contained in:
Anders Nylander 2019-03-12 11:16:33 +01:00 committed by emersion
parent 6b3be42264
commit 7d5a73b0a9
3 changed files with 76 additions and 22 deletions

View File

@ -69,6 +69,7 @@ struct swaylock_state {
struct loop_timer *clear_password_timer; // clears the password buffer struct loop_timer *clear_password_timer; // clears the password buffer
struct wl_display *display; struct wl_display *display;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wl_subcompositor *subcompositor;
struct zwlr_layer_shell_v1 *layer_shell; struct zwlr_layer_shell_v1 *layer_shell;
struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager; struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager;
struct wl_shm *shm; struct wl_shm *shm;
@ -90,8 +91,11 @@ struct swaylock_surface {
uint32_t output_global_name; uint32_t output_global_name;
struct zxdg_output_v1 *xdg_output; struct zxdg_output_v1 *xdg_output;
struct wl_surface *surface; struct wl_surface *surface;
struct wl_surface *child; // surface made into subsurface
struct wl_subsurface *subsurface;
struct zwlr_layer_surface_v1 *layer_surface; struct zwlr_layer_surface_v1 *layer_surface;
struct pool_buffer buffers[2]; struct pool_buffer buffers[2];
struct pool_buffer indicator_buffers[2];
struct pool_buffer *current_buffer; struct pool_buffer *current_buffer;
bool frame_pending, dirty; bool frame_pending, dirty;
uint32_t width, height; uint32_t width, height;
@ -111,6 +115,7 @@ struct swaylock_image {
void swaylock_handle_key(struct swaylock_state *state, void swaylock_handle_key(struct swaylock_state *state,
xkb_keysym_t keysym, uint32_t codepoint); xkb_keysym_t keysym, uint32_t codepoint);
void render_frame_background(struct swaylock_surface *surface);
void render_frame(struct swaylock_surface *surface); void render_frame(struct swaylock_surface *surface);
void render_frames(struct swaylock_state *state); void render_frames(struct swaylock_state *state);
void damage_surface(struct swaylock_surface *surface); void damage_surface(struct swaylock_surface *surface);

10
main.c
View File

@ -126,6 +126,12 @@ static void create_layer_surface(struct swaylock_surface *surface) {
surface->surface = wl_compositor_create_surface(state->compositor); surface->surface = wl_compositor_create_surface(state->compositor);
assert(surface->surface); 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( surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
state->layer_shell, surface->surface, surface->output, state->layer_shell, surface->surface, surface->output,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen"); ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
@ -163,6 +169,7 @@ static void layer_surface_configure(void *data,
surface->width = width; surface->width = width;
surface->height = height; surface->height = height;
zwlr_layer_surface_v1_ack_configure(layer_surface, serial); zwlr_layer_surface_v1_ack_configure(layer_surface, serial);
render_frame_background(surface);
render_frame(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) { if (strcmp(interface, wl_compositor_interface.name) == 0) {
state->compositor = wl_registry_bind(registry, name, state->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 3); &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) { } else if (strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = wl_registry_bind(registry, name, state->shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1); &wl_shm_interface, 1);

View File

@ -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; struct swaylock_state *state = surface->state;
int buffer_width = surface->width * surface->scale; 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_t *cairo = surface->current_buffer->cairo;
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); 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_save(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 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) { if (surface->image && state->args.mode != BACKGROUND_MODE_SOLID_COLOR) {
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
render_background_image(cairo, surface->image, render_background_image(cairo, surface->image,
state->args.mode, buffer_width, buffer_height); state->args.mode, buffer_width, buffer_height);
} }
cairo_restore(cairo); cairo_restore(cairo);
cairo_identity_matrix(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_radius = state->args.radius * surface->scale;
int arc_thickness = state->args.thickness * 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 = float type_indicator_border_thickness =
TYPE_INDICATOR_BORDER_THICKNESS * surface->scale; TYPE_INDICATOR_BORDER_THICKNESS * surface->scale;
if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) { if (state->args.show_indicator && state->auth_state != AUTH_STATE_IDLE) {
// Draw circle // Draw circle
cairo_set_line_width(cairo, arc_thickness); 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); 0, 2 * M_PI);
set_color_for_state(cairo, state, &state->args.colors.inside); set_color_for_state(cairo, state, &state->args.colors.inside);
cairo_fill_preserve(cairo); cairo_fill_preserve(cairo);
@ -142,9 +179,9 @@ void render_frame(struct swaylock_surface *surface) {
double x, y; double x, y;
cairo_text_extents(cairo, text, &extents); cairo_text_extents(cairo, text, &extents);
cairo_font_extents(cairo, &fe); cairo_font_extents(cairo, &fe);
x = (buffer_width / 2) - x = (buffer_diameter / 2) -
(extents.width / 2 + extents.x_bearing); (extents.width / 2 + extents.x_bearing);
y = (buffer_height / 2) + y = (buffer_diameter / 2) +
(fe.height / 2 - fe.descent); (fe.height / 2 - fe.descent);
cairo_move_to(cairo, x, y); cairo_move_to(cairo, x, y);
@ -159,7 +196,7 @@ void render_frame(struct swaylock_surface *surface) {
static double highlight_start = 0; static double highlight_start = 0;
highlight_start += highlight_start +=
(rand() % (int)(M_PI * 100)) / 100.0 + M_PI * 0.5; (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, arc_radius, highlight_start,
highlight_start + TYPE_INDICATOR_RANGE); highlight_start + TYPE_INDICATOR_RANGE);
if (state->auth_state == AUTH_STATE_INPUT) { if (state->auth_state == AUTH_STATE_INPUT) {
@ -179,12 +216,12 @@ void render_frame(struct swaylock_surface *surface) {
// Draw borders // Draw borders
cairo_set_source_u32(cairo, state->args.colors.separator); 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, arc_radius, highlight_start,
highlight_start + type_indicator_border_thickness); highlight_start + type_indicator_border_thickness);
cairo_stroke(cairo); 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, arc_radius, highlight_start + TYPE_INDICATOR_RANGE,
highlight_start + TYPE_INDICATOR_RANGE + highlight_start + TYPE_INDICATOR_RANGE +
type_indicator_border_thickness); type_indicator_border_thickness);
@ -194,10 +231,10 @@ void render_frame(struct swaylock_surface *surface) {
// Draw inner + outer border of the circle // Draw inner + outer border of the circle
set_color_for_state(cairo, state, &state->args.colors.line); set_color_for_state(cairo, state, &state->args.colors.line);
cairo_set_line_width(cairo, 2.0 * surface->scale); 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); arc_radius - arc_thickness / 2, 0, 2 * M_PI);
cairo_stroke(cairo); 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); arc_radius + arc_thickness / 2, 0, 2 * M_PI);
cairo_stroke(cairo); cairo_stroke(cairo);
@ -210,8 +247,8 @@ void render_frame(struct swaylock_surface *surface) {
cairo_text_extents(cairo, layout_text, &extents); cairo_text_extents(cairo, layout_text, &extents);
cairo_font_extents(cairo, &fe); cairo_font_extents(cairo, &fe);
// upper left coordinates for box // upper left coordinates for box
x = (buffer_width / 2) - (extents.width / 2) - box_padding; x = (buffer_diameter / 2) - (extents.width / 2) - box_padding;
y = (buffer_height / 2) + arc_radius + arc_thickness/2 + y = (buffer_diameter / 2) + arc_radius + arc_thickness/2 +
box_padding; // use box_padding also as gap to indicator box_padding; // use box_padding also as gap to indicator
// background box // background box
@ -235,9 +272,11 @@ void render_frame(struct swaylock_surface *surface) {
} }
} }
wl_surface_set_buffer_scale(surface->surface, surface->scale); wl_surface_set_buffer_scale(surface->child, surface->scale);
wl_surface_attach(surface->surface, surface->current_buffer->buffer, 0, 0); wl_surface_attach(surface->child, surface->current_buffer->buffer, 0, 0);
wl_surface_damage(surface->surface, 0, 0, surface->width, surface->height); 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); wl_surface_commit(surface->surface);
} }