aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Magahern <james@magahern.com>2019-02-09 14:01:58 -0800
committerJames Magahern <james@magahern.com>2019-02-09 14:52:45 -0800
commit84e764a5c1e89e72094b3db8aa8e17943b867218 (patch)
treee402550c5dded5a4a137e4a6a17bec8f484c4f9b
parentSlight adjustment to the screenshot (diff)
Multi-monitor support
Use BUZZLOCKER_MONITOR_NUM to specify which monitor you want the locker to appear on. 0 is the primary one
-rw-r--r--README.md4
-rw-r--r--meson.build1
-rw-r--r--src/main.c13
-rw-r--r--src/x11_support.c84
-rw-r--r--src/x11_support.h16
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 <X11/extensions/Xrandr.h>
#include <stdio.h>
#include <stdlib.h>
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 <X11/Xlib.h>
#include <X11/Xutil.h>
-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);