diff --git a/i3lock.c b/i3lock.c index 3ad92f2..0cb59be 100644 --- a/i3lock.c +++ b/i3lock.c @@ -243,14 +243,13 @@ static uint8_t xkb_base_error; static int randr_base = -1; cairo_surface_t *img = NULL; -cairo_surface_t *blur_img = NULL; cairo_surface_t *img_slideshow[256]; int slideshow_image_count = 0; int slideshow_interval = 10; bool slideshow_random_selection = false; -bool tile = false; -bool centered = false; +background_type_t bg_type = NONE; + bool ignore_empty_password = false; bool skip_repeated_empty_password = false; bool pass_media_keys = false; @@ -1358,6 +1357,7 @@ static cairo_surface_t* load_image(char* image_path, char* image_raw_format) { img = cairo_image_surface_create_for_data(jpg_data, CAIRO_FORMAT_ARGB32, jpg_info.width, jpg_info.height, jpg_info.stride); + free(jpg_data); } } @@ -1435,6 +1435,9 @@ int main(int argc, char *argv[]) { {"raw", required_argument, NULL, 998}, {"tiling", no_argument, NULL, 't'}, {"centered", no_argument, NULL, 'C'}, + {"fill", no_argument, NULL, 'F'}, + {"scale", no_argument, NULL, 'L'}, + {"max", no_argument, NULL, 'M'}, {"ignore-empty-password", no_argument, NULL, 'e'}, {"inactivity-timeout", required_argument, NULL, 'I'}, {"show-failed-attempts", no_argument, NULL, 'f'}, @@ -1575,7 +1578,7 @@ int main(int argc, char *argv[]) { if (getenv("WAYLAND_DISPLAY") != NULL) errx(EXIT_FAILURE, "i3lock is a program for X11 and does not work on Wayland. Try https://github.com/swaywm/swaylock instead"); - char *optstring = "hvnbdc:p:ui:tCeI:frsS:kB:m"; + char *optstring = "hvnbdc:p:ui:tCFLMeI:frsS:kB:m"; char *arg = NULL; int opt = 0; char padded[9] = "ffffffff"; \ @@ -1624,16 +1627,34 @@ 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."); + if(bg_type != NONE) { + errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used."); } - tile = true; + bg_type = TILE; break; case 'C': - if(tile) { - errx(EXIT_FAILURE, "i3lock-color: Options tiling and centered conflict."); + if(bg_type != NONE) { + errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used."); } - centered = true; + bg_type = CENTER; + break; + case 'F': + if(bg_type != NONE) { + errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used."); + } + bg_type = FILL; + break; + case 'L': + if(bg_type != NONE) { + errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used."); + } + bg_type = SCALE; + break; + case 'M': + if(bg_type != NONE) { + errx(EXIT_FAILURE, "i3lock-color: Only one background type can be used."); + } + bg_type = MAX; break; case 'p': if (!strcmp(optarg, "win")) { @@ -2349,20 +2370,22 @@ int main(int argc, char *argv[]) { *blur_pixmap = capture_bg_pixmap(conn, screen, last_resolution); cairo_surface_t *xcb_img = cairo_xcb_surface_create(conn, *blur_pixmap, vistype, last_resolution[0], last_resolution[1]); - blur_img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, last_resolution[0], last_resolution[1]); + cairo_surface_t *blur_img = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, last_resolution[0], last_resolution[1]); cairo_t *ctx = cairo_create(blur_img); cairo_set_source_surface(ctx, xcb_img, 0, 0); cairo_paint(ctx); blur_image_surface(blur_img, blur_sigma); if (img) { - // Display image centered on all outputs. - draw_image(last_resolution, ctx); + // Display image on all outputs. + draw_image(last_resolution, img, ctx); cairo_surface_destroy(img); - img = NULL; } cairo_destroy(ctx); cairo_surface_destroy(xcb_img); + + img = blur_img; + bg_type = NONE; } xcb_window_t stolen_focus = find_focused_window(conn, screen->root); diff --git a/unlock_indicator.c b/unlock_indicator.c index eb6b768..a7e9b67 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -62,7 +62,6 @@ extern char *modifier_string; /* A Cairo surface containing the specified image (-i), if any. */ extern cairo_surface_t *img; -extern cairo_surface_t *blur_img; extern cairo_surface_t *img_slideshow[256]; extern int slideshow_image_count; extern int slideshow_interval; @@ -70,9 +69,8 @@ extern bool slideshow_random_selection; unsigned long lastCheck; -/* Whether the image should be tiled or centered. */ -extern bool centered; -extern bool tile; +/* How the background image should be displayed */ +extern background_type_t bg_type; /* The background color to use (in hex). */ extern char color[9]; /* indicator color options */ @@ -699,13 +697,8 @@ void render_lock(uint32_t *resolution, xcb_drawable_t drawable) { } } - if (blur_img || img) { - if (blur_img) { - 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 - draw_image(resolution, xcb_ctx); - } + if (img) { + draw_image(resolution, img, xcb_ctx); } else { cairo_set_source_rgba(xcb_ctx, background.red, background.green, background.blue, background.alpha); cairo_rectangle(xcb_ctx, 0, 0, resolution[0], resolution[1]); @@ -1108,54 +1101,64 @@ void render_lock(uint32_t *resolution, xcb_drawable_t drawable) { * Draws the configured image on the provided context. The image is drawn centered on all monitors, tiled, or just * painted starting from 0,0. */ -void draw_image(uint32_t* resolution, cairo_t* xcb_ctx) { - if (centered) { - double image_width = cairo_image_surface_get_width(img); - double image_height = cairo_image_surface_get_height(img); +void draw_image(uint32_t* root_resolution, cairo_surface_t *img, 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); + switch (bg_type) { + case CENTER: + case FILL: + case SCALE: + case MAX: + for (int i = 0; i < xr_screens; i++) { + cairo_save(xcb_ctx); - 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); + // Scale image according to bg_type and aspect ratios + double scale_x = 1, scale_y = 1; + if (bg_type == SCALE) { + scale_x = xr_resolutions[i].width / image_width; + scale_y = xr_resolutions[i].height / image_height; + } else { + double aspect_diff = (double) xr_resolutions[i].height / xr_resolutions[i].width - image_height / image_width; + if((bg_type == MAX && aspect_diff > 0) || (bg_type == FILL && aspect_diff < 0)) { + scale_x = scale_y = xr_resolutions[i].width / image_width; + } else if ((bg_type == MAX && aspect_diff < 0) || (bg_type == FILL && aspect_diff > 0)) { + scale_x = scale_y = xr_resolutions[i].height / image_height; + } + } - // For every output - 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 (scale_x != 0 || scale_y != 0) { + cairo_scale(xcb_ctx, scale_x, scale_y); + } - if (output->crtc == XCB_NONE || output->connection == XCB_RANDR_CONNECTION_DISCONNECTED) - continue; + // Place image in the middle + double origin_x = (xr_resolutions[i].x + xr_resolutions[i].width / 2) / scale_x - image_width / 2; + double origin_y = (xr_resolutions[i].y + xr_resolutions[i].height / 2) / scale_y - image_height / 2; - 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); + cairo_set_source_surface(xcb_ctx, img, origin_x, origin_y); + cairo_paint(xcb_ctx); - // Paint around center of monitor - 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_restore(xcb_ctx); + } + break; - cairo_set_source_surface(xcb_ctx, img, origin_x, origin_y); + case TILE: + { + /* create a pattern and fill a rectangle as big as the screen */ + cairo_pattern_t *pattern; + pattern = cairo_pattern_create_for_surface(img); + cairo_set_source(xcb_ctx, pattern); + cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); + cairo_rectangle(xcb_ctx, 0, 0, root_resolution[0], root_resolution[1]); + cairo_fill(xcb_ctx); + cairo_pattern_destroy(pattern); + break; + } + + default: + cairo_set_source_surface(xcb_ctx, img, 0, 0); cairo_paint(xcb_ctx); - - free(crtc); - free(output); - } - } 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); - cairo_set_source(xcb_ctx, pattern); - cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); - 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); + break; } } diff --git a/unlock_indicator.h b/unlock_indicator.h index 15aa905..3c07243 100644 --- a/unlock_indicator.h +++ b/unlock_indicator.h @@ -38,8 +38,17 @@ typedef struct { double bar_x, bar_y, bar_width; } DrawData; +typedef enum { + NONE, + TILE, + CENTER, + FILL, + SCALE, + MAX, +} background_type_t; + void render_lock(uint32_t* resolution, xcb_drawable_t drawable); -void draw_image(uint32_t* resolution, cairo_t* xcb_ctx); +void draw_image(uint32_t* resolution, cairo_surface_t* img, cairo_t* xcb_ctx); void init_colors_once(void); void redraw_screen(void); void clear_indicator(void);