From c4382470e6b43f8f1105de1a70be8d67c0effb66 Mon Sep 17 00:00:00 2001 From: Igor Kolokolnikov Date: Sat, 12 Sep 2026 20:40:10 -0700 Subject: [PATCH] Tidying up. --- config.h | 10 +- helpers.h | 13 +++ slock.c | 344 +++++++++++++++++++++++++++++++++--------------------- 3 files changed, 227 insertions(+), 140 deletions(-) create mode 100644 helpers.h diff --git a/config.h b/config.h index d2a6588..ec1a393 100644 --- a/config.h +++ b/config.h @@ -3,13 +3,11 @@ static const char *user = ""; static const char *group = ""; +#if !DEBUG static const int displaytimeout = 5; /* 0 to disable */ - -static const char *colorname[NUMCOLS] = { - [INIT] = "black", /* after initialization */ - [INPUT] = "#005577", /* during input */ - [FAILED] = "#CC3333", /* wrong password */ -}; +#else +static const int displaytimeout = 0; +#endif /* treat a cleared input like a wrong password (color) */ static const int failonclear = 1; diff --git a/helpers.h b/helpers.h new file mode 100644 index 0000000..6535624 --- /dev/null +++ b/helpers.h @@ -0,0 +1,13 @@ +#ifndef HELPERS_SENTRY +#define HELPERS_SENTRY + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) + +#define KB(n) (((unsigned long long)(n)) << 10) +#define MB(n) (((unsigned long long)(n)) << 20) +#define GB(n) (((unsigned long long)(n)) << 30) +#define TB(n) (((unsigned long long)(n)) << 40) + +#define SWAP(T, a, b) do { T t__ = a; a = b; b = t__; } while(0) + +#endif diff --git a/slock.c b/slock.c index c4bc479..49da1d3 100644 --- a/slock.c +++ b/slock.c @@ -15,6 +15,8 @@ #include #include #include +#include /* roundf */ +#include /* mmap */ #include /* timerfd_create */ #include #include @@ -24,12 +26,19 @@ #include #include +#ifdef __linux__ +#include +#include + #include #include FT_FREETYPE_H #include "main_font.h" #include "secondary_font.h" +#include "helpers.h" +#include "arena_allocator.h" + #include "arg.h" #include "util.h" @@ -100,6 +109,12 @@ die(const char *errstr, ...) exit(1); } +int round_float_to_int(float real32) +{ + int result = (int)roundf(real32); + return result; +} + int str_len(const char *str) { int i = 0; @@ -109,10 +124,12 @@ int str_len(const char *str) return i; } -/* TODO: Move to top. */ -#ifdef __linux__ -#include -#include +unsigned long long millis() +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (unsigned long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; +} XRRScreenResources *crtcres = 0; static int crtccount = 0; @@ -121,7 +138,6 @@ static XRRCrtcInfo *crtcinfos[16]; void update_crtc_infos(Display *dpy) { if(crtcres) { - /* TODO: Turn on displays here first? */ int i; for(i = 0; i < crtccount; i++) { XRRFreeCrtcInfo(crtcinfos[i]); @@ -253,20 +269,38 @@ gethash(void) return hash; } -struct game_offscreen_buffer { /* TODO: REMOVE! */ - /* Pixels are always 32-bit and have the bytes in BGRX (little-endian). */ - void *memory; - int width; - int height; - int bytes_per_pixel; - int pitch; +/* TODO: Optimize. */ +struct fonts { + FT_Library main_library; + FT_Face main_face; + + FT_Library secondary_library; + FT_Face secondary_face; }; -#include -int round_float_to_int(float real32) +static int load_fonts(struct fonts *fonts) { - int result = (int)roundf(real32); - return result; + if(FT_Init_FreeType(&fonts->main_library) != 0) + return 0; + + if(FT_New_Memory_Face(fonts->main_library, + main_ttf, main_ttf_len, + 0, &fonts->main_face) != 0) + { + return 0; + } + + if(FT_Init_FreeType(&fonts->secondary_library) != 0) + return 0; + + if(FT_New_Memory_Face(fonts->secondary_library, + secondary_ttf, secondary_ttf_len, + 0, &fonts->secondary_face) != 0) + { + return 0; + } + + return 1; } static void clear_background(void *memory, int width, int height, int color) @@ -331,12 +365,6 @@ draw_glyph(void *memory, int width, int height, int bytes_per_pixel, float a, r, g, b, sa, sr, sg, sb, da, dr, dg, db, ar; - /* TODO: This should be replaced by premultiplied alpha. */ - a = (1.0f-ar)*da + ar*sa; - r = (1.0f-ar)*dr + ar*sr; - g = (1.0f-ar)*dg + ar*sg; - b = (1.0f-ar)*db + ar*sb; - gray = source[mx]; source_pixel = (gray << 24) | (gray << 16) | (gray << 8) | gray; @@ -366,7 +394,6 @@ draw_glyph(void *memory, int width, int height, int bytes_per_pixel, } } -/* TODO: Must not crash on error! */ static void draw_string(void *buffer, int width, int height, const char *str, FT_Face face, int x, int y) @@ -388,12 +415,12 @@ draw_string(void *buffer, int width, int height, error = FT_Load_Glyph(face, glyph_index, 0); if(error) - die("slock: FT_Set_Pixel_Sizes\n"); + break; if(face->glyph->format != FT_GLYPH_FORMAT_BITMAP) { error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); if(error) - die("slock: FT_Set_Pixel_Sizes\n"); + break; } draw_glyph(buffer, width, height, 4, face, start_x, start_y); @@ -403,16 +430,16 @@ draw_string(void *buffer, int width, int height, } } -/* TODO: Must not crash on error! */ static void get_string_dimension(int *width, int *height, const char *str, FT_Face face) { int str_length, start_x, start_y, i, error; + int result_width, result_height; str_length = str_len(str); - int result_width = 0; - int result_height = 0; + result_width = 0; + result_height = 0; for(i = 0; i < str_length; i++) { char character = str[i]; @@ -424,12 +451,12 @@ get_string_dimension(int *width, int *height, const char *str, FT_Face face) error = FT_Load_Glyph(face, glyph_index, 0); if(error) - die("slock: FT_Set_Pixel_Sizes\n"); + break; if(face->glyph->format != FT_GLYPH_FORMAT_BITMAP) { error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); if(error) - die("slock: FT_Set_Pixel_Sizes\n"); + break; } result_width += face->glyph->bitmap.width; @@ -442,66 +469,84 @@ get_string_dimension(int *width, int *height, const char *str, FT_Face face) *height = result_height; } +static void get_time_str(char *buffer, int buffer_size) +{ + time_t now; + struct tm *tm_info; + char *time_str; + + now = time(0); + tm_info = localtime(&now); + strftime(buffer, buffer_size, "%H:%M", tm_info); +} + +/* TODO: We are relying heavily on locks[0], is there a guarantee that it is + * going to be the main screen? */ static void -render_screen(Display *dpy, struct lock **locks, +render_screen(struct arena *arena, + Display *dpy, struct lock **locks, FT_Face main_font_face, FT_Face secondary_font_face, unsigned int pass_len) { - int error; - - error = 0; - - /* TODO: Do not free the pixel buffer. */ XWindowAttributes attrs; if(XGetWindowAttributes(dpy, locks[0]->win, &attrs)) { - int width = attrs.width; - int height = attrs.height; - int depth = DefaultDepth(dpy, 0); + int width, height, depth; + struct arena temp_arena; + void *data; + char *time_str; + int time_str_len; + + width = attrs.width; + height = attrs.height; + depth = DefaultDepth(dpy, 0); + + temp_arena = temp_arena_begin(arena); Visual *visual = DefaultVisual(dpy, 0); GC gc = XCreateGC(dpy, locks[0]->win, 0, NULL); - void *data = malloc(width * height * 4); + data = arena_alloc(&temp_arena, width * height * 4); XImage *img = XCreateImage(dpy, visual, depth, ZPixmap, 0, - data, width, height, 32, 0); + data, width, height, 32, 0); clear_background(data, width, height, 0); - time_t now = time(NULL); - struct tm *tm_info = localtime(&now); - char time[64]; - strftime(time, sizeof(time), "%H:%M", tm_info); - - FT_Set_Pixel_Sizes(main_font_face, 0, 200); - if(!error) { + time_str_len = 64; + time_str = (char *)arena_alloc(&temp_arena, time_str_len); + get_time_str(time_str, time_str_len); + if(FT_Set_Pixel_Sizes(main_font_face, 0, 200) == 0) { int mwidth, mheight; - get_string_dimension(&mwidth, &mheight, time, main_font_face); + get_string_dimension(&mwidth, &mheight, time_str, main_font_face); draw_string(data, width, height, - time, + time_str, main_font_face, width/2-mwidth/2, height/4+mheight/2); } - error = FT_Set_Pixel_Sizes(secondary_font_face, 0, 30); - if(!error) { - char message[16] = ""; - if(pass_len > 0) { - message[0] = '\0'; + if(FT_Set_Pixel_Sizes(secondary_font_face, 0, 30) == 0) { + int mwidth, mheight; + char *message_str; + int message_str_len; + + message_str_len = 32; + message_str = (char *)arena_alloc(&temp_arena, message_str_len); + memset(message_str, 0, message_str_len); + if(pass_len > 0) { unsigned int i; - for(i = 0; i < 10 && i < pass_len; i++) { - message[i] = '*'; - } - message[i] = '\0'; + + message_str[0] = '\0'; + for(i = 0; i < 20 && i < pass_len; i++) + message_str[i] = '*'; + message_str[i] = '\0'; } - int mwidth, mheight; get_string_dimension(&mwidth, &mheight, - message, secondary_font_face); + message_str, secondary_font_face); draw_string(data, width, height, - message, + message_str, secondary_font_face, width/2-mwidth/2, height/2+mheight/2); } @@ -509,13 +554,71 @@ render_screen(Display *dpy, struct lock **locks, XPutImage(dpy, locks[0]->win, gc, img, 0, 0, 0, 0, width, height); XFlush(dpy); + img->data = 0; XDestroyImage(img); XFreeGC(dpy, gc); + + temp_arena_end(&temp_arena); } } +/* TODO: Optimize. */ +struct dpms_state { + Bool dpmsavailable; + CARD16 dpmspowerlevel; + BOOL dpmsstate; + CARD16 dpmsstandby, dpmssuspend, dpmsoff; +}; + +static void dpms_disable(Display *dpy, struct dpms_state *state) +{ + if(DPMSCapable(dpy) && + DPMSInfo(dpy, &state->dpmspowerlevel, &state->dpmsstate) && + DPMSGetTimeouts(dpy, + &state->dpmsstandby, + &state->dpmssuspend, + &state->dpmsoff)) + { + state->dpmsavailable = 1; + if(state->dpmsstate) + DPMSDisable(dpy); + XSync(dpy, 0); + } +} + +static void dpms_enable(Display *dpy, struct dpms_state *state) +{ + if(state->dpmsavailable && state->dpmsstate) + { + DPMSSetTimeouts(dpy, + state->dpmsstandby, + state->dpmssuspend, + state->dpmsoff); + DPMSEnable(dpy); + XSync(dpy, 0); + } +} + +static void update_timerfd(int tfd) +{ + time_t now; + struct tm tmv; + int secs_left; + struct itimerspec its; + + now = time(0); + localtime_r(&now, &tmv); + + secs_left = 60 - tmv.tm_sec; + + memset(&its, 0, sizeof(its)); + its.it_value.tv_sec = secs_left; + timerfd_settime(tfd, 0, &its, 0); +} + static void -readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, +readpw(struct arena *arena, + Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, const char *hash) { XRRScreenChangeNotifyEvent *rre; @@ -525,11 +628,10 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, struct timeval tv; KeySym ksym; XEvent ev; - - Bool dpmsavailable; - CARD16 dpmspowerlevel; - BOOL dpmsstate; - CARD16 dpmsstandby, dpmssuspend, dpmsoff; + unsigned long long last_millis; + struct dpms_state dpms_state; + struct fonts fonts; + int error; len = 0; running = 1; @@ -542,14 +644,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, update_crtc_infos(dpy); - if(DPMSCapable(dpy) && DPMSInfo(dpy, &dpmspowerlevel, &dpmsstate) && - DPMSGetTimeouts(dpy, &dpmsstandby, &dpmssuspend, &dpmsoff)) - { - dpmsavailable = 1; - if(dpmsstate) - DPMSDisable(dpy); - XSync(dpy, 0); - } + dpms_disable(dpy, &dpms_state); FT_Library main_font_library; FT_Face main_font_face; @@ -557,29 +652,15 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, FT_Library secondary_font_library; FT_Face secondary_font_face; - int error; + if(!load_fonts(&fonts)) + die("slock: load_fonts\n"); - error = FT_Init_FreeType(&main_font_library); - if(error) - die("slock: FT_Init_FreeType\n"); - - error = FT_New_Memory_Face(main_font_library, - main_ttf, main_ttf_len, - 0, &main_font_face); - if(error) - die("slock: FT_New_Memory_Face\n"); - - error = FT_Init_FreeType(&secondary_font_library); - if(error) - die("slock: FT_Init_FreeType\n"); - - error = FT_New_Memory_Face(secondary_font_library, - secondary_ttf, secondary_ttf_len, - 0, &secondary_font_face); - if(error) - die("slock: FT_New_Memory_Face\n"); - - unsigned long long count = 0; + render_screen(arena, + dpy, locks, + fonts.main_face, fonts.secondary_face, + len); + + last_millis = millis(); while(running) { fd_set fds; FD_ZERO(&fds); @@ -588,15 +669,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, XFlush(dpy); - time_t now = time(NULL); - struct tm tmv; - localtime_r(&now, &tmv); - - int secs_left = 60 - tmv.tm_sec; - - struct itimerspec its = {0}; - its.it_value.tv_sec = secs_left; - timerfd_settime(tfd, 0, &its, NULL); + update_timerfd(tfd); while(XPending(dpy)) { XNextEvent(dpy, &ev); @@ -701,16 +774,6 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, } break; } - color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT); - if (running && oldc != (int)color) { /* WARNING: Unsafe cast. */ - for (screen = 0; screen < nscreens; screen++) { - /*XSetWindowBackground(dpy, - locks[screen]->win, - locks[screen]->colors[color]);*/ - /*XClearWindow(dpy, locks[screen]->win);*/ - } - oldc = color; - } } else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) { rre = (XRRScreenChangeNotifyEvent*)&ev; for (screen = 0; screen < nscreens; screen++) { @@ -724,15 +787,24 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, XResizeWindow(dpy, locks[screen]->win, rre->width, rre->height); } - /*XClearWindow(dpy, locks[screen]->win);*/ + XClearWindow(dpy, locks[screen]->win); break; } } + } else if(ev.type == ConfigureNotify) { } else { for(screen = 0; screen < nscreens; screen++) XRaiseWindow(dpy, locks[screen]->win); } - render_screen(dpy, locks, main_font_face, secondary_font_face, len); + + /* cap redraw at roughly 30 FPS */ + if(millis() - last_millis >= 33) { + render_screen(arena, + dpy, locks, + fonts.main_face, fonts.secondary_face, + len); + last_millis = millis(); + } } int ret; @@ -748,16 +820,14 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens, set_screen_off(dpy); } else if (ret > 0 && FD_ISSET(xfd, &fds)) { } else if (ret > 0 && FD_ISSET(tfd, &fds)) { - render_screen(dpy, locks, main_font_face, secondary_font_face, len); + render_screen(arena, + dpy, locks, + fonts.main_face, fonts.secondary_face, + len); } } - if(dpmsavailable && dpmsstate) - { - DPMSSetTimeouts(dpy, dpmsstandby, dpmssuspend, dpmsoff); - DPMSEnable(dpy); - XSync(dpy, 0); - } + dpms_enable(dpy, &dpms_state); } static struct lock * @@ -776,12 +846,6 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) lock->screen = screen; lock->root = RootWindow(dpy, lock->screen); - for (i = 0; i < NUMCOLS; i++) { - XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen), - colorname[i], &color, &dummy); - lock->colors[i] = color.pixel; - } - /* init */ wa.override_redirect = 1; wa.background_pixel = lock->colors[INIT]; @@ -811,7 +875,7 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen) XMapRaised(dpy, lock->win); XSelectInput(dpy, lock->win, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | - PointerMotionMask); + PointerMotionMask | StructureNotifyMask); return lock; #else /* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */ @@ -878,6 +942,17 @@ main(int argc, char **argv) { char *username, *groupname; + unsigned long long bf_size; + void *bf; + + bf_size = GB(1); + bf = mmap(0, + bf_size, + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, + -1, 0); + if(!bf) + die("slock: mmap\n"); + ARGBEGIN { case 'v': puts("slock-"VERSION); @@ -960,7 +1035,8 @@ main(int argc, char **argv) { } /* everything is now blank. Wait for the correct password */ - readpw(dpy, &rr, locks, nscreens, hash); + struct arena arena = arena_init(bf, GB(1)); + readpw(&arena, dpy, &rr, locks, nscreens, hash); return 0; }