i3lock-color

The world's most popular non-default computer lockscreen.
Index Commits Files Refs README LICENSE
commit 8bb468697c725f0947bf24c9ad9791402ede2d59
parent b386a984e57e2e94298738758ef02fc7e5b75daf
Author: BenoƮt Dardenne <benoit.dardenne@gmail.com>
Date:   Sat, 18 Apr 2020 12:37:41 +0200

Added option to display the provided image centered on all monitors

Diffstat:
Mi3lock.c | 26+++++++++++++++++++-------
Munlock_indicator.c | 55+++++++++++++++++++++++++++++++++++++++++++++++--------
Munlock_indicator.h | 1+
3 files changed, 67 insertions(+), 15 deletions(-)
diff --git 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
@@ -13,6 +13,7 @@
 #include <string.h>
 #include <math.h>
 #include <xcb/xcb.h>
+#include <xcb/randr.h>
 #include <ev.h>
 #include <cairo.h>
 #include <cairo/cairo-xcb.h>
@@ -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
@@ -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);