From 58befcf2cdf261b8898b6fd1288a69d367101ff1 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 1 Jul 2018 10:58:13 +1000 Subject: [PATCH 1/7] Don't send frame done to surfaces behind lockscreen Also, when rendering, don't descend into the tree if the lockscreen is active. Just render the lockscreen's surfaces. --- sway/desktop/output.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1211cc07..52bd1666 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -948,8 +948,30 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_container *workspace = output_get_active_workspace(output); struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; + struct sway_seat *seat = input_manager_current_seat(input_manager); + + if (seat->exclusive_client && seat->focused_layer) { + float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, clear_color); + } - if (fullscreen_view) { + struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer; + struct sway_layer_surface *sway_layer_surface = + layer_from_wlr_layer_surface(seat->focused_layer); + struct render_data data = { + .output = output, + .damage = damage, + .alpha = 1.0f, + }; + surface_for_each_surface(wlr_layer_surface->surface, + sway_layer_surface->geo.x, sway_layer_surface->geo.y, + &data.root_geo, render_surface_iterator, &data); + } else if (fullscreen_view) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; int nrects; @@ -1019,11 +1041,16 @@ struct send_frame_done_data { struct root_geometry root_geo; struct sway_output *output; struct timespec *when; + struct wl_client *exclusive_client; }; static void send_frame_done_iterator(struct wlr_surface *surface, int sx, int sy, void *_data) { struct send_frame_done_data *data = _data; + if (data->exclusive_client && + data->exclusive_client != surface->resource->client) { + return; + } bool intersects = get_surface_box(&data->root_geo, data->output, surface, sx, sy, NULL); @@ -1072,9 +1099,11 @@ static void send_frame_done_container(struct send_frame_done_data *data, } static void send_frame_done(struct sway_output *output, struct timespec *when) { + struct sway_seat *seat = input_manager_current_seat(input_manager); struct send_frame_done_data data = { .output = output, .when = when, + .exclusive_client = seat->exclusive_client, }; struct sway_container *workspace = output_get_active_workspace(output); From 839c3a550043fd38096a15ff8dcd7de1a084efdc Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 3 Jul 2018 17:29:23 +1000 Subject: [PATCH 2/7] Use opaque region to determine if frame done should be sent --- include/sway/output.h | 4 ++++ sway/desktop/output.c | 35 +++++++++++++++++++++++++++++++++-- swaylock/main.c | 15 +++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 19fc5e99..e6fe55c6 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -54,4 +54,8 @@ void output_damage_whole_container(struct sway_output *output, struct sway_container *output_by_name(const char *name); void output_enable(struct sway_output *output); + +bool output_has_opaque_lockscreen(struct sway_output *output, + struct sway_seat *seat); + #endif diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 52bd1666..a6b2ebc2 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -915,6 +915,36 @@ static struct sway_container *output_get_active_workspace( return workspace; } +bool output_has_opaque_lockscreen(struct sway_output *output, + struct sway_seat *seat) { + if (!seat->exclusive_client) { + return false; + } + + struct wlr_layer_surface *wlr_layer_surface; + wl_list_for_each(wlr_layer_surface, &server.layer_shell->surfaces, link) { + if (wlr_layer_surface->output != output->wlr_output) { + continue; + } + struct wlr_surface *wlr_surface = wlr_layer_surface->surface; + if (wlr_surface->resource->client != seat->exclusive_client) { + continue; + } + int nrects; + pixman_box32_t *rects = + pixman_region32_rectangles(&wlr_surface->current->opaque, &nrects); + for (int i = 0; i < nrects; ++i) { + pixman_box32_t *rect = &rects[i]; + if (rect->x1 <= 0 && rect->y1 <= 0 && + rect->x2 >= output->swayc->current.swayc_width && + rect->y2 >= output->swayc->current.swayc_height) { + return true; + } + } + } + return false; +} + static void render_output(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; @@ -950,7 +980,7 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_view *fullscreen_view = workspace->current.ws_fullscreen; struct sway_seat *seat = input_manager_current_seat(input_manager); - if (seat->exclusive_client && seat->focused_layer) { + if (output_has_opaque_lockscreen(output, seat)) { float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; int nrects; @@ -1103,7 +1133,8 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { struct send_frame_done_data data = { .output = output, .when = when, - .exclusive_client = seat->exclusive_client, + .exclusive_client = output_has_opaque_lockscreen(output, seat) ? + seat->exclusive_client : NULL, }; struct sway_container *workspace = output_get_active_workspace(output); diff --git a/swaylock/main.c b/swaylock/main.c index f31ed679..a7a68e9b 100644 --- a/swaylock/main.c +++ b/swaylock/main.c @@ -111,12 +111,27 @@ static void create_layer_surface(struct swaylock_surface *surface) { wl_surface_commit(surface->surface); } +static bool image_is_opaque(cairo_surface_t *image) { + return cairo_surface_get_content(image) == CAIRO_CONTENT_COLOR; +} + static void layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *layer_surface, uint32_t serial, uint32_t width, uint32_t height) { struct swaylock_surface *surface = data; surface->width = width; surface->height = height; + + if (image_is_opaque(surface->image) && + surface->state->args.mode != BACKGROUND_MODE_CENTER && + surface->state->args.mode != BACKGROUND_MODE_FIT) { + struct wl_region *region = + wl_compositor_create_region(surface->state->compositor); + wl_region_add(region, 0, 0, width, height); + wl_surface_set_opaque_region(surface->surface, region); + wl_region_destroy(region); + } + zwlr_layer_surface_v1_ack_configure(layer_surface, serial); render_frame(surface); } From f1fadef923ef8b1278bf2e380ab639f32c0cf79b Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 3 Jul 2018 18:14:46 +1000 Subject: [PATCH 3/7] Use pixman_region32_contains_rectangle --- sway/desktop/output.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a6b2ebc2..fa85d260 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -930,16 +930,13 @@ bool output_has_opaque_lockscreen(struct sway_output *output, if (wlr_surface->resource->client != seat->exclusive_client) { continue; } - int nrects; - pixman_box32_t *rects = - pixman_region32_rectangles(&wlr_surface->current->opaque, &nrects); - for (int i = 0; i < nrects; ++i) { - pixman_box32_t *rect = &rects[i]; - if (rect->x1 <= 0 && rect->y1 <= 0 && - rect->x2 >= output->swayc->current.swayc_width && - rect->y2 >= output->swayc->current.swayc_height) { - return true; - } + pixman_box32_t output_box = { + .x2 = output->swayc->current.swayc_width, + .y2 = output->swayc->current.swayc_height, + }; + if (pixman_region32_contains_rectangle(&wlr_surface->current->opaque, + &output_box)) { + return true; } } return false; From 58b2c8ed142ded772382ae7811a217a5590b0c1c Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 3 Jul 2018 18:15:02 +1000 Subject: [PATCH 4/7] Use infinite opaque region in swaylock --- swaylock/main.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/swaylock/main.c b/swaylock/main.c index a7a68e9b..a2a8a36e 100644 --- a/swaylock/main.c +++ b/swaylock/main.c @@ -84,6 +84,10 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener; static cairo_surface_t *select_image(struct swaylock_state *state, struct swaylock_surface *surface); +static bool image_is_opaque(cairo_surface_t *image) { + return cairo_surface_get_content(image) == CAIRO_CONTENT_COLOR; +} + static void create_layer_surface(struct swaylock_surface *surface) { struct swaylock_state *state = surface->state; @@ -108,30 +112,26 @@ static void create_layer_surface(struct swaylock_surface *surface) { surface->layer_surface, true); zwlr_layer_surface_v1_add_listener(surface->layer_surface, &layer_surface_listener, surface); - wl_surface_commit(surface->surface); -} - -static bool image_is_opaque(cairo_surface_t *image) { - return cairo_surface_get_content(image) == CAIRO_CONTENT_COLOR; -} - -static void layer_surface_configure(void *data, - struct zwlr_layer_surface_v1 *layer_surface, - uint32_t serial, uint32_t width, uint32_t height) { - struct swaylock_surface *surface = data; - surface->width = width; - surface->height = height; if (image_is_opaque(surface->image) && surface->state->args.mode != BACKGROUND_MODE_CENTER && surface->state->args.mode != BACKGROUND_MODE_FIT) { struct wl_region *region = wl_compositor_create_region(surface->state->compositor); - wl_region_add(region, 0, 0, width, height); + wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX); wl_surface_set_opaque_region(surface->surface, region); wl_region_destroy(region); } + wl_surface_commit(surface->surface); +} + +static void layer_surface_configure(void *data, + struct zwlr_layer_surface_v1 *layer_surface, + uint32_t serial, uint32_t width, uint32_t height) { + struct swaylock_surface *surface = data; + surface->width = width; + surface->height = height; zwlr_layer_surface_v1_ack_configure(layer_surface, serial); render_frame(surface); } From 3b842f4eed7276f44b0a9154976ecfeef07aa867 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 00:17:08 +1000 Subject: [PATCH 5/7] Detect opaque lockscreen when using a solid color --- sway/desktop/output.c | 2 +- swaylock/main.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index fa85d260..329632b6 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -934,7 +934,7 @@ bool output_has_opaque_lockscreen(struct sway_output *output, .x2 = output->swayc->current.swayc_width, .y2 = output->swayc->current.swayc_height, }; - if (pixman_region32_contains_rectangle(&wlr_surface->current->opaque, + if (pixman_region32_contains_rectangle(&wlr_surface->current.opaque, &output_box)) { return true; } diff --git a/swaylock/main.c b/swaylock/main.c index a2a8a36e..1c0cef2b 100644 --- a/swaylock/main.c +++ b/swaylock/main.c @@ -84,8 +84,11 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener; static cairo_surface_t *select_image(struct swaylock_state *state, struct swaylock_surface *surface); -static bool image_is_opaque(cairo_surface_t *image) { - return cairo_surface_get_content(image) == CAIRO_CONTENT_COLOR; +static bool surface_is_opaque(struct swaylock_surface *surface) { + if (surface->image) { + return cairo_surface_get_content(surface->image) == CAIRO_CONTENT_COLOR; + } + return (surface->state->args.color & 0xff) == 0xff; } static void create_layer_surface(struct swaylock_surface *surface) { @@ -113,7 +116,7 @@ static void create_layer_surface(struct swaylock_surface *surface) { zwlr_layer_surface_v1_add_listener(surface->layer_surface, &layer_surface_listener, surface); - if (image_is_opaque(surface->image) && + if (surface_is_opaque(surface) && surface->state->args.mode != BACKGROUND_MODE_CENTER && surface->state->args.mode != BACKGROUND_MODE_FIT) { struct wl_region *region = From 948078122932a9782bbf1042356b62099b0cd25f Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 00:21:39 +1000 Subject: [PATCH 6/7] Don't clear when using opaque lockscreen --- sway/desktop/output.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 329632b6..3c34040b 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -978,15 +978,6 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_seat *seat = input_manager_current_seat(input_manager); if (output_has_opaque_lockscreen(output, seat)) { - float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - struct wlr_layer_surface *wlr_layer_surface = seat->focused_layer; struct sway_layer_surface *sway_layer_surface = layer_from_wlr_layer_surface(seat->focused_layer); From 464d4d58892597f31da3fcdbcfcd7928643a9ec3 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 7 Jul 2018 01:18:54 +1000 Subject: [PATCH 7/7] Translate surface by its geo when doing opaque box check --- sway/desktop/output.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3c34040b..e5a42db0 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -930,12 +930,21 @@ bool output_has_opaque_lockscreen(struct sway_output *output, if (wlr_surface->resource->client != seat->exclusive_client) { continue; } + struct sway_layer_surface *sway_layer_surface = + layer_from_wlr_layer_surface(wlr_layer_surface); pixman_box32_t output_box = { .x2 = output->swayc->current.swayc_width, .y2 = output->swayc->current.swayc_height, }; - if (pixman_region32_contains_rectangle(&wlr_surface->current.opaque, - &output_box)) { + pixman_region32_t surface_opaque_box; + pixman_region32_init(&surface_opaque_box); + pixman_region32_copy(&surface_opaque_box, &wlr_surface->current.opaque); + pixman_region32_translate(&surface_opaque_box, + sway_layer_surface->geo.x, sway_layer_surface->geo.y); + bool contains = pixman_region32_contains_rectangle( + &wlr_surface->current.opaque, &output_box); + pixman_region32_fini(&surface_opaque_box); + if (contains) { return true; } }