From 84e764a5c1e89e72094b3db8aa8e17943b867218 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sat, 9 Feb 2019 14:01:58 -0800 Subject: Multi-monitor support Use BUZZLOCKER_MONITOR_NUM to specify which monitor you want the locker to appear on. 0 is the primary one --- README.md | 4 +++ meson.build | 1 + src/main.c | 13 ++++----- src/x11_support.c | 84 ++++++++++++++++++++++++++++++++++++++++++------------- src/x11_support.h | 16 +++++++++-- 5 files changed, 88 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index db1887c..b39b6cb 100644 --- a/README.md +++ b/README.md @@ -38,4 +38,8 @@ XSECURELOCK_AUTH=/usr/local/bin/auth_buzzlocker xsecurelock So every time you run `xsecurelock` by itself, it will use buzzlocker as the GUI. +## Configuration +If you have multiple monitors, buzzlocker will appear only on whatever the primary monitor is (according +to XRandR). If you want to override this behavior, set the environment variable `BUZZLOCKER_MONITOR_NUM` +to whichever monitor you wish to have buzzlocker appear on. diff --git a/meson.build b/meson.build index 0e639c4..e74d74d 100644 --- a/meson.build +++ b/meson.build @@ -14,6 +14,7 @@ sources = [ dependencies = [ dependency('x11'), + dependency('xrandr'), dependency('cairo'), dependency('librsvg-2.0'), dependency('pangocairo'), diff --git a/src/main.c b/src/main.c index 3eebc55..82439e6 100644 --- a/src/main.c +++ b/src/main.c @@ -17,9 +17,6 @@ static const int kXSecureLockCharFD = 0; -static const int kDefaultWidth = 1024; -static const int kDefaultHeight = 768; - static const char *kDefaultFont = "Input Mono 22"; static inline saver_state_t* saver_state(void *c) @@ -326,7 +323,10 @@ static int runloop(cairo_surface_t *surface) }; schedule_animation(&state, logo_animation); - x11_get_display_bounds(&state.canvas_width, &state.canvas_height); + x11_display_bounds_t bounds; + x11_get_display_bounds(get_preferred_monitor_num(), &bounds); + state.canvas_width = bounds.width; + state.canvas_height = bounds.height; // Docs say this must be called whenever the size of the window changes cairo_xlib_surface_set_size(surface, state.canvas_width, state.canvas_height); @@ -370,10 +370,7 @@ static int runloop(cairo_surface_t *surface) int main(int argc, char **argv) { - int default_width = kDefaultWidth; - int default_height = kDefaultHeight; - - cairo_surface_t *surface = x11_helper_acquire_cairo_surface(default_width, default_height); + cairo_surface_t *surface = x11_helper_acquire_cairo_surface(); if (surface == NULL) { fprintf(stderr, "Error creating cairo surface\n"); exit(1); diff --git a/src/x11_support.c b/src/x11_support.c index 3683b5a..9f924d7 100644 --- a/src/x11_support.c +++ b/src/x11_support.c @@ -6,46 +6,89 @@ #include "x11_support.h" +#include #include #include static Window __window = { 0 }; static Display *__display = NULL; -static Window get_window_from_environment_or_make_one(Display *display, int width, int height) +static void x11_get_display_bounds_w(Window window, unsigned int monitor_num, x11_display_bounds_t *out_bounds); + +static Window get_window_from_environment_or_make_one(Display *display, int *out_width, int *out_height) { Window window; + Window root_window = DefaultRootWindow(__display); const char *env_window = getenv("XSCREENSAVER_WINDOW"); if (env_window != NULL && env_window[0] != 0) { char *endptr = NULL; unsigned long long number = strtoull(env_window, &endptr, 0); - window = (Window)number; - } else { - // Presumably this is for debugging - Window root_window = DefaultRootWindow(__display); - window = XCreateSimpleWindow( - display, // display - root_window, // parent window - 0, 0, // x, y - width, // width - height, // height - 0, // border_width - 0, // border - 0 // background - ); + root_window = (Window)number; } + // Figure out which monitor this is supposed to go on + const unsigned int preferred_monitor = get_preferred_monitor_num(); + x11_display_bounds_t bounds; + x11_get_display_bounds_w(root_window, preferred_monitor, &bounds); + + window = XCreateSimpleWindow( + display, // display + root_window, // parent window + bounds.x, // x + bounds.y, // y + bounds.width, // width + bounds.height, // height + 0, // border_width + 0, // border + 0 // background + ); + + *out_width = bounds.width; + *out_height = bounds.height; return window; } -void x11_get_display_bounds(int *width, int *height) +void x11_get_display_bounds(unsigned int monitor_num, x11_display_bounds_t *out_bounds) { - *width = DisplayWidth(__display, DefaultScreen(__display)); - *height = DisplayHeight(__display, DefaultScreen(__display)); + x11_get_display_bounds_w(__window, monitor_num, out_bounds); +} + +static void x11_get_display_bounds_w(Window window, unsigned int monitor_num, x11_display_bounds_t *out_bounds) +{ + int num_monitors = 0; + XRRMonitorInfo *monitor_infos = XRRGetMonitors(__display, window, True, &num_monitors); + if (num_monitors == 0) { + fprintf(stderr, "FATAL: Couldn't get monitor info from XRandR!\n"); + exit(1); + } + + unsigned int idx = monitor_num; + if (idx > num_monitors) { + fprintf(stderr, "WARNING: Specified monitor number is greater than the number of connected monitors!\n"); + idx = 0; + } + + XRRMonitorInfo *monitor = &monitor_infos[idx]; + out_bounds->x = monitor->x; + out_bounds->y = monitor->y; + out_bounds->width = monitor->width; + out_bounds->height = monitor->height; +} + +unsigned int get_preferred_monitor_num() +{ + const char *preferred_monitor = getenv("BUZZLOCKER_MONITOR_NUM"); + if (preferred_monitor != NULL && preferred_monitor[0] != 0) { + char *endptr = NULL; + unsigned long int result = strtoul(preferred_monitor, &endptr, 0); + return result; + } + + return 0; } -cairo_surface_t* x11_helper_acquire_cairo_surface(int width, int height) +cairo_surface_t* x11_helper_acquire_cairo_surface() { __display = XOpenDisplay(NULL); if (__display == NULL) { @@ -54,7 +97,8 @@ cairo_surface_t* x11_helper_acquire_cairo_surface(int width, int height) } // Create (or get) window - __window = get_window_from_environment_or_make_one(__display, width, height); + int width, height; + __window = get_window_from_environment_or_make_one(__display, &width, &height); // Enable key events XSelectInput(__display, __window, ButtonPressMask | KeyPressMask | StructureNotifyMask); diff --git a/src/x11_support.h b/src/x11_support.h index 6421f4b..9007602 100644 --- a/src/x11_support.h +++ b/src/x11_support.h @@ -12,10 +12,22 @@ #include #include -void x11_get_display_bounds(int *width, int *height); +typedef struct { + int x; + int y; + int width; + int height; +} x11_display_bounds_t; + +// Get the preferred monitor number (via BUZZLOCKER_MONITOR_NUM environment variable) +// Returns 0 (the primary one) if not set +unsigned int get_preferred_monitor_num(); + +// Get the bounds for the specified monitor num (via XRandR) +void x11_get_display_bounds(unsigned int monitor_num, x11_display_bounds_t *out_bounds); // Sets up a window and returns a cairo_surface to draw onto -cairo_surface_t* x11_helper_acquire_cairo_surface(int width, int height); +cairo_surface_t* x11_helper_acquire_cairo_surface(); // Cleanup void x11_helper_destroy_surface(cairo_surface_t *surface); -- cgit v1.2.3