diff --git a/i3lock.c b/i3lock.c index 893f32a..8ce8ffc 100644 --- a/i3lock.c +++ b/i3lock.c @@ -229,6 +229,7 @@ int slideshow_interval = 10; bool slideshow_random_selection = false; bool tile = false; +bool centered = false; bool ignore_empty_password = false; bool skip_repeated_empty_password = false; bool pass_media_keys = false; @@ -1379,6 +1380,7 @@ int main(int argc, char *argv[]) { {"image", required_argument, NULL, 'i'}, {"raw", required_argument, NULL, 998}, {"tiling", no_argument, NULL, 't'}, + {"centered", no_argument, NULL, 'C'}, {"ignore-empty-password", no_argument, NULL, 'e'}, {"inactivity-timeout", required_argument, NULL, 'I'}, {"show-failed-attempts", no_argument, NULL, 'f'}, @@ -1494,7 +1496,7 @@ int main(int argc, char *argv[]) { if ((username = pw->pw_name) == NULL) errx(EXIT_FAILURE, "pw->pw_name is NULL."); - char *optstring = "hvnbdc:p:ui:teI:frsS:kB:m"; + char *optstring = "hvnbdc:p:ui:tCeI:frsS:kB:m"; char *arg = NULL; int opt = 0; @@ -1534,8 +1536,17 @@ int main(int argc, char *argv[]) { image_path = strdup(optarg); break; case 't': + if(centered) { + errx(EXIT_FAILURE, "i3lock-color: Options tiling and centered conflict."); + } tile = true; break; + case 'C': + if(tile) { + errx(EXIT_FAILURE, "i3lock-color: Options tiling and centered conflict."); + } + centered = true; + break; case 'p': if (!strcmp(optarg, "win")) { curs_choice = CURS_WIN; @@ -2183,10 +2194,10 @@ int main(int argc, char *argv[]) { blur_image_surface(blur_img, blur_sigma); if (img) { - if (!tile) { - cairo_set_source_surface(ctx, img, 0, 0); - cairo_paint(ctx); - } else { + // Display image centered on all outputs. + if (centered) { + draw_on_all_outputs(ctx); + } else if (tile) { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); @@ -2195,9 +2206,10 @@ int main(int argc, char *argv[]) { cairo_rectangle(ctx, 0, 0, last_resolution[0], last_resolution[1]); cairo_fill(ctx); cairo_pattern_destroy(pattern); + } else { + cairo_set_source_surface(ctx, img, 0, 0); + cairo_paint(ctx); } - cairo_set_source_surface(ctx, img, 0, 0); - cairo_paint(ctx); cairo_surface_destroy(img); img = NULL; } diff --git a/unlock_indicator.c b/unlock_indicator.c index 82eb79b..5a46423 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -68,7 +69,8 @@ extern bool slideshow_random_selection; unsigned long lastCheck; -/* Whether the image should be tiled. */ +/* Whether the image should be tiled or centered. */ +extern bool centered; extern bool tile; /* The background color to use (in hex). */ extern char color[9]; @@ -671,9 +673,8 @@ static void draw_elements(cairo_t *const ctx, DrawData const *const draw_data) { } /* - * Draws global image with fill color onto a pixmap with the given - * resolution and returns it. - * + * Draws global image with fill color onto a provided drawable with the given + * resolution. */ void draw_image(uint32_t *resolution, xcb_drawable_t drawable) { const double scaling_factor = get_dpi_value() / 96.0; @@ -719,10 +720,10 @@ void draw_image(uint32_t *resolution, xcb_drawable_t drawable) { cairo_set_source_surface(xcb_ctx, blur_img, 0, 0); cairo_paint(xcb_ctx); } else { // img can no longer be non-NULL if blur_img is not null - if (!tile) { - cairo_set_source_surface(xcb_ctx, img, 0, 0); - cairo_paint(xcb_ctx); - } else { + if (centered) + draw_on_all_outputs(xcb_ctx); + } + else if (tile) { /* create a pattern and fill a rectangle as big as the screen */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_for_surface(img); @@ -731,6 +732,9 @@ void draw_image(uint32_t *resolution, xcb_drawable_t drawable) { cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); cairo_fill(xcb_ctx); cairo_pattern_destroy(pattern); + } else { + cairo_set_source_surface(xcb_ctx, img, 0, 0); + cairo_paint(xcb_ctx); } } } else { @@ -1064,6 +1068,41 @@ void draw_image(uint32_t *resolution, xcb_drawable_t drawable) { cairo_destroy(xcb_ctx); } +void draw_on_all_outputs(cairo_t* xcb_ctx) { + double image_width = cairo_image_surface_get_width(img); + double image_height = cairo_image_surface_get_height(img); + + xcb_randr_get_screen_resources_current_reply_t *reply = xcb_randr_get_screen_resources_current_reply( + conn, xcb_randr_get_screen_resources_current(conn, screen->root), NULL); + + xcb_timestamp_t timestamp = reply->config_timestamp; + int len = xcb_randr_get_screen_resources_current_outputs_length(reply); + xcb_randr_output_t *randr_outputs = xcb_randr_get_screen_resources_current_outputs(reply); + + for (int i = 0; i < len; i++) { + xcb_randr_get_output_info_reply_t *output = xcb_randr_get_output_info_reply( + conn, xcb_randr_get_output_info(conn, randr_outputs[i], timestamp), NULL); + if (output == NULL) + continue; + + if (output->crtc == XCB_NONE || output->connection == XCB_RANDR_CONNECTION_DISCONNECTED) + continue; + + xcb_randr_get_crtc_info_cookie_t infoCookie = xcb_randr_get_crtc_info(conn, output->crtc, + timestamp); + xcb_randr_get_crtc_info_reply_t *crtc = xcb_randr_get_crtc_info_reply(conn, infoCookie, NULL); + + double origin_x = crtc->x + (crtc->width / 2.0 - image_width / 2.0); + double origin_y = crtc->y + (crtc->height / 2.0 - image_height / 2.0); + + cairo_set_source_surface(xcb_ctx, img, origin_x, origin_y); + cairo_paint(xcb_ctx); + + free(crtc); + free(output); + } +} + /* * Calls draw_image on a new pixmap and swaps that with the current pixmap * diff --git a/unlock_indicator.h b/unlock_indicator.h index 05851d5..360e190 100644 --- a/unlock_indicator.h +++ b/unlock_indicator.h @@ -39,6 +39,7 @@ typedef struct { } DrawData; void draw_image(uint32_t* resolution, xcb_drawable_t drawable); +void draw_on_all_outputs(cairo_t* xcb_ctx); void init_colors_once(void); void redraw_screen(void); void clear_indicator(void);