Merge remote-tracking branch 'upstream/master' into i3lock-color
This commit is contained in:
commit
03822cbc7e
17
CHANGELOG
17
CHANGELOG
|
@ -1,3 +1,20 @@
|
|||
2018-10-18 i3lock 2.11.1
|
||||
|
||||
• Fix dist tarball by including I3LOCK_VERSION
|
||||
|
||||
2018-10-10 i3lock 2.11
|
||||
|
||||
• Switch to autotools
|
||||
• Display an error when backspace is pressed without any input
|
||||
• Print an error when a non-PNG file is opened
|
||||
(i3lock only supports PNG files) (Thanks eplanet)
|
||||
• Don’t unnecessarily check the xcb_connect return value,
|
||||
it is known never to be NULL (Thanks SegFault42)
|
||||
• Fix memory leak when grabbing fails (Thanks karulont)
|
||||
• Respect Xft.dpi for determining the unlock indicator’s scale factor
|
||||
• Discard pending password verification attempts
|
||||
when a new password is entered (Thanks layus)
|
||||
|
||||
2017-11-25 i3lock 2.10
|
||||
|
||||
• Only use -lpam when not on OpenBSD (Thanks Kaashif)
|
||||
|
|
|
@ -67,4 +67,9 @@ EXTRA_DIST = \
|
|||
$(pamd_files) \
|
||||
CHANGELOG \
|
||||
LICENSE \
|
||||
README.md
|
||||
README.md \
|
||||
I3LOCK_VERSION
|
||||
|
||||
# SUID the executable so it has permissions to lock TTY switching
|
||||
install-exec-hook:
|
||||
chmod +s $(DESTDIR)$(bindir)/i3lock$(EXEEXT)
|
||||
|
|
21
README.md
21
README.md
|
@ -101,6 +101,27 @@ A [sample script](https://github.com/PandorasFox/i3lock-color/blob/master/lock.s
|
|||
On OpenBSD the `i3lock` binary needs to be setgid `auth` to call the
|
||||
authentication helpers, e.g. `/usr/libexec/auth/login_passwd`.
|
||||
|
||||
Building i3lock
|
||||
---------------
|
||||
We recommend you use the provided package from your distribution. Do not build
|
||||
i3lock unless you have a reason to do so.
|
||||
|
||||
First install the dependencies listed in requirements section, then run these
|
||||
commands (might need to be adapted to your OS):
|
||||
```
|
||||
autoreconf --force --install
|
||||
|
||||
rm -rf build/
|
||||
mkdir -p build && cd build/
|
||||
|
||||
../configure \
|
||||
--prefix=/usr \
|
||||
--sysconfdir=/etc \
|
||||
--disable-sanitizers
|
||||
|
||||
make
|
||||
```
|
||||
|
||||
Upstream
|
||||
--------
|
||||
Please submit pull requests for i3lock things to https://github.com/i3/i3lock and pull requests for features to me here at https://github.com/PandorasFox/i3lock-color.
|
||||
|
|
15
i3lock.1
15
i3lock.1
|
@ -29,6 +29,7 @@ i3lock-color \- improved screen locker
|
|||
.RB [\|\-e\|]
|
||||
.RB [\|\-f\|]
|
||||
.RB [\|\-m\|]
|
||||
.RB [\|\-l\|]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B i3lock-color
|
||||
|
@ -74,6 +75,16 @@ verified or whether it is wrong).
|
|||
.BI \-i\ path \fR,\ \fB\-\-image= path
|
||||
Display the given PNG image instead of a blank screen.
|
||||
|
||||
.TP
|
||||
.BI \fB\-\-raw= format
|
||||
Read the image given by \-\-image as a raw image instead of PNG. The argument is the image's format
|
||||
as <width>x<height>:<pixfmt>. The supported pixel formats are:
|
||||
\'native', 'rgb', 'xrgb', 'rgbx', 'bgr', 'xbgr', and 'bgrx'.
|
||||
The "native" pixel format expects a pixel as a 32-bit (4-byte) integer in
|
||||
the machine's native endianness, with the upper 8 bits unused. Red, green and blue are stored in
|
||||
the remaining bits, in that order.
|
||||
Example: \-\-raw=1920x1080:rgb
|
||||
|
||||
.TP
|
||||
.BI \-c\ rrggbb \fR,\ \fB\-\-color= rrggbb
|
||||
Turn the screen into the given color instead of white. Color must be given in 3-byte
|
||||
|
@ -106,6 +117,10 @@ your computer with the enter key.
|
|||
.B \-f, \-\-show-failed-attempts
|
||||
Show the number of failed attempts, if any.
|
||||
|
||||
.TP
|
||||
.B \-l, \-\-lock-console
|
||||
Lock the console to disable TTY switching (Linux only).
|
||||
|
||||
.TP
|
||||
.B \-\-debug
|
||||
Enables debug logging.
|
||||
|
|
225
i3lock.c
225
i3lock.c
|
@ -49,6 +49,11 @@
|
|||
#endif
|
||||
#include <xcb/xcb_aux.h>
|
||||
#include <xcb/randr.h>
|
||||
#if defined(__linux__)
|
||||
#include <fcntl.h>
|
||||
#include <linux/vt.h>
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "i3lock.h"
|
||||
#include "xcb.h"
|
||||
|
@ -553,7 +558,7 @@ static void input_done(void) {
|
|||
else if (strcmp(mod_name, XKB_MOD_NAME_NUM) == 0)
|
||||
mod_name = "Num Lock";
|
||||
else if (strcmp(mod_name, XKB_MOD_NAME_LOGO) == 0)
|
||||
mod_name = "Win";
|
||||
mod_name = "Super";
|
||||
|
||||
char *tmp;
|
||||
if (modifier_string == NULL) {
|
||||
|
@ -887,6 +892,152 @@ void handle_screen_resize(void) {
|
|||
redraw_screen();
|
||||
}
|
||||
|
||||
static ssize_t read_raw_image_native(uint32_t *dest, FILE *src, size_t width, size_t height, int pixstride) {
|
||||
ssize_t count = 0;
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
size_t n = fread(&dest[y * pixstride], 1, width * 4, src);
|
||||
count += n;
|
||||
if (n < (size_t)(width * 4))
|
||||
break;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
struct raw_pixel_format {
|
||||
int bpp;
|
||||
int red;
|
||||
int green;
|
||||
int blue;
|
||||
};
|
||||
|
||||
static ssize_t read_raw_image_fmt(uint32_t *dest, FILE *src, size_t width, size_t height, int pixstride,
|
||||
struct raw_pixel_format fmt) {
|
||||
unsigned char *buf = malloc(width * fmt.bpp);
|
||||
if (buf == NULL)
|
||||
return -1;
|
||||
|
||||
ssize_t count = 0;
|
||||
for (size_t y = 0; y < height; y++) {
|
||||
size_t n = fread(buf, 1, width * fmt.bpp, src);
|
||||
count += n;
|
||||
if (n < (size_t)(width * fmt.bpp))
|
||||
break;
|
||||
|
||||
for (size_t x = 0; x < width; ++x) {
|
||||
int idx = x * fmt.bpp;
|
||||
dest[y * pixstride + x] = 0 |
|
||||
(buf[idx + fmt.red]) << 16 |
|
||||
(buf[idx + fmt.green]) << 8 |
|
||||
(buf[idx + fmt.blue]);
|
||||
}
|
||||
}
|
||||
|
||||
free(buf);
|
||||
return count;
|
||||
}
|
||||
|
||||
// Pre-defind pixel formats (<bytes per pixel>, <red pixel>, <green pixel>, <blue pixel>)
|
||||
static const struct raw_pixel_format raw_fmt_rgb = {3, 0, 1, 2};
|
||||
static const struct raw_pixel_format raw_fmt_rgbx = {4, 0, 1, 2};
|
||||
static const struct raw_pixel_format raw_fmt_xrgb = {4, 1, 2, 3};
|
||||
static const struct raw_pixel_format raw_fmt_bgr = {3, 2, 1, 0};
|
||||
static const struct raw_pixel_format raw_fmt_bgrx = {4, 2, 1, 0};
|
||||
static const struct raw_pixel_format raw_fmt_xbgr = {4, 3, 2, 1};
|
||||
|
||||
static cairo_surface_t *read_raw_image(const char *image_path, const char *image_raw_format) {
|
||||
cairo_surface_t *img;
|
||||
|
||||
#define RAW_PIXFMT_MAXLEN 6
|
||||
#define STRINGIFY1(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY1(x)
|
||||
/* Parse format as <width>x<height>:<pixfmt> */
|
||||
char pixfmt[RAW_PIXFMT_MAXLEN + 1];
|
||||
size_t w, h;
|
||||
const char *fmt = "%zux%zu:%" STRINGIFY(RAW_PIXFMT_MAXLEN) "s";
|
||||
if (sscanf(image_raw_format, fmt, &w, &h, pixfmt) != 3) {
|
||||
fprintf(stderr, "Invalid image format: \"%s\"\n", image_raw_format);
|
||||
return NULL;
|
||||
}
|
||||
#undef RAW_PIXFMT_MAXLEN
|
||||
#undef STRINGIFY1
|
||||
#undef STRINGIFY
|
||||
|
||||
/* Create image surface */
|
||||
img = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
|
||||
if (cairo_surface_status(img) != CAIRO_STATUS_SUCCESS) {
|
||||
fprintf(stderr, "Could not create surface: %s\n",
|
||||
cairo_status_to_string(cairo_surface_status(img)));
|
||||
return NULL;
|
||||
}
|
||||
cairo_surface_flush(img);
|
||||
|
||||
/* Use uint32_t* because cairo uses native endianness */
|
||||
uint32_t *data = (uint32_t *)cairo_image_surface_get_data(img);
|
||||
const int pixstride = cairo_image_surface_get_stride(img) / 4;
|
||||
|
||||
FILE *f = fopen(image_path, "r");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "Could not open image \"%s\": %s\n",
|
||||
image_path, strerror(errno));
|
||||
cairo_surface_destroy(img);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read the image, respecting cairo's stride, according to the pixfmt */
|
||||
ssize_t size, count;
|
||||
if (strcmp(pixfmt, "native") == 0) {
|
||||
/* If the pixfmt is 'native', just read each line directly into the buffer */
|
||||
size = w * h * 4;
|
||||
count = read_raw_image_native(data, f, w, h, pixstride);
|
||||
} else {
|
||||
const struct raw_pixel_format *fmt = NULL;
|
||||
|
||||
if (strcmp(pixfmt, "rgb") == 0)
|
||||
fmt = &raw_fmt_rgb;
|
||||
else if (strcmp(pixfmt, "rgbx") == 0)
|
||||
fmt = &raw_fmt_rgbx;
|
||||
else if (strcmp(pixfmt, "xrgb") == 0)
|
||||
fmt = &raw_fmt_xrgb;
|
||||
else if (strcmp(pixfmt, "bgr") == 0)
|
||||
fmt = &raw_fmt_bgr;
|
||||
else if (strcmp(pixfmt, "bgrx") == 0)
|
||||
fmt = &raw_fmt_bgrx;
|
||||
else if (strcmp(pixfmt, "xbgr") == 0)
|
||||
fmt = &raw_fmt_xbgr;
|
||||
|
||||
if (fmt == NULL) {
|
||||
fprintf(stderr, "Unknown raw pixel format: %s\n", pixfmt);
|
||||
fclose(f);
|
||||
cairo_surface_destroy(img);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = w * h * fmt->bpp;
|
||||
count = read_raw_image_fmt(data, f, w, h, pixstride, *fmt);
|
||||
}
|
||||
|
||||
cairo_surface_mark_dirty(img);
|
||||
|
||||
if (count < size) {
|
||||
if (count < 0 || ferror(f)) {
|
||||
fprintf(stderr, "Failed to read image \"%s\": %s\n",
|
||||
image_path, strerror(errno));
|
||||
fclose(f);
|
||||
cairo_surface_destroy(img);
|
||||
return NULL;
|
||||
} else {
|
||||
/* Print a warning if the file contains less data than expected,
|
||||
* but don't abort. It's useful to see how the image looks even if it's wrong. */
|
||||
fprintf(stderr, "Warning: expected to read %zi bytes from \"%s\", read %zi\n",
|
||||
size, image_path, count);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return img;
|
||||
}
|
||||
|
||||
static bool verify_png_image(const char *image_path) {
|
||||
if (!image_path) {
|
||||
return false;
|
||||
|
@ -992,7 +1143,7 @@ static void xcb_check_cb(EV_P_ ev_check *w, int revents) {
|
|||
xcb_generic_event_t *event;
|
||||
|
||||
if (xcb_connection_has_error(conn))
|
||||
errx(EXIT_FAILURE, "X11 connection broke, did your server terminate?\n");
|
||||
errx(EXIT_FAILURE, "X11 connection broke, did your server terminate?");
|
||||
|
||||
while ((event = xcb_poll_for_event(conn)) != NULL) {
|
||||
if (event->response_type == 0) {
|
||||
|
@ -1062,7 +1213,7 @@ static void raise_loop(xcb_window_t window) {
|
|||
int screens;
|
||||
|
||||
if (xcb_connection_has_error((conn = xcb_connect(NULL, &screens))) > 0)
|
||||
errx(EXIT_FAILURE, "Cannot open display\n");
|
||||
errx(EXIT_FAILURE, "Cannot open display");
|
||||
|
||||
/* We need to know about the window being obscured or getting destroyed. */
|
||||
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK,
|
||||
|
@ -1108,11 +1259,15 @@ static void raise_loop(xcb_window_t window) {
|
|||
/*
|
||||
* Loads an image from the given path. Handles JPEG and PNG. Returns NULL in case of error.
|
||||
*/
|
||||
static cairo_surface_t* load_image(char* image_path) {
|
||||
static cairo_surface_t* load_image(char* image_path, char* image_raw_format) {
|
||||
cairo_surface_t *img = NULL;
|
||||
JPEG_INFO jpg_info;
|
||||
|
||||
if (verify_png_image(image_path)) {
|
||||
if (image_raw_format != NULL && image_path != NULL) {
|
||||
/* Read image. 'read_raw_image' returns NULL on error,
|
||||
* so we don't have to handle errors here. */
|
||||
img = read_raw_image(image_path, image_raw_format);
|
||||
} else if (verify_png_image(image_path)) {
|
||||
/* Create a pixmap to render on, fill it with the background color */
|
||||
img = cairo_image_surface_create_from_png(image_path);
|
||||
} else if (file_is_jpg(image_path)) {
|
||||
|
@ -1139,7 +1294,7 @@ static cairo_surface_t* load_image(char* image_path) {
|
|||
* Loads the images from the provided directory and stores them in the pointer array
|
||||
* img_slideshow
|
||||
*/
|
||||
static void load_slideshow_images(const char *path) {
|
||||
static void load_slideshow_images(const char *path, char *image_raw_format) {
|
||||
slideshow_enabled = true;
|
||||
DIR *d;
|
||||
struct dirent *dir;
|
||||
|
@ -1161,7 +1316,7 @@ static void load_slideshow_images(const char *path) {
|
|||
strcat(path_to_image, "/");
|
||||
strcat(path_to_image, dir->d_name);
|
||||
|
||||
img_slideshow[file_count] = load_image(path_to_image);
|
||||
img_slideshow[file_count] = load_image(path_to_image, image_raw_format);
|
||||
|
||||
if (img_slideshow[file_count] != NULL) {
|
||||
++file_count;
|
||||
|
@ -1177,10 +1332,16 @@ int main(int argc, char *argv[]) {
|
|||
struct passwd *pw;
|
||||
char *username;
|
||||
char *image_path = NULL;
|
||||
char *image_raw_format = NULL;
|
||||
#ifndef __OpenBSD__
|
||||
int ret;
|
||||
struct pam_conv conv = {conv_callback, NULL};
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
bool lock_tty_switching = false;
|
||||
int term = -1;
|
||||
#endif
|
||||
|
||||
int curs_choice = CURS_NONE;
|
||||
int o;
|
||||
int longoptind = 0;
|
||||
|
@ -1195,6 +1356,7 @@ int main(int argc, char *argv[]) {
|
|||
{"help", no_argument, NULL, 'h'},
|
||||
{"no-unlock-indicator", no_argument, NULL, 'u'},
|
||||
{"image", required_argument, NULL, 'i'},
|
||||
{"raw", required_argument, NULL, 998},
|
||||
{"tiling", no_argument, NULL, 't'},
|
||||
{"ignore-empty-password", no_argument, NULL, 'e'},
|
||||
{"inactivity-timeout", required_argument, NULL, 'I'},
|
||||
|
@ -1307,14 +1469,15 @@ int main(int argc, char *argv[]) {
|
|||
{"slideshow-interval", required_argument, NULL, 903},
|
||||
{"slideshow-random-selection", no_argument, NULL, 904},
|
||||
|
||||
{"lock-console", no_argument, NULL, 'l'},
|
||||
{NULL, no_argument, NULL, 0}};
|
||||
|
||||
if ((pw = getpwuid(getuid())) == NULL)
|
||||
err(EXIT_FAILURE, "getpwuid() failed");
|
||||
if ((username = pw->pw_name) == NULL)
|
||||
errx(EXIT_FAILURE, "pw->pw_name is NULL.\n");
|
||||
errx(EXIT_FAILURE, "pw->pw_name is NULL.");
|
||||
|
||||
char *optstring = "hvnbdc:p:ui:teI:frsS:kB:m";
|
||||
char *optstring = "hvnbdc:p:ui:teI:frsS:kB:ml";
|
||||
char *arg = NULL;
|
||||
int opt = 0;
|
||||
while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) {
|
||||
|
@ -1342,7 +1505,7 @@ int main(int argc, char *argv[]) {
|
|||
arg++;
|
||||
|
||||
if (strlen(arg) != 6 || sscanf(arg, "%06[0-9a-fA-F]", color) != 1)
|
||||
errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb\n");
|
||||
errx(EXIT_FAILURE, "color is invalid, it must be given in 3-byte hexadecimal format: rrggbb");
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1361,7 +1524,7 @@ int main(int argc, char *argv[]) {
|
|||
} else if (!strcmp(optarg, "default")) {
|
||||
curs_choice = CURS_DEFAULT;
|
||||
} else {
|
||||
errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".\n");
|
||||
errx(EXIT_FAILURE, "i3lock: Invalid pointer type given. Expected one of \"win\" or \"default\".");
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
|
@ -1829,9 +1992,12 @@ int main(int argc, char *argv[]) {
|
|||
case 999:
|
||||
debug_mode = true;
|
||||
break;
|
||||
case 998:
|
||||
image_raw_format = strdup(optarg);
|
||||
break;
|
||||
default:
|
||||
errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]"
|
||||
" [-i image.png] [-t] [-e] [-f]\n"
|
||||
" [-i image.png] [-t] [-e] [-f] [-l]\n"
|
||||
"Please see the manpage for a full list of arguments.");
|
||||
}
|
||||
}
|
||||
|
@ -1957,15 +2123,17 @@ int main(int argc, char *argv[]) {
|
|||
init_colors_once();
|
||||
if (image_path != NULL) {
|
||||
if (is_regular_file(image_path)) {
|
||||
img = load_image(image_path);
|
||||
img = load_image(image_path, image_raw_format);
|
||||
} else {
|
||||
/* Path to a directory is provided -> use slideshow mode */
|
||||
load_slideshow_images(image_path);
|
||||
load_slideshow_images(image_path, image_raw_format);
|
||||
}
|
||||
|
||||
free(image_path);
|
||||
}
|
||||
|
||||
free(image_raw_format);
|
||||
|
||||
xcb_pixmap_t* blur_pixmap = NULL;
|
||||
if (blur) {
|
||||
blur_pixmap = malloc(sizeof(xcb_pixmap_t));
|
||||
|
@ -2060,7 +2228,22 @@ int main(int argc, char *argv[]) {
|
|||
/* Initialize the libev event loop. */
|
||||
main_loop = EV_DEFAULT;
|
||||
if (main_loop == NULL)
|
||||
errx(EXIT_FAILURE, "Could not initialize libev. Bad LIBEV_FLAGS?\n");
|
||||
errx(EXIT_FAILURE, "Could not initialize libev. Bad LIBEV_FLAGS?");
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
/* Lock tty switching */
|
||||
if (lock_tty_switching) {
|
||||
if ((term = open("/dev/console", O_RDWR)) == -1) {
|
||||
perror("error locking TTY switching: opening console failed");
|
||||
}
|
||||
|
||||
if (term != -1 && (ioctl(term, VT_LOCKSWITCH)) == -1) {
|
||||
perror("error locking TTY switching: locking console failed");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Explicitly call the screen redraw in case "locking…" message was displayed */
|
||||
auth_state = STATE_AUTH_IDLE;
|
||||
|
@ -2102,6 +2285,18 @@ int main(int argc, char *argv[]) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
/* Restore tty switching */
|
||||
if (lock_tty_switching) {
|
||||
if (term != -1 && (ioctl(term, VT_UNLOCKSWITCH)) == -1) {
|
||||
perror("error unlocking TTY switching: unlocking console failed");
|
||||
}
|
||||
|
||||
close(term);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DEBUG("restoring focus to X11 window 0x%08x\n", stolen_focus);
|
||||
xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
|
||||
xcb_ungrab_keyboard(conn, XCB_CURRENT_TIME);
|
||||
|
|
9
xcb.c
9
xcb.c
|
@ -182,6 +182,15 @@ xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, c
|
|||
strlen(name),
|
||||
name);
|
||||
|
||||
xcb_change_property(conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
win,
|
||||
XCB_ATOM_WM_CLASS,
|
||||
XCB_ATOM_STRING,
|
||||
8,
|
||||
2 * (strlen("i3lock") + 1),
|
||||
"i3lock\0i3lock\0");
|
||||
|
||||
/* Map the window (= make it visible) */
|
||||
xcb_map_window(conn, win);
|
||||
|
||||
|
|
Loading…
Reference in New Issue