Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
X11:Wayland
swaylock
swaylock-1.8.0.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File swaylock-1.8.0.obscpio of Package swaylock
07070100000000000081A400000000000000000000000166C8F385000001A1000000000000000000000000000000000000001A00000000swaylock-1.8.0/.build.ymlimage: alpine/edge packages: - meson - cairo-dev - wayland-dev - wayland-protocols - libxkbcommon-dev - gdk-pixbuf-dev - linux-pam-dev - scdoc sources: - https://github.com/swaywm/swaylock tasks: - setup: | cd swaylock meson build - build: | cd swaylock ninja -C build - build-no-pam: | cd swaylock meson configure build -Dpam=disabled ninja -C build 07070100000001000081A400000000000000000000000166C8F38500000142000000000000000000000000000000000000001D00000000swaylock-1.8.0/.editorconfig# For the full list of code style requirements, see sway's CONTRIBUTING.md root = true [*] charset = utf-8 end_of_line = lf [*.{c,h,cmake,txt}] indent_style = tab indent_size = 4 [*.{xml,yml}] indent_style = space indent_size = 2 [config] indent_style = space indent_size = 4 [*.md] trim_trailing_whitespace = false 07070100000002000081A400000000000000000000000166C8F38500000006000000000000000000000000000000000000001A00000000swaylock-1.8.0/.gitignorebuild 07070100000003000081A400000000000000000000000166C8F38500000425000000000000000000000000000000000000001700000000swaylock-1.8.0/LICENSECopyright (c) 2016-2019 Drew DeVault Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 07070100000004000081A400000000000000000000000166C8F385000004DA000000000000000000000000000000000000001900000000swaylock-1.8.0/README.md# swaylock swaylock is a screen locking utility for Wayland compositors. It is compatible with any Wayland compositor which implements the ext-session-lock-v1 Wayland protocol. See the man page, [swaylock(1)](swaylock.1.scd), for instructions on using swaylock. ## Release Signatures Releases are signed with [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) and published [on GitHub](https://github.com/swaywm/swaylock/releases). swaylock releases are managed independently of sway releases. ## Installation ### From Packages Swaylock is available in many distributions. Try installing the "swaylock" package for yours. ### Compiling from Source Install dependencies: * meson \* * wayland * wayland-protocols \* * libxkbcommon * cairo * gdk-pixbuf2 \*\* * pam (optional) * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optional: man pages) \* * git \* _\* Compile-time dep_ _\*\* Optional: required for background images other than PNG_ Run these commands: meson build ninja -C build sudo ninja -C build install On systems without PAM, you need to suid the swaylock binary: sudo chmod a+s /usr/local/bin/swaylock Swaylock will drop root permissions shortly after startup. 07070100000005000081A400000000000000000000000166C8F38500001025000000000000000000000000000000000000002200000000swaylock-1.8.0/background-image.c#include <assert.h> #include "background-image.h" #include "cairo.h" #include "log.h" enum background_mode parse_background_mode(const char *mode) { if (strcmp(mode, "stretch") == 0) { return BACKGROUND_MODE_STRETCH; } else if (strcmp(mode, "fill") == 0) { return BACKGROUND_MODE_FILL; } else if (strcmp(mode, "fit") == 0) { return BACKGROUND_MODE_FIT; } else if (strcmp(mode, "center") == 0) { return BACKGROUND_MODE_CENTER; } else if (strcmp(mode, "tile") == 0) { return BACKGROUND_MODE_TILE; } else if (strcmp(mode, "solid_color") == 0) { return BACKGROUND_MODE_SOLID_COLOR; } swaylock_log(LOG_ERROR, "Unsupported background mode: %s", mode); return BACKGROUND_MODE_INVALID; } cairo_surface_t *load_background_image(const char *path) { cairo_surface_t *image; #if HAVE_GDK_PIXBUF GError *err = NULL; GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); if (!pixbuf) { swaylock_log(LOG_ERROR, "Failed to load background image (%s).", err->message); return NULL; } // Correct for embedded image orientation; typical images are not // rotated and will be handled efficiently GdkPixbuf *oriented = gdk_pixbuf_apply_embedded_orientation(pixbuf); g_object_unref(pixbuf); image = gdk_cairo_image_surface_create_from_pixbuf(oriented); g_object_unref(oriented); #else image = cairo_image_surface_create_from_png(path); #endif // HAVE_GDK_PIXBUF if (!image) { swaylock_log(LOG_ERROR, "Failed to read background image."); return NULL; } if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) { swaylock_log(LOG_ERROR, "Failed to read background image: %s." #if !HAVE_GDK_PIXBUF "\nSway was compiled without gdk_pixbuf support, so only" "\nPNG images can be loaded. This is the likely cause." #endif // !HAVE_GDK_PIXBUF , cairo_status_to_string(cairo_surface_status(image))); return NULL; } return image; } void render_background_image(cairo_t *cairo, cairo_surface_t *image, enum background_mode mode, int buffer_width, int buffer_height) { double width = cairo_image_surface_get_width(image); double height = cairo_image_surface_get_height(image); cairo_save(cairo); switch (mode) { case BACKGROUND_MODE_STRETCH: cairo_scale(cairo, (double)buffer_width / width, (double)buffer_height / height); cairo_set_source_surface(cairo, image, 0, 0); break; case BACKGROUND_MODE_FILL: { double window_ratio = (double)buffer_width / buffer_height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double)buffer_width / width; cairo_scale(cairo, scale, scale); cairo_set_source_surface(cairo, image, 0, (double)buffer_height / 2 / scale - height / 2); } else { double scale = (double)buffer_height / height; cairo_scale(cairo, scale, scale); cairo_set_source_surface(cairo, image, (double)buffer_width / 2 / scale - width / 2, 0); } break; } case BACKGROUND_MODE_FIT: { double window_ratio = (double)buffer_width / buffer_height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double)buffer_height / height; cairo_scale(cairo, scale, scale); cairo_set_source_surface(cairo, image, (double)buffer_width / 2 / scale - width / 2, 0); } else { double scale = (double)buffer_width / width; cairo_scale(cairo, scale, scale); cairo_set_source_surface(cairo, image, 0, (double)buffer_height / 2 / scale - height / 2); } break; } case BACKGROUND_MODE_CENTER: /* * Align the unscaled image to integer pixel boundaries * in order to prevent loss of clarity (this only matters * for odd-sized images). */ cairo_set_source_surface(cairo, image, (int)((double)buffer_width / 2 - width / 2), (int)((double)buffer_height / 2 - height / 2)); break; case BACKGROUND_MODE_TILE: { cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(cairo, pattern); break; } case BACKGROUND_MODE_SOLID_COLOR: case BACKGROUND_MODE_INVALID: assert(0); break; } cairo_paint(cairo); cairo_restore(cairo); } 07070100000006000081A400000000000000000000000166C8F38500000D7D000000000000000000000000000000000000001700000000swaylock-1.8.0/cairo.c#include <stdint.h> #include <cairo/cairo.h> #include "cairo.h" #if HAVE_GDK_PIXBUF #include <gdk-pixbuf/gdk-pixbuf.h> #endif void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { cairo_set_source_rgba(cairo, (color >> (3*8) & 0xFF) / 255.0, (color >> (2*8) & 0xFF) / 255.0, (color >> (1*8) & 0xFF) / 255.0, (color >> (0*8) & 0xFF) / 255.0); } cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel) { switch (subpixel) { case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: return CAIRO_SUBPIXEL_ORDER_RGB; case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: return CAIRO_SUBPIXEL_ORDER_BGR; case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: return CAIRO_SUBPIXEL_ORDER_VRGB; case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: return CAIRO_SUBPIXEL_ORDER_VBGR; default: return CAIRO_SUBPIXEL_ORDER_DEFAULT; } return CAIRO_SUBPIXEL_ORDER_DEFAULT; } #if HAVE_GDK_PIXBUF cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(const GdkPixbuf *gdkbuf) { int chan = gdk_pixbuf_get_n_channels(gdkbuf); if (chan < 3) { return NULL; } const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf); if (!gdkpix) { return NULL; } gint w = gdk_pixbuf_get_width(gdkbuf); gint h = gdk_pixbuf_get_height(gdkbuf); int stride = gdk_pixbuf_get_rowstride(gdkbuf); cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32; cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h); cairo_surface_flush (cs); if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) { return NULL; } int cstride = cairo_image_surface_get_stride(cs); unsigned char * cpix = cairo_image_surface_get_data(cs); if (chan == 3) { int i; for (i = h; i; --i) { const guint8 *gp = gdkpix; unsigned char *cp = cpix; const guint8* end = gp + 3*w; while (gp < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN cp[0] = gp[2]; cp[1] = gp[1]; cp[2] = gp[0]; #else cp[1] = gp[0]; cp[2] = gp[1]; cp[3] = gp[2]; #endif gp += 3; cp += 4; } gdkpix += stride; cpix += cstride; } } else { /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255 * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255) * = z/256 + (z/256)/255 = (z + z/255)/256 * # recurse once * = (z + (z + z/255)/256)/256 * = (z + z/256 + z/256/255) / 256 * # only use 16bit uint operations, loose some precision, * # result is floored. * -> (z + z>>8)>>8 * # add 0x80/255 = 0.5 to convert floor to round * => (z+0x80 + (z+0x80)>>8 ) >> 8 * ------ * tested as equal to lround(z/255.0) for uint z in [0..0xfe02] */ #define PREMUL_ALPHA(x,a,b,z) \ G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } \ G_STMT_END int i; for (i = h; i; --i) { const guint8 *gp = gdkpix; unsigned char *cp = cpix; const guint8* end = gp + 4*w; guint z1, z2, z3; while (gp < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN PREMUL_ALPHA(cp[0], gp[2], gp[3], z1); PREMUL_ALPHA(cp[1], gp[1], gp[3], z2); PREMUL_ALPHA(cp[2], gp[0], gp[3], z3); cp[3] = gp[3]; #else PREMUL_ALPHA(cp[1], gp[0], gp[3], z1); PREMUL_ALPHA(cp[2], gp[1], gp[3], z2); PREMUL_ALPHA(cp[3], gp[2], gp[3], z3); cp[0] = gp[3]; #endif gp += 4; cp += 4; } gdkpix += stride; cpix += cstride; } #undef PREMUL_ALPHA } cairo_surface_mark_dirty(cs); return cs; } #endif // HAVE_GDK_PIXBUF 07070100000007000081A400000000000000000000000166C8F3850000092A000000000000000000000000000000000000001600000000swaylock-1.8.0/comm.c#include <stdbool.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include "comm.h" #include "log.h" #include "swaylock.h" #include "password-buffer.h" static int comm[2][2] = {{-1, -1}, {-1, -1}}; ssize_t read_comm_request(char **buf_ptr) { size_t size; ssize_t amt; amt = read(comm[0][0], &size, sizeof(size)); if (amt == 0) { return 0; } else if (amt < 0) { swaylock_log_errno(LOG_ERROR, "read pw request"); return -1; } swaylock_log(LOG_DEBUG, "received pw check request"); char *buf = password_buffer_create(size); if (!buf) { return -1; } size_t offs = 0; do { amt = read(comm[0][0], &buf[offs], size - offs); if (amt <= 0) { swaylock_log_errno(LOG_ERROR, "failed to read pw"); return -1; } offs += (size_t)amt; } while (offs < size); *buf_ptr = buf; return size; } bool write_comm_reply(bool success) { if (write(comm[1][1], &success, sizeof(success)) != sizeof(success)) { swaylock_log_errno(LOG_ERROR, "failed to write pw check result"); return false; } return true; } bool spawn_comm_child(void) { if (pipe(comm[0]) != 0) { swaylock_log_errno(LOG_ERROR, "failed to create pipe"); return false; } if (pipe(comm[1]) != 0) { swaylock_log_errno(LOG_ERROR, "failed to create pipe"); return false; } pid_t child = fork(); if (child < 0) { swaylock_log_errno(LOG_ERROR, "failed to fork"); return false; } else if (child == 0) { close(comm[0][1]); close(comm[1][0]); run_pw_backend_child(); } close(comm[0][0]); close(comm[1][1]); return true; } bool write_comm_request(struct swaylock_password *pw) { bool result = false; size_t len = pw->len + 1; size_t offs = 0; if (write(comm[0][1], &len, sizeof(len)) < 0) { swaylock_log_errno(LOG_ERROR, "Failed to request pw check"); goto out; } do { ssize_t amt = write(comm[0][1], &pw->buffer[offs], len - offs); if (amt < 0) { swaylock_log_errno(LOG_ERROR, "Failed to write pw buffer"); goto out; } offs += amt; } while (offs < len); result = true; out: clear_password_buffer(pw); return result; } bool read_comm_reply(void) { bool result = false; if (read(comm[1][0], &result, sizeof(result)) != sizeof(result)) { swaylock_log_errno(LOG_ERROR, "Failed to read pw result"); result = false; } return result; } int get_comm_reply_fd(void) { return comm[1][0]; } 07070100000008000041ED00000000000000000000000266C8F38500000000000000000000000000000000000000000000001B00000000swaylock-1.8.0/completions07070100000009000041ED00000000000000000000000266C8F38500000000000000000000000000000000000000000000002000000000swaylock-1.8.0/completions/bash0707010000000A000081A400000000000000000000000166C8F38500000846000000000000000000000000000000000000002900000000swaylock-1.8.0/completions/bash/swaylock# swaylock(1) completion _swaylock() { local cur prev short long scaling _get_comp_words_by_ref -n : cur prev short=( -C -c -d -e -f -F -h -i -k -K -L -l -n -r -s -t -u -v ) long=( --bs-hl-color --caps-lock-bs-hl-color --caps-lock-key-hl-color --color --config --daemonize --debug --disable-caps-lock-text --font --font-size --help --hide-keyboard-layout --ignore-empty-password --image --indicator-caps-lock --indicator-idle-visible --indicator-radius --indicator-thickness --indicator-x-position --indicator-y-position --inside-caps-lock-color --inside-clear-color --inside-color --inside-ver-color --inside-wrong-color --key-hl-color --layout-bg-color --layout-border-color --layout-text-color --line-caps-lock-color --line-clear-color --line-color --line-uses-inside --line-uses-ring --line-ver-color --line-wrong-color --no-unlock-indicator --ring-caps-lock-color --ring-clear-color --ring-color --ring-ver-color --ring-wrong-color --scaling --separator-color --show-failed-attempts --show-keyboard-layout --text-caps-lock-color --text-clear-color --text-color --text-ver-color --text-wrong-color --tiling --version ) scaling=( 'stretch' 'fill' 'fit' 'center' 'tile' 'solid_color' ) case $prev in -c|--color) return ;; --scaling) COMPREPLY=($(compgen -W "${scaling[*]}" -- "$cur")) return ;; -i|--image) if grep -q : <<< "$cur"; then output="${cur%%:*}:" cur="${cur#*:}" else output= fi COMPREPLY=($(compgen -f -- "$cur")) return ;; esac if [[ $cur == --* ]]; then COMPREPLY=($(compgen -W "${long[*]}" -- "$cur")) else COMPREPLY=($(compgen -W "${short[*]}" -- "$cur")) COMPREPLY+=($(compgen -W "${long[*]}" -- "$cur")) fi } && complete -F _swaylock swaylock 0707010000000B000041ED00000000000000000000000266C8F38500000000000000000000000000000000000000000000002000000000swaylock-1.8.0/completions/fish0707010000000C000081A400000000000000000000000166C8F385000018B5000000000000000000000000000000000000002E00000000swaylock-1.8.0/completions/fish/swaylock.fish# swaylock(1) completion complete -c swaylock -l bs-hl-color --description "Sets the color of backspace highlight segments." complete -c swaylock -l caps-lock-bs-hl-color --description "Sets the color of backspace highlight segments when Caps Lock is active." complete -c swaylock -l caps-lock-key-hl-color --description "Sets the color of the key press highlight segments when Caps Lock is active." complete -c swaylock -l color -s c --description "Turn the screen into the given color instead of white." complete -c swaylock -l config -s C --description "Path to the config file." complete -c swaylock -l daemonize -s f --description "Detach from the controlling terminal after locking." complete -c swaylock -l debug -s d --description "Enable debugging output." complete -c swaylock -l disable-caps-lock-text -s L --description "Disable the Caps Lock text." complete -c swaylock -l font --description "Sets the font of the text." complete -c swaylock -l font-size --description "Sets a fixed font size for the indicator text." complete -c swaylock -l help -s h --description "Show help message and quit." complete -c swaylock -l hide-keyboard-layout -s K --description "Hide the current xkb layout while typing." complete -c swaylock -l ignore-empty-password -s e --description "When an empty password is provided, do not validate it." complete -c swaylock -l image -s i --description "Display the given image, optionally only on the given output." complete -c swaylock -l indicator-caps-lock -s l --description "Show the current Caps Lock state also on the indicator." complete -c swaylock -l indicator-idle-visible --description "Sets the indicator to show even if idle." complete -c swaylock -l indicator-radius --description "Sets the indicator radius." complete -c swaylock -l indicator-thickness --description "Sets the indicator thickness." complete -c swaylock -l indicator-x-position --description "Sets the horizontal position of the indicator." complete -c swaylock -l indicator-y-position --description "Sets the vertical position of the indicator." complete -c swaylock -l inside-caps-lock-color --description "Sets the color of the inside of the indicator when Caps Lock is active." complete -c swaylock -l inside-clear-color --description "Sets the color of the inside of the indicator when cleared." complete -c swaylock -l inside-color --description "Sets the color of the inside of the indicator." complete -c swaylock -l inside-ver-color --description "Sets the color of the inside of the indicator when verifying." complete -c swaylock -l inside-wrong-color --description "Sets the color of the inside of the indicator when invalid." complete -c swaylock -l key-hl-color --description "Sets the color of the key press highlight segments." complete -c swaylock -l layout-bg-color --description "Sets the background color of the box containing the layout text." complete -c swaylock -l layout-border-color --description "Sets the color of the border of the box containing the layout text." complete -c swaylock -l layout-text-color --description "Sets the color of the layout text." complete -c swaylock -l line-caps-lock-color --description "Sets the color of the line between the inside and ring when Caps Lock is active." complete -c swaylock -l line-clear-color --description "Sets the color of the line between the inside and ring when cleared." complete -c swaylock -l line-color --description "Sets the color of the line between the inside and ring." complete -c swaylock -l line-uses-inside -s n --description "Use the inside color for the line between the inside and ring." complete -c swaylock -l line-uses-ring -s r --description "Use the ring color for the line between the inside and ring." complete -c swaylock -l line-ver-color --description "Sets the color of the line between the inside and ring when verifying." complete -c swaylock -l line-wrong-color --description "Sets the color of the line between the inside and ring when invalid." complete -c swaylock -l no-unlock-indicator -s u --description "Disable the unlock indicator." complete -c swaylock -l ring-caps-lock-color --description "Sets the color of the ring of the indicator when Caps Lock is active." complete -c swaylock -l ring-clear-color --description "Sets the color of the ring of the indicator when cleared." complete -c swaylock -l ring-color --description "Sets the color of the ring of the indicator." complete -c swaylock -l ring-ver-color --description "Sets the color of the ring of the indicator when verifying." complete -c swaylock -l ring-wrong-color --description "Sets the color of the ring of the indicator when invalid." complete -c swaylock -l scaling -s s --description "Image scaling mode: stretch, fill, fit, center, tile, solid_color." complete -c swaylock -l separator-color --description "Sets the color of the lines that separate highlight segments." complete -c swaylock -l show-failed-attempts -s F --description "Show current count of failed authentication attempts." complete -c swaylock -l show-keyboard-layout -s k --description "Display the current xkb layout while typing." complete -c swaylock -l text-caps-lock-color --description "Sets the color of the text when Caps Lock is active." complete -c swaylock -l text-clear-color --description "Sets the color of the text when cleared." complete -c swaylock -l text-color --description "Sets the color of the text." complete -c swaylock -l text-ver-color --description "Sets the color of the text when verifying." complete -c swaylock -l text-wrong-color --description "Sets the color of the text when invalid." complete -c swaylock -l tiling -s t --description "Same as --scaling=tile." complete -c swaylock -l version -s v --description "Show the version number and quit." 0707010000000D000081A400000000000000000000000166C8F385000003A6000000000000000000000000000000000000002700000000swaylock-1.8.0/completions/meson.buildbash_comp = dependency('bash-completion', required: false) fish_comp = dependency('fish', required: false) datadir = get_option('datadir') if get_option('zsh-completions') zsh_files = files( 'zsh/_swaylock', ) zsh_install_dir = datadir + '/zsh/site-functions' install_data(zsh_files, install_dir: zsh_install_dir) endif if get_option('bash-completions') bash_files = files( 'bash/swaylock', ) if bash_comp.found() bash_install_dir = bash_comp.get_variable('completionsdir') else bash_install_dir = datadir + '/bash-completion/completions' endif install_data(bash_files, install_dir: bash_install_dir) endif if get_option('fish-completions') fish_files = files( 'fish/swaylock.fish', ) if fish_comp.found() fish_install_dir = fish_comp.get_variable('completionsdir') else fish_install_dir = datadir + '/fish/vendor_completions.d' endif install_data(fish_files, install_dir: fish_install_dir) endif 0707010000000E000041ED00000000000000000000000266C8F38500000000000000000000000000000000000000000000001F00000000swaylock-1.8.0/completions/zsh0707010000000F000081A400000000000000000000000166C8F38500001591000000000000000000000000000000000000002900000000swaylock-1.8.0/completions/zsh/_swaylock#compdef swaylock # # Completion script for swaylock # _arguments -s \ '(--bs-hl-color)'--bs-hl-color'[Sets the color of backspace highlight segments]:color:' \ '(--caps-lock-bs-hl-color)'--caps-lock-bs-hl-color'[Sets the color of backspace highlight segments when Caps Lock is active]:color:' \ '(--caps-lock-key-hl-color)'--caps-lock-key-hl-color'[Sets the color of the key press highlight segments when Caps Lock is active]:color:' \ '(--color -c)'{--color,-c}'[Turn the screen into the given color instead of white]:color:' \ '(--config -C)'{--config,-C}'[Path to the config file]:filename:_files' \ '(--daemonize -f)'{--daemonize,-f}'[Detach from the controlling terminal after locking]' \ '(--debug -d)'{--debug,-d}'[Enable debugging output]' \ '(--disable-caps-lock-text -L)'{--disable-caps-lock-text,-L}'[Disable the Caps Lock text]' \ '(--font)'--font'[Sets the font of the text]:font:' \ '(--font-size)'--font-size'[Sets a fixed font size for the indicator text]' \ '(--help -h)'{--help,-h}'[Show help message and quit]' \ '(--hide-keyboard-layout -K)'{--hide-keyboard-layout,-K}'[Hide the current xkb layout while typing]' \ '(--ignore-empty-password -e)'{--ignore-empty-password,-e}'[When an empty password is provided, do not validate it]' \ '(--image -i)'{--image,-i}'[Display the given image, optionally only on the given output]:filename:_files' \ '(--indicator-caps-lock -l)'{--indicator-caps-lock,-l}'[Show the current Caps Lock state also on the indicator]' \ '(--indicator-idle-visible)'--indicator-idle-visible'[Sets the indicator to show even if idle]' \ '(--indicator-radius)'--indicator-radius'[Sets the indicator radius]:radius:' \ '(--indicator-thickness)'--indicator-thickness'[Sets the indicator thickness]:thickness:' \ '(--indicator-x-position)'--indicator-x-position'[Sets the horizontal position of the indicator]' \ '(--indicator-y-position)'--indicator-y-position'[Sets the vertical position of the indicator]' \ '(--inside-caps-lock-color)'--inside-caps-lock-color'[Sets the color of the inside of the indicator when Caps Lock is active]:color:' \ '(--inside-clear-color)'--inside-clear-color'[Sets the color of the inside of the indicator when cleared]:color:' \ '(--inside-color)'--inside-color'[Sets the color of the inside of the indicator]:color:' \ '(--inside-ver-color)'--inside-ver-color'[Sets the color of the inside of the indicator when verifying]:color:' \ '(--inside-wrong-color)'--inside-wrong-color'[Sets the color of the inside of the indicator when invalid]:color:' \ '(--key-hl-color)'--key-hl-color'[Sets the color of the key press highlight segments]:color:' \ '(--layout-bg-color)'--layout-bg-color'[Sets the background color of the box containing the layout text]:color:' \ '(--layout-border-color)'--layout-border-color'[Sets the color of the border of the box containing the layout text]:color:' \ '(--layout-text-color)'--layout-text-color'[Sets the color of the layout text]:color:' \ '(--line-caps-lock-color)'--line-caps-lock-color'[Sets the color of the line between the inside and ring when Caps Lock is active]:color:' \ '(--line-clear-color)'--line-clear-color'[Sets the color of the line between the inside and ring when cleared]:color:' \ '(--line-color)'--line-color'[Sets the color of the line between the inside and ring]:color:' \ '(--line-uses-inside -n)'{--line-uses-inside,-n}'[Use the inside color for the line between the inside and ring]' \ '(--line-uses-ring -r)'{--line-uses-ring,-r}'[Use the ring color for the line between the inside and ring]' \ '(--line-ver-color)'--line-ver-color'[Sets the color of the line between the inside and ring when verifying]:color:' \ '(--line-wrong-color)'--line-wrong-color'[Sets the color of the line between the inside and ring when invalid]:color:' \ '(--no-unlock-indicator -u)'{--no-unlock-indicator,-u}'[Disable the unlock indicator]' \ '(--ring-caps-lock-color)'--ring-caps-lock-color'[Sets the color of the ring of the indicator when Caps Lock is active]:color:' \ '(--ring-clear-color)'--ring-clear-color'[Sets the color of the ring of the indicator when cleared]:color:' \ '(--ring-color)'--ring-color'[Sets the color of the ring of the indicator]:color:' \ '(--ring-ver-color)'--ring-ver-color'[Sets the color of the ring of the indicator when verifying]:color:' \ '(--ring-wrong-color)'--ring-wrong-color'[Sets the color of the ring of the indicator when invalid]:color:' \ '(--scaling -s)'{--scaling,-s}'[Image scaling mode: stretch, fill, fit, center, tile, solid_color]:mode:(stretch fill fit center tile solid_color)' \ '(--separator-color)'--separator-color'[Sets the color of the lines that separate highlight segments]:color:' \ '(--show-failed-attempts -F)'{--show-failed-attempts,-F}'[Show current count of failed authentication attempts]' \ '(--show-keyboard-layout -k)'{--show-keyboard-layout,-k}'[Display the current xkb layout while typing]' \ '(--text-caps-lock-color)'--text-caps-lock-color'[Sets the color of the text when Caps Lock is active]:color:' \ '(--text-clear-color)'--text-clear-color'[Sets the color of the text when cleared]:color:' \ '(--text-color)'--text-color'[Sets the color of the text]:color:' \ '(--text-ver-color)'--text-ver-color'[Sets the color of the text when verifying]:color:' \ '(--text-wrong-color)'--text-wrong-color'[Sets the color of the text when invalid]:color:' \ '(--tiling -t)'{--tiling,-t}'[Same as --scaling=tile]' \ '(--version -v)'{--version,-v}'[Show the version number and quit]' 07070100000010000041ED00000000000000000000000266C8F38500000000000000000000000000000000000000000000001700000000swaylock-1.8.0/include07070100000011000081A400000000000000000000000166C8F38500000228000000000000000000000000000000000000002A00000000swaylock-1.8.0/include/background-image.h#ifndef _SWAY_BACKGROUND_IMAGE_H #define _SWAY_BACKGROUND_IMAGE_H #include "cairo.h" enum background_mode { BACKGROUND_MODE_STRETCH, BACKGROUND_MODE_FILL, BACKGROUND_MODE_FIT, BACKGROUND_MODE_CENTER, BACKGROUND_MODE_TILE, BACKGROUND_MODE_SOLID_COLOR, BACKGROUND_MODE_INVALID, }; enum background_mode parse_background_mode(const char *mode); cairo_surface_t *load_background_image(const char *path); void render_background_image(cairo_t *cairo, cairo_surface_t *image, enum background_mode mode, int buffer_width, int buffer_height); #endif 07070100000012000081A400000000000000000000000166C8F385000001E8000000000000000000000000000000000000001F00000000swaylock-1.8.0/include/cairo.h#ifndef _SWAY_CAIRO_H #define _SWAY_CAIRO_H #include "config.h" #include <stdint.h> #include <cairo/cairo.h> #include <wayland-client.h> #if HAVE_GDK_PIXBUF #include <gdk-pixbuf/gdk-pixbuf.h> #endif void cairo_set_source_u32(cairo_t *cairo, uint32_t color); cairo_subpixel_order_t to_cairo_subpixel_order(enum wl_output_subpixel subpixel); #if HAVE_GDK_PIXBUF cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf( const GdkPixbuf *gdkbuf); #endif // HAVE_GDK_PIXBUF #endif 07070100000013000081A400000000000000000000000166C8F385000001EA000000000000000000000000000000000000001E00000000swaylock-1.8.0/include/comm.h#ifndef _SWAYLOCK_COMM_H #define _SWAYLOCK_COMM_H #include <stdbool.h> struct swaylock_password; bool spawn_comm_child(void); ssize_t read_comm_request(char **buf_ptr); bool write_comm_reply(bool success); // Requests the provided password to be checked. The password is always cleared // when the function returns. bool write_comm_request(struct swaylock_password *pw); bool read_comm_reply(void); // FD to poll for password authentication replies. int get_comm_reply_fd(void); #endif 07070100000014000081A400000000000000000000000166C8F38500000341000000000000000000000000000000000000001D00000000swaylock-1.8.0/include/log.h#ifndef _SWAYLOCK_LOG_H #define _SWAYLOCK_LOG_H #include <stdarg.h> #include <string.h> #include <errno.h> enum log_importance { LOG_SILENT = 0, LOG_ERROR = 1, LOG_INFO = 2, LOG_DEBUG = 3, LOG_IMPORTANCE_LAST, }; void swaylock_log_init(enum log_importance verbosity); #ifdef __GNUC__ #define _ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end))) #else #define _ATTRIB_PRINTF(start, end) #endif void _swaylock_log(enum log_importance verbosity, const char *format, ...) _ATTRIB_PRINTF(2, 3); const char *_swaylock_strip_path(const char *filepath); #define swaylock_log(verb, fmt, ...) \ _swaylock_log(verb, "[%s:%d] " fmt, _swaylock_strip_path(__FILE__), \ __LINE__, ##__VA_ARGS__) #define swaylock_log_errno(verb, fmt, ...) \ swaylock_log(verb, fmt ": %s", ##__VA_ARGS__, strerror(errno)) #endif 07070100000015000081A400000000000000000000000166C8F385000004BF000000000000000000000000000000000000001E00000000swaylock-1.8.0/include/loop.h#ifndef _SWAY_LOOP_H #define _SWAY_LOOP_H #include <stdbool.h> /** * This is an event loop system designed for sway clients, not sway itself. * * The loop consists of file descriptors and timers. Typically the Wayland * display's file descriptor will be one of the fds in the loop. */ struct loop; struct loop_timer; /** * Create an event loop. */ struct loop *loop_create(void); /** * Destroy the event loop (eg. on program termination). */ void loop_destroy(struct loop *loop); /** * Poll the event loop. This will block until one of the fds has data. */ void loop_poll(struct loop *loop); /** * Add a file descriptor to the loop. */ void loop_add_fd(struct loop *loop, int fd, short mask, void (*func)(int fd, short mask, void *data), void *data); /** * Add a timer to the loop. * * When the timer expires, the timer will be removed from the loop and freed. */ struct loop_timer *loop_add_timer(struct loop *loop, int ms, void (*callback)(void *data), void *data); /** * Remove a file descriptor from the loop. */ bool loop_remove_fd(struct loop *loop, int fd); /** * Remove a timer from the loop. */ bool loop_remove_timer(struct loop *loop, struct loop_timer *timer); #endif 07070100000016000081A400000000000000000000000166C8F3850000003E000000000000000000000000000000000000002300000000swaylock-1.8.0/include/meson.buildconfigure_file(output: 'config.h', configuration: conf_data) 07070100000017000081A400000000000000000000000166C8F385000000C2000000000000000000000000000000000000002900000000swaylock-1.8.0/include/password-buffer.h#ifndef _SWAY_PASSWORD_BUFFER_H #define _SWAY_PASSWORD_BUFFER_H #include <stddef.h> char *password_buffer_create(size_t size); void password_buffer_destroy(char *buffer, size_t size); #endif 07070100000018000081A400000000000000000000000166C8F38500000267000000000000000000000000000000000000002500000000swaylock-1.8.0/include/pool-buffer.h#ifndef _SWAY_BUFFERS_H #define _SWAY_BUFFERS_H #include <cairo/cairo.h> #include <stdbool.h> #include <stdint.h> #include <wayland-client.h> struct pool_buffer { struct wl_buffer *buffer; cairo_surface_t *surface; cairo_t *cairo; uint32_t width, height; void *data; size_t size; bool busy; }; struct pool_buffer *create_buffer(struct wl_shm *shm, struct pool_buffer *buf, int32_t width, int32_t height, uint32_t format); struct pool_buffer *get_next_buffer(struct wl_shm *shm, struct pool_buffer pool[static 2], uint32_t width, uint32_t height); void destroy_buffer(struct pool_buffer *buffer); #endif 07070100000019000081A400000000000000000000000166C8F38500000267000000000000000000000000000000000000001E00000000swaylock-1.8.0/include/seat.h#ifndef _SWAYLOCK_SEAT_H #define _SWAYLOCK_SEAT_H #include <xkbcommon/xkbcommon.h> #include <stdint.h> #include <stdbool.h> struct loop; struct loop_timer; struct swaylock_xkb { bool caps_lock; bool control; struct xkb_state *state; struct xkb_context *context; struct xkb_keymap *keymap; }; struct swaylock_seat { struct swaylock_state *state; struct wl_pointer *pointer; struct wl_keyboard *keyboard; int32_t repeat_period_ms; int32_t repeat_delay_ms; uint32_t repeat_sym; uint32_t repeat_codepoint; struct loop_timer *repeat_timer; }; extern const struct wl_seat_listener seat_listener; #endif 0707010000001A000081A400000000000000000000000166C8F3850000116D000000000000000000000000000000000000002200000000swaylock-1.8.0/include/swaylock.h#ifndef _SWAYLOCK_H #define _SWAYLOCK_H #include <stdbool.h> #include <stdint.h> #include <wayland-client.h> #include "background-image.h" #include "cairo.h" #include "pool-buffer.h" #include "seat.h" // Indicator state: status of authentication attempt enum auth_state { AUTH_STATE_IDLE, // nothing happening AUTH_STATE_VALIDATING, // currently validating password AUTH_STATE_INVALID, // displaying message: password was wrong }; // Indicator state: status of password buffer / typing letters enum input_state { INPUT_STATE_IDLE, // nothing happening; other states decay to this after time INPUT_STATE_CLEAR, // displaying message: password buffer was cleared INPUT_STATE_LETTER, // pressed a key that input a letter INPUT_STATE_BACKSPACE, // pressed backspace and removed a letter INPUT_STATE_NEUTRAL, // pressed a key (like Ctrl) that did nothing }; struct swaylock_colorset { uint32_t input; uint32_t cleared; uint32_t caps_lock; uint32_t verifying; uint32_t wrong; }; struct swaylock_colors { uint32_t background; uint32_t bs_highlight; uint32_t key_highlight; uint32_t caps_lock_bs_highlight; uint32_t caps_lock_key_highlight; uint32_t separator; uint32_t layout_background; uint32_t layout_border; uint32_t layout_text; struct swaylock_colorset inside; struct swaylock_colorset line; struct swaylock_colorset ring; struct swaylock_colorset text; }; struct swaylock_args { struct swaylock_colors colors; enum background_mode mode; char *font; uint32_t font_size; uint32_t radius; uint32_t thickness; uint32_t indicator_x_position; uint32_t indicator_y_position; bool override_indicator_x_position; bool override_indicator_y_position; bool ignore_empty; bool show_indicator; bool show_caps_lock_text; bool show_caps_lock_indicator; bool show_keyboard_layout; bool hide_keyboard_layout; bool show_failed_attempts; bool daemonize; int ready_fd; bool indicator_idle_visible; }; struct swaylock_password { size_t len; size_t buffer_len; char *buffer; }; struct swaylock_state { struct loop *eventloop; struct loop_timer *input_idle_timer; // timer to reset input state to IDLE struct loop_timer *auth_idle_timer; // timer to stop displaying AUTH_STATE_INVALID struct loop_timer *clear_password_timer; // clears the password buffer struct wl_display *display; struct wl_compositor *compositor; struct wl_subcompositor *subcompositor; struct wl_shm *shm; struct wl_list surfaces; struct wl_list images; struct swaylock_args args; struct swaylock_password password; struct swaylock_xkb xkb; cairo_surface_t *test_surface; cairo_t *test_cairo; // used to estimate font/text sizes enum auth_state auth_state; // state of the authentication attempt enum input_state input_state; // state of the password buffer and key inputs uint32_t highlight_start; // position of highlight; 2048 = 1 full turn int failed_attempts; bool run_display, locked; struct ext_session_lock_manager_v1 *ext_session_lock_manager_v1; struct ext_session_lock_v1 *ext_session_lock_v1; }; struct swaylock_surface { cairo_surface_t *image; struct swaylock_state *state; struct wl_output *output; uint32_t output_global_name; struct wl_surface *surface; // surface for background struct wl_surface *child; // indicator surface made into subsurface struct wl_subsurface *subsurface; struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1; struct pool_buffer indicator_buffers[2]; bool created; bool frame_pending, dirty; uint32_t width, height; int32_t scale; enum wl_output_subpixel subpixel; char *output_name; struct wl_list link; // Dimensions of last wl_buffer committed to background surface int last_buffer_width, last_buffer_height; }; // There is exactly one swaylock_image for each -i argument struct swaylock_image { char *path; char *output_name; cairo_surface_t *cairo_surface; struct wl_list link; }; void swaylock_handle_key(struct swaylock_state *state, xkb_keysym_t keysym, uint32_t codepoint); void render_frame_background(struct swaylock_surface *surface); void render_frame(struct swaylock_surface *surface); void damage_surface(struct swaylock_surface *surface); void damage_state(struct swaylock_state *state); void clear_password_buffer(struct swaylock_password *pw); void schedule_auth_idle(struct swaylock_state *state); void initialize_pw_backend(int argc, char **argv); void run_pw_backend_child(void); void clear_buffer(char *buf, size_t size); #endif 0707010000001B000081A400000000000000000000000166C8F385000003D9000000000000000000000000000000000000002100000000swaylock-1.8.0/include/unicode.h#ifndef _SWAY_UNICODE_H #define _SWAY_UNICODE_H #include <stddef.h> #include <stdint.h> // Technically UTF-8 supports up to 6 byte codepoints, but Unicode itself // doesn't really bother with more than 4. #define UTF8_MAX_SIZE 4 #define UTF8_INVALID 0x80 /** * Gets the size in bytes of the last utf8 character in a NULL terminated string * This function does not validate that the buffer contains correct utf8 data; * it merely looks for the first byte that correctly denotes the beginning of a * utf8 character. */ int utf8_last_size(const char *str); /** * Grabs the next UTF-8 character and advances the string pointer */ uint32_t utf8_decode(const char **str); /** * Encodes a character as UTF-8 and returns the length of that character. */ size_t utf8_encode(char *str, uint32_t ch); /** * Returns the size of the next UTF-8 character */ int utf8_size(const char *str); /** * Returns the size of a UTF-8 character */ size_t utf8_chsize(uint32_t ch); #endif 0707010000001C000081A400000000000000000000000166C8F3850000059A000000000000000000000000000000000000001500000000swaylock-1.8.0/log.c#define _POSIX_C_SOURCE 199506L #include <errno.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include "log.h" static enum log_importance log_importance = LOG_ERROR; static const char *verbosity_colors[] = { [LOG_SILENT] = "", [LOG_ERROR ] = "\x1B[1;31m", [LOG_INFO ] = "\x1B[1;34m", [LOG_DEBUG ] = "\x1B[1;30m", }; void swaylock_log_init(enum log_importance verbosity) { if (verbosity < LOG_IMPORTANCE_LAST) { log_importance = verbosity; } } void _swaylock_log(enum log_importance verbosity, const char *fmt, ...) { if (verbosity > log_importance) { return; } va_list args; va_start(args, fmt); // prefix the time to the log message struct tm result; time_t t = time(NULL); struct tm *tm_info = localtime_r(&t, &result); char buffer[26]; // generate time prefix strftime(buffer, sizeof(buffer), "%F %T - ", tm_info); fprintf(stderr, "%s", buffer); unsigned c = (verbosity < LOG_IMPORTANCE_LAST) ? verbosity : LOG_IMPORTANCE_LAST - 1; if (isatty(STDERR_FILENO)) { fprintf(stderr, "%s", verbosity_colors[c]); } vfprintf(stderr, fmt, args); if (isatty(STDERR_FILENO)) { fprintf(stderr, "\x1B[0m"); } fprintf(stderr, "\n"); va_end(args); } const char *_swaylock_strip_path(const char *filepath) { if (*filepath == '.') { while (*filepath == '.' || *filepath == '/') { ++filepath; } } return filepath; } 0707010000001D000081A400000000000000000000000166C8F385000013FA000000000000000000000000000000000000001600000000swaylock-1.8.0/loop.c#define _POSIX_C_SOURCE 200809L #include <limits.h> #include <string.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <poll.h> #include <time.h> #include <unistd.h> #include <wayland-client.h> #include "log.h" #include "loop.h" struct loop_fd_event { void (*callback)(int fd, short mask, void *data); void *data; struct wl_list link; // struct loop_fd_event::link }; struct loop_timer { void (*callback)(void *data); void *data; struct timespec expiry; bool removed; struct wl_list link; // struct loop_timer::link }; struct loop { struct pollfd *fds; int fd_length; int fd_capacity; struct wl_list fd_events; // struct loop_fd_event::link struct wl_list timers; // struct loop_timer::link }; struct loop *loop_create(void) { struct loop *loop = calloc(1, sizeof(struct loop)); if (!loop) { swaylock_log(LOG_ERROR, "Unable to allocate memory for loop"); return NULL; } loop->fd_capacity = 10; loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); wl_list_init(&loop->fd_events); wl_list_init(&loop->timers); return loop; } void loop_destroy(struct loop *loop) { struct loop_fd_event *event = NULL, *tmp_event = NULL; wl_list_for_each_safe(event, tmp_event, &loop->fd_events, link) { wl_list_remove(&event->link); free(event); } struct loop_timer *timer = NULL, *tmp_timer = NULL; wl_list_for_each_safe(timer, tmp_timer, &loop->timers, link) { wl_list_remove(&timer->link); free(timer); } free(loop->fds); free(loop); } void loop_poll(struct loop *loop) { // Calculate next timer in ms int ms = INT_MAX; if (!wl_list_empty(&loop->timers)) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); struct loop_timer *timer = NULL; wl_list_for_each(timer, &loop->timers, link) { int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000; timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000; if (timer_ms < ms) { ms = timer_ms; } } } if (ms < 0) { ms = 0; } int ret = poll(loop->fds, loop->fd_length, ms); if (ret < 0 && errno != EINTR) { swaylock_log_errno(LOG_ERROR, "poll failed"); exit(1); } // Dispatch fds size_t fd_index = 0; struct loop_fd_event *event = NULL; wl_list_for_each(event, &loop->fd_events, link) { struct pollfd pfd = loop->fds[fd_index]; // Always send these events unsigned events = pfd.events | POLLHUP | POLLERR; if (pfd.revents & events) { event->callback(pfd.fd, pfd.revents, event->data); } ++fd_index; } // Dispatch timers if (!wl_list_empty(&loop->timers)) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); struct loop_timer *timer = NULL, *tmp_timer = NULL; wl_list_for_each_safe(timer, tmp_timer, &loop->timers, link) { if (timer->removed) { wl_list_remove(&timer->link); free(timer); continue; } bool expired = timer->expiry.tv_sec < now.tv_sec || (timer->expiry.tv_sec == now.tv_sec && timer->expiry.tv_nsec < now.tv_nsec); if (expired) { timer->callback(timer->data); wl_list_remove(&timer->link); free(timer); } } } } void loop_add_fd(struct loop *loop, int fd, short mask, void (*callback)(int fd, short mask, void *data), void *data) { struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event)); if (!event) { swaylock_log(LOG_ERROR, "Unable to allocate memory for event"); return; } event->callback = callback; event->data = data; wl_list_insert(loop->fd_events.prev, &event->link); struct pollfd pfd = {fd, mask, 0}; if (loop->fd_length == loop->fd_capacity) { loop->fd_capacity += 10; loop->fds = realloc(loop->fds, sizeof(struct pollfd) * loop->fd_capacity); } loop->fds[loop->fd_length++] = pfd; } struct loop_timer *loop_add_timer(struct loop *loop, int ms, void (*callback)(void *data), void *data) { struct loop_timer *timer = calloc(1, sizeof(struct loop_timer)); if (!timer) { swaylock_log(LOG_ERROR, "Unable to allocate memory for timer"); return NULL; } timer->callback = callback; timer->data = data; clock_gettime(CLOCK_MONOTONIC, &timer->expiry); timer->expiry.tv_sec += ms / 1000; long int nsec = (ms % 1000) * 1000000; if (timer->expiry.tv_nsec + nsec >= 1000000000) { timer->expiry.tv_sec++; nsec -= 1000000000; } timer->expiry.tv_nsec += nsec; wl_list_insert(&loop->timers, &timer->link); return timer; } bool loop_remove_fd(struct loop *loop, int fd) { size_t fd_index = 0; struct loop_fd_event *event = NULL, *tmp_event = NULL; wl_list_for_each_safe(event, tmp_event, &loop->fd_events, link) { if (loop->fds[fd_index].fd == fd) { wl_list_remove(&event->link); free(event); loop->fd_length--; memmove(&loop->fds[fd_index], &loop->fds[fd_index + 1], sizeof(struct pollfd) * (loop->fd_length - fd_index)); return true; } ++fd_index; } return false; } bool loop_remove_timer(struct loop *loop, struct loop_timer *remove) { struct loop_timer *timer = NULL, *tmp_timer = NULL; wl_list_for_each_safe(timer, tmp_timer, &loop->timers, link) { if (timer == remove) { timer->removed = true; return true; } } return false; } 0707010000001E000081A400000000000000000000000166C8F385000092C1000000000000000000000000000000000000001600000000swaylock-1.8.0/main.c#define _POSIX_C_SOURCE 200809L #include <assert.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> #include <poll.h> #include <signal.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <sys/stat.h> #include <time.h> #include <unistd.h> #include <wayland-client.h> #include <wordexp.h> #include "background-image.h" #include "cairo.h" #include "comm.h" #include "log.h" #include "loop.h" #include "password-buffer.h" #include "pool-buffer.h" #include "seat.h" #include "swaylock.h" #include "ext-session-lock-v1-client-protocol.h" static uint32_t parse_color(const char *color) { if (color[0] == '#') { ++color; } int len = strlen(color); if (len != 6 && len != 8) { swaylock_log(LOG_DEBUG, "Invalid color %s, defaulting to 0xFFFFFFFF", color); return 0xFFFFFFFF; } uint32_t res = (uint32_t)strtoul(color, NULL, 16); if (strlen(color) == 6) { res = (res << 8) | 0xFF; } return res; } int lenient_strcmp(char *a, char *b) { if (a == b) { return 0; } else if (!a) { return -1; } else if (!b) { return 1; } else { return strcmp(a, b); } } static void daemonize(void) { int fds[2]; if (pipe(fds) != 0) { swaylock_log(LOG_ERROR, "Failed to pipe"); exit(1); } if (fork() == 0) { setsid(); close(fds[0]); int devnull = open("/dev/null", O_RDWR); dup2(STDOUT_FILENO, devnull); dup2(STDERR_FILENO, devnull); close(devnull); uint8_t success = 0; if (chdir("/") != 0) { write(fds[1], &success, 1); exit(1); } success = 1; if (write(fds[1], &success, 1) != 1) { exit(1); } close(fds[1]); } else { close(fds[1]); uint8_t success; if (read(fds[0], &success, 1) != 1 || !success) { swaylock_log(LOG_ERROR, "Failed to daemonize"); exit(1); } close(fds[0]); exit(0); } } static void destroy_surface(struct swaylock_surface *surface) { wl_list_remove(&surface->link); if (surface->ext_session_lock_surface_v1 != NULL) { ext_session_lock_surface_v1_destroy(surface->ext_session_lock_surface_v1); } if (surface->subsurface) { wl_subsurface_destroy(surface->subsurface); } if (surface->child) { wl_surface_destroy(surface->child); } if (surface->surface != NULL) { wl_surface_destroy(surface->surface); } destroy_buffer(&surface->indicator_buffers[0]); destroy_buffer(&surface->indicator_buffers[1]); wl_output_release(surface->output); free(surface); } static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener; static cairo_surface_t *select_image(struct swaylock_state *state, struct swaylock_surface *surface); static bool surface_is_opaque(struct swaylock_surface *surface) { if (surface->image) { return cairo_surface_get_content(surface->image) == CAIRO_CONTENT_COLOR; } return (surface->state->args.colors.background & 0xff) == 0xff; } static void create_surface(struct swaylock_surface *surface) { struct swaylock_state *state = surface->state; surface->image = select_image(state, surface); surface->surface = wl_compositor_create_surface(state->compositor); assert(surface->surface); surface->child = wl_compositor_create_surface(state->compositor); assert(surface->child); surface->subsurface = wl_subcompositor_get_subsurface(state->subcompositor, surface->child, surface->surface); assert(surface->subsurface); wl_subsurface_set_sync(surface->subsurface); surface->ext_session_lock_surface_v1 = ext_session_lock_v1_get_lock_surface( state->ext_session_lock_v1, surface->surface, surface->output); ext_session_lock_surface_v1_add_listener(surface->ext_session_lock_surface_v1, &ext_session_lock_surface_v1_listener, surface); if (surface_is_opaque(surface) && surface->state->args.mode != BACKGROUND_MODE_CENTER && surface->state->args.mode != BACKGROUND_MODE_FIT) { struct wl_region *region = wl_compositor_create_region(surface->state->compositor); wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX); wl_surface_set_opaque_region(surface->surface, region); wl_region_destroy(region); } surface->created = true; } static void ext_session_lock_surface_v1_handle_configure(void *data, struct ext_session_lock_surface_v1 *lock_surface, uint32_t serial, uint32_t width, uint32_t height) { struct swaylock_surface *surface = data; surface->width = width; surface->height = height; ext_session_lock_surface_v1_ack_configure(lock_surface, serial); render_frame_background(surface); render_frame(surface); } static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener = { .configure = ext_session_lock_surface_v1_handle_configure, }; static const struct wl_callback_listener surface_frame_listener; static void surface_frame_handle_done(void *data, struct wl_callback *callback, uint32_t time) { struct swaylock_surface *surface = data; wl_callback_destroy(callback); surface->frame_pending = false; if (surface->dirty) { // Schedule a frame in case the surface is damaged again struct wl_callback *callback = wl_surface_frame(surface->surface); wl_callback_add_listener(callback, &surface_frame_listener, surface); surface->frame_pending = true; render_frame(surface); surface->dirty = false; } } static const struct wl_callback_listener surface_frame_listener = { .done = surface_frame_handle_done, }; void damage_surface(struct swaylock_surface *surface) { if (surface->width == 0 || surface->height == 0) { // Not yet configured return; } surface->dirty = true; if (surface->frame_pending) { return; } struct wl_callback *callback = wl_surface_frame(surface->surface); wl_callback_add_listener(callback, &surface_frame_listener, surface); surface->frame_pending = true; wl_surface_commit(surface->surface); } void damage_state(struct swaylock_state *state) { struct swaylock_surface *surface; wl_list_for_each(surface, &state->surfaces, link) { damage_surface(surface); } } static void handle_wl_output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t width_mm, int32_t height_mm, int32_t subpixel, const char *make, const char *model, int32_t transform) { struct swaylock_surface *surface = data; surface->subpixel = subpixel; if (surface->state->run_display) { damage_surface(surface); } } static void handle_wl_output_mode(void *data, struct wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { // Who cares } static void handle_wl_output_done(void *data, struct wl_output *output) { struct swaylock_surface *surface = data; if (!surface->created && surface->state->run_display) { create_surface(surface); } } static void handle_wl_output_scale(void *data, struct wl_output *output, int32_t factor) { struct swaylock_surface *surface = data; surface->scale = factor; if (surface->state->run_display) { damage_surface(surface); } } static void handle_wl_output_name(void *data, struct wl_output *output, const char *name) { struct swaylock_surface *surface = data; surface->output_name = strdup(name); } static void handle_wl_output_description(void *data, struct wl_output *output, const char *description) { // Who cares } struct wl_output_listener _wl_output_listener = { .geometry = handle_wl_output_geometry, .mode = handle_wl_output_mode, .done = handle_wl_output_done, .scale = handle_wl_output_scale, .name = handle_wl_output_name, .description = handle_wl_output_description, }; static void ext_session_lock_v1_handle_locked(void *data, struct ext_session_lock_v1 *lock) { struct swaylock_state *state = data; state->locked = true; } static void ext_session_lock_v1_handle_finished(void *data, struct ext_session_lock_v1 *lock) { swaylock_log(LOG_ERROR, "Failed to lock session -- " "is another lockscreen running?"); exit(2); } static const struct ext_session_lock_v1_listener ext_session_lock_v1_listener = { .locked = ext_session_lock_v1_handle_locked, .finished = ext_session_lock_v1_handle_finished, }; static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { struct swaylock_state *state = data; if (strcmp(interface, wl_compositor_interface.name) == 0) { state->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4); } else if (strcmp(interface, wl_subcompositor_interface.name) == 0) { state->subcompositor = wl_registry_bind(registry, name, &wl_subcompositor_interface, 1); } else if (strcmp(interface, wl_shm_interface.name) == 0) { state->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if (strcmp(interface, wl_seat_interface.name) == 0) { struct wl_seat *seat = wl_registry_bind( registry, name, &wl_seat_interface, 4); struct swaylock_seat *swaylock_seat = calloc(1, sizeof(struct swaylock_seat)); swaylock_seat->state = state; wl_seat_add_listener(seat, &seat_listener, swaylock_seat); } else if (strcmp(interface, wl_output_interface.name) == 0) { struct swaylock_surface *surface = calloc(1, sizeof(struct swaylock_surface)); surface->state = state; surface->output = wl_registry_bind(registry, name, &wl_output_interface, 4); surface->output_global_name = name; wl_output_add_listener(surface->output, &_wl_output_listener, surface); wl_list_insert(&state->surfaces, &surface->link); } else if (strcmp(interface, ext_session_lock_manager_v1_interface.name) == 0) { state->ext_session_lock_manager_v1 = wl_registry_bind(registry, name, &ext_session_lock_manager_v1_interface, 1); } } static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { struct swaylock_state *state = data; struct swaylock_surface *surface; wl_list_for_each(surface, &state->surfaces, link) { if (surface->output_global_name == name) { destroy_surface(surface); break; } } } static const struct wl_registry_listener registry_listener = { .global = handle_global, .global_remove = handle_global_remove, }; static int sigusr_fds[2] = {-1, -1}; void do_sigusr(int sig) { (void)write(sigusr_fds[1], "1", 1); } static cairo_surface_t *select_image(struct swaylock_state *state, struct swaylock_surface *surface) { struct swaylock_image *image; cairo_surface_t *default_image = NULL; wl_list_for_each(image, &state->images, link) { if (lenient_strcmp(image->output_name, surface->output_name) == 0) { return image->cairo_surface; } else if (!image->output_name) { default_image = image->cairo_surface; } } return default_image; } static char *join_args(char **argv, int argc) { assert(argc > 0); int len = 0, i; for (i = 0; i < argc; ++i) { len += strlen(argv[i]) + 1; } char *res = malloc(len); len = 0; for (i = 0; i < argc; ++i) { strcpy(res + len, argv[i]); len += strlen(argv[i]); res[len++] = ' '; } res[len - 1] = '\0'; return res; } static void load_image(char *arg, struct swaylock_state *state) { // [[<output>]:]<path> struct swaylock_image *image = calloc(1, sizeof(struct swaylock_image)); char *separator = strchr(arg, ':'); if (separator) { *separator = '\0'; image->output_name = separator == arg ? NULL : strdup(arg); image->path = strdup(separator + 1); } else { image->output_name = NULL; image->path = strdup(arg); } struct swaylock_image *iter_image, *temp; wl_list_for_each_safe(iter_image, temp, &state->images, link) { if (lenient_strcmp(iter_image->output_name, image->output_name) == 0) { if (image->output_name) { swaylock_log(LOG_DEBUG, "Replacing image defined for output %s with %s", image->output_name, image->path); } else { swaylock_log(LOG_DEBUG, "Replacing default image with %s", image->path); } wl_list_remove(&iter_image->link); free(iter_image->cairo_surface); free(iter_image->output_name); free(iter_image->path); free(iter_image); break; } } // The shell will not expand ~ to the value of $HOME when an output name is // given. Also, any image paths given in the config file need to have shell // expansions performed wordexp_t p; while (strstr(image->path, " ")) { image->path = realloc(image->path, strlen(image->path) + 2); char *ptr = strstr(image->path, " ") + 1; memmove(ptr + 1, ptr, strlen(ptr) + 1); *ptr = '\\'; } if (wordexp(image->path, &p, 0) == 0) { free(image->path); image->path = join_args(p.we_wordv, p.we_wordc); wordfree(&p); } // Load the actual image image->cairo_surface = load_background_image(image->path); if (!image->cairo_surface) { free(image); return; } wl_list_insert(&state->images, &image->link); swaylock_log(LOG_DEBUG, "Loaded image %s for output %s", image->path, image->output_name ? image->output_name : "*"); } static void set_default_colors(struct swaylock_colors *colors) { colors->background = 0xFFFFFFFF; colors->bs_highlight = 0xDB3300FF; colors->key_highlight = 0x33DB00FF; colors->caps_lock_bs_highlight = 0xDB3300FF; colors->caps_lock_key_highlight = 0x33DB00FF; colors->separator = 0x000000FF; colors->layout_background = 0x000000C0; colors->layout_border = 0x00000000; colors->layout_text = 0xFFFFFFFF; colors->inside = (struct swaylock_colorset){ .input = 0x000000C0, .cleared = 0xE5A445C0, .caps_lock = 0x000000C0, .verifying = 0x0072FFC0, .wrong = 0xFA0000C0, }; colors->line = (struct swaylock_colorset){ .input = 0x000000FF, .cleared = 0x000000FF, .caps_lock = 0x000000FF, .verifying = 0x000000FF, .wrong = 0x000000FF, }; colors->ring = (struct swaylock_colorset){ .input = 0x337D00FF, .cleared = 0xE5A445FF, .caps_lock = 0xE5A445FF, .verifying = 0x3300FFFF, .wrong = 0x7D3300FF, }; colors->text = (struct swaylock_colorset){ .input = 0xE5A445FF, .cleared = 0x000000FF, .caps_lock = 0xE5A445FF, .verifying = 0x000000FF, .wrong = 0x000000FF, }; } enum line_mode { LM_LINE, LM_INSIDE, LM_RING, }; static int parse_options(int argc, char **argv, struct swaylock_state *state, enum line_mode *line_mode, char **config_path) { enum long_option_codes { LO_BS_HL_COLOR = 256, LO_CAPS_LOCK_BS_HL_COLOR, LO_CAPS_LOCK_KEY_HL_COLOR, LO_FONT, LO_FONT_SIZE, LO_IND_IDLE_VISIBLE, LO_IND_RADIUS, LO_IND_X_POSITION, LO_IND_Y_POSITION, LO_IND_THICKNESS, LO_INSIDE_COLOR, LO_INSIDE_CLEAR_COLOR, LO_INSIDE_CAPS_LOCK_COLOR, LO_INSIDE_VER_COLOR, LO_INSIDE_WRONG_COLOR, LO_KEY_HL_COLOR, LO_LAYOUT_TXT_COLOR, LO_LAYOUT_BG_COLOR, LO_LAYOUT_BORDER_COLOR, LO_LINE_COLOR, LO_LINE_CLEAR_COLOR, LO_LINE_CAPS_LOCK_COLOR, LO_LINE_VER_COLOR, LO_LINE_WRONG_COLOR, LO_RING_COLOR, LO_RING_CLEAR_COLOR, LO_RING_CAPS_LOCK_COLOR, LO_RING_VER_COLOR, LO_RING_WRONG_COLOR, LO_SEP_COLOR, LO_TEXT_COLOR, LO_TEXT_CLEAR_COLOR, LO_TEXT_CAPS_LOCK_COLOR, LO_TEXT_VER_COLOR, LO_TEXT_WRONG_COLOR, }; static struct option long_options[] = { {"config", required_argument, NULL, 'C'}, {"color", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, {"ignore-empty-password", no_argument, NULL, 'e'}, {"daemonize", no_argument, NULL, 'f'}, {"ready-fd", required_argument, NULL, 'R'}, {"help", no_argument, NULL, 'h'}, {"image", required_argument, NULL, 'i'}, {"disable-caps-lock-text", no_argument, NULL, 'L'}, {"indicator-caps-lock", no_argument, NULL, 'l'}, {"line-uses-inside", no_argument, NULL, 'n'}, {"line-uses-ring", no_argument, NULL, 'r'}, {"scaling", required_argument, NULL, 's'}, {"tiling", no_argument, NULL, 't'}, {"no-unlock-indicator", no_argument, NULL, 'u'}, {"show-keyboard-layout", no_argument, NULL, 'k'}, {"hide-keyboard-layout", no_argument, NULL, 'K'}, {"show-failed-attempts", no_argument, NULL, 'F'}, {"version", no_argument, NULL, 'v'}, {"bs-hl-color", required_argument, NULL, LO_BS_HL_COLOR}, {"caps-lock-bs-hl-color", required_argument, NULL, LO_CAPS_LOCK_BS_HL_COLOR}, {"caps-lock-key-hl-color", required_argument, NULL, LO_CAPS_LOCK_KEY_HL_COLOR}, {"font", required_argument, NULL, LO_FONT}, {"font-size", required_argument, NULL, LO_FONT_SIZE}, {"indicator-idle-visible", no_argument, NULL, LO_IND_IDLE_VISIBLE}, {"indicator-radius", required_argument, NULL, LO_IND_RADIUS}, {"indicator-thickness", required_argument, NULL, LO_IND_THICKNESS}, {"indicator-x-position", required_argument, NULL, LO_IND_X_POSITION}, {"indicator-y-position", required_argument, NULL, LO_IND_Y_POSITION}, {"inside-color", required_argument, NULL, LO_INSIDE_COLOR}, {"inside-clear-color", required_argument, NULL, LO_INSIDE_CLEAR_COLOR}, {"inside-caps-lock-color", required_argument, NULL, LO_INSIDE_CAPS_LOCK_COLOR}, {"inside-ver-color", required_argument, NULL, LO_INSIDE_VER_COLOR}, {"inside-wrong-color", required_argument, NULL, LO_INSIDE_WRONG_COLOR}, {"key-hl-color", required_argument, NULL, LO_KEY_HL_COLOR}, {"layout-bg-color", required_argument, NULL, LO_LAYOUT_BG_COLOR}, {"layout-border-color", required_argument, NULL, LO_LAYOUT_BORDER_COLOR}, {"layout-text-color", required_argument, NULL, LO_LAYOUT_TXT_COLOR}, {"line-color", required_argument, NULL, LO_LINE_COLOR}, {"line-clear-color", required_argument, NULL, LO_LINE_CLEAR_COLOR}, {"line-caps-lock-color", required_argument, NULL, LO_LINE_CAPS_LOCK_COLOR}, {"line-ver-color", required_argument, NULL, LO_LINE_VER_COLOR}, {"line-wrong-color", required_argument, NULL, LO_LINE_WRONG_COLOR}, {"ring-color", required_argument, NULL, LO_RING_COLOR}, {"ring-clear-color", required_argument, NULL, LO_RING_CLEAR_COLOR}, {"ring-caps-lock-color", required_argument, NULL, LO_RING_CAPS_LOCK_COLOR}, {"ring-ver-color", required_argument, NULL, LO_RING_VER_COLOR}, {"ring-wrong-color", required_argument, NULL, LO_RING_WRONG_COLOR}, {"separator-color", required_argument, NULL, LO_SEP_COLOR}, {"text-color", required_argument, NULL, LO_TEXT_COLOR}, {"text-clear-color", required_argument, NULL, LO_TEXT_CLEAR_COLOR}, {"text-caps-lock-color", required_argument, NULL, LO_TEXT_CAPS_LOCK_COLOR}, {"text-ver-color", required_argument, NULL, LO_TEXT_VER_COLOR}, {"text-wrong-color", required_argument, NULL, LO_TEXT_WRONG_COLOR}, {0, 0, 0, 0} }; const char usage[] = "Usage: swaylock [options...]\n" "\n" " -C, --config <config_file> " "Path to the config file.\n" " -c, --color <color> " "Turn the screen into the given color instead of white.\n" " -d, --debug " "Enable debugging output.\n" " -e, --ignore-empty-password " "When an empty password is provided, do not validate it.\n" " -F, --show-failed-attempts " "Show current count of failed authentication attempts.\n" " -f, --daemonize " "Detach from the controlling terminal after locking.\n" " -R, --ready-fd <fd> " "File descriptor to send readiness notifications to.\n" " -h, --help " "Show help message and quit.\n" " -i, --image [[<output>]:]<path> " "Display the given image, optionally only on the given output.\n" " -k, --show-keyboard-layout " "Display the current xkb layout while typing.\n" " -K, --hide-keyboard-layout " "Hide the current xkb layout while typing.\n" " -L, --disable-caps-lock-text " "Disable the Caps Lock text.\n" " -l, --indicator-caps-lock " "Show the current Caps Lock state also on the indicator.\n" " -s, --scaling <mode> " "Image scaling mode: stretch, fill, fit, center, tile, solid_color.\n" " -t, --tiling " "Same as --scaling=tile.\n" " -u, --no-unlock-indicator " "Disable the unlock indicator.\n" " -v, --version " "Show the version number and quit.\n" " --bs-hl-color <color> " "Sets the color of backspace highlight segments.\n" " --caps-lock-bs-hl-color <color> " "Sets the color of backspace highlight segments when Caps Lock " "is active.\n" " --caps-lock-key-hl-color <color> " "Sets the color of the key press highlight segments when " "Caps Lock is active.\n" " --font <font> " "Sets the font of the text.\n" " --font-size <size> " "Sets a fixed font size for the indicator text.\n" " --indicator-idle-visible " "Sets the indicator to show even if idle.\n" " --indicator-radius <radius> " "Sets the indicator radius.\n" " --indicator-thickness <thick> " "Sets the indicator thickness.\n" " --indicator-x-position <x> " "Sets the horizontal position of the indicator.\n" " --indicator-y-position <y> " "Sets the vertical position of the indicator.\n" " --inside-color <color> " "Sets the color of the inside of the indicator.\n" " --inside-clear-color <color> " "Sets the color of the inside of the indicator when cleared.\n" " --inside-caps-lock-color <color> " "Sets the color of the inside of the indicator when Caps Lock " "is active.\n" " --inside-ver-color <color> " "Sets the color of the inside of the indicator when verifying.\n" " --inside-wrong-color <color> " "Sets the color of the inside of the indicator when invalid.\n" " --key-hl-color <color> " "Sets the color of the key press highlight segments.\n" " --layout-bg-color <color> " "Sets the background color of the box containing the layout text.\n" " --layout-border-color <color> " "Sets the color of the border of the box containing the layout text.\n" " --layout-text-color <color> " "Sets the color of the layout text.\n" " --line-color <color> " "Sets the color of the line between the inside and ring.\n" " --line-clear-color <color> " "Sets the color of the line between the inside and ring when " "cleared.\n" " --line-caps-lock-color <color> " "Sets the color of the line between the inside and ring when " "Caps Lock is active.\n" " --line-ver-color <color> " "Sets the color of the line between the inside and ring when " "verifying.\n" " --line-wrong-color <color> " "Sets the color of the line between the inside and ring when " "invalid.\n" " -n, --line-uses-inside " "Use the inside color for the line between the inside and ring.\n" " -r, --line-uses-ring " "Use the ring color for the line between the inside and ring.\n" " --ring-color <color> " "Sets the color of the ring of the indicator.\n" " --ring-clear-color <color> " "Sets the color of the ring of the indicator when cleared.\n" " --ring-caps-lock-color <color> " "Sets the color of the ring of the indicator when Caps Lock " "is active.\n" " --ring-ver-color <color> " "Sets the color of the ring of the indicator when verifying.\n" " --ring-wrong-color <color> " "Sets the color of the ring of the indicator when invalid.\n" " --separator-color <color> " "Sets the color of the lines that separate highlight segments.\n" " --text-color <color> " "Sets the color of the text.\n" " --text-clear-color <color> " "Sets the color of the text when cleared.\n" " --text-caps-lock-color <color> " "Sets the color of the text when Caps Lock is active.\n" " --text-ver-color <color> " "Sets the color of the text when verifying.\n" " --text-wrong-color <color> " "Sets the color of the text when invalid.\n" "\n" "All <color> options are of the form <rrggbb[aa]>.\n"; int c; optind = 1; while (1) { int opt_idx = 0; c = getopt_long(argc, argv, "c:deFfhi:kKLlnrs:tuvC:R:", long_options, &opt_idx); if (c == -1) { break; } switch (c) { case 'C': if (config_path) { *config_path = strdup(optarg); } break; case 'c': if (state) { state->args.colors.background = parse_color(optarg); } break; case 'd': swaylock_log_init(LOG_DEBUG); break; case 'e': if (state) { state->args.ignore_empty = true; } break; case 'F': if (state) { state->args.show_failed_attempts = true; } break; case 'f': if (state) { state->args.daemonize = true; } break; case 'R': if (state) { state->args.ready_fd = strtol(optarg, NULL, 10); } break; case 'i': if (state) { load_image(optarg, state); } break; case 'k': if (state) { state->args.show_keyboard_layout = true; } break; case 'K': if (state) { state->args.hide_keyboard_layout = true; } break; case 'L': if (state) { state->args.show_caps_lock_text = false; } break; case 'l': if (state) { state->args.show_caps_lock_indicator = true; } break; case 'n': if (line_mode) { *line_mode = LM_INSIDE; } break; case 'r': if (line_mode) { *line_mode = LM_RING; } break; case 's': if (state) { state->args.mode = parse_background_mode(optarg); if (state->args.mode == BACKGROUND_MODE_INVALID) { return 1; } } break; case 't': if (state) { state->args.mode = BACKGROUND_MODE_TILE; } break; case 'u': if (state) { state->args.show_indicator = false; } break; case 'v': fprintf(stdout, "swaylock version " SWAYLOCK_VERSION "\n"); exit(EXIT_SUCCESS); break; case LO_BS_HL_COLOR: if (state) { state->args.colors.bs_highlight = parse_color(optarg); } break; case LO_CAPS_LOCK_BS_HL_COLOR: if (state) { state->args.colors.caps_lock_bs_highlight = parse_color(optarg); } break; case LO_CAPS_LOCK_KEY_HL_COLOR: if (state) { state->args.colors.caps_lock_key_highlight = parse_color(optarg); } break; case LO_FONT: if (state) { free(state->args.font); state->args.font = strdup(optarg); } break; case LO_FONT_SIZE: if (state) { state->args.font_size = atoi(optarg); } break; case LO_IND_IDLE_VISIBLE: if (state) { state->args.indicator_idle_visible = true; } break; case LO_IND_RADIUS: if (state) { state->args.radius = strtol(optarg, NULL, 0); } break; case LO_IND_THICKNESS: if (state) { state->args.thickness = strtol(optarg, NULL, 0); } break; case LO_IND_X_POSITION: if (state) { state->args.override_indicator_x_position = true; state->args.indicator_x_position = atoi(optarg); } break; case LO_IND_Y_POSITION: if (state) { state->args.override_indicator_y_position = true; state->args.indicator_y_position = atoi(optarg); } break; case LO_INSIDE_COLOR: if (state) { state->args.colors.inside.input = parse_color(optarg); } break; case LO_INSIDE_CLEAR_COLOR: if (state) { state->args.colors.inside.cleared = parse_color(optarg); } break; case LO_INSIDE_CAPS_LOCK_COLOR: if (state) { state->args.colors.inside.caps_lock = parse_color(optarg); } break; case LO_INSIDE_VER_COLOR: if (state) { state->args.colors.inside.verifying = parse_color(optarg); } break; case LO_INSIDE_WRONG_COLOR: if (state) { state->args.colors.inside.wrong = parse_color(optarg); } break; case LO_KEY_HL_COLOR: if (state) { state->args.colors.key_highlight = parse_color(optarg); } break; case LO_LAYOUT_BG_COLOR: if (state) { state->args.colors.layout_background = parse_color(optarg); } break; case LO_LAYOUT_BORDER_COLOR: if (state) { state->args.colors.layout_border = parse_color(optarg); } break; case LO_LAYOUT_TXT_COLOR: if (state) { state->args.colors.layout_text = parse_color(optarg); } break; case LO_LINE_COLOR: if (state) { state->args.colors.line.input = parse_color(optarg); } break; case LO_LINE_CLEAR_COLOR: if (state) { state->args.colors.line.cleared = parse_color(optarg); } break; case LO_LINE_CAPS_LOCK_COLOR: if (state) { state->args.colors.line.caps_lock = parse_color(optarg); } break; case LO_LINE_VER_COLOR: if (state) { state->args.colors.line.verifying = parse_color(optarg); } break; case LO_LINE_WRONG_COLOR: if (state) { state->args.colors.line.wrong = parse_color(optarg); } break; case LO_RING_COLOR: if (state) { state->args.colors.ring.input = parse_color(optarg); } break; case LO_RING_CLEAR_COLOR: if (state) { state->args.colors.ring.cleared = parse_color(optarg); } break; case LO_RING_CAPS_LOCK_COLOR: if (state) { state->args.colors.ring.caps_lock = parse_color(optarg); } break; case LO_RING_VER_COLOR: if (state) { state->args.colors.ring.verifying = parse_color(optarg); } break; case LO_RING_WRONG_COLOR: if (state) { state->args.colors.ring.wrong = parse_color(optarg); } break; case LO_SEP_COLOR: if (state) { state->args.colors.separator = parse_color(optarg); } break; case LO_TEXT_COLOR: if (state) { state->args.colors.text.input = parse_color(optarg); } break; case LO_TEXT_CLEAR_COLOR: if (state) { state->args.colors.text.cleared = parse_color(optarg); } break; case LO_TEXT_CAPS_LOCK_COLOR: if (state) { state->args.colors.text.caps_lock = parse_color(optarg); } break; case LO_TEXT_VER_COLOR: if (state) { state->args.colors.text.verifying = parse_color(optarg); } break; case LO_TEXT_WRONG_COLOR: if (state) { state->args.colors.text.wrong = parse_color(optarg); } break; default: fprintf(stderr, "%s", usage); return 1; } } return 0; } static bool file_exists(const char *path) { return path && access(path, R_OK) != -1; } static char *get_config_path(void) { static const char *config_paths[] = { "$HOME/.swaylock/config", "$XDG_CONFIG_HOME/swaylock/config", SYSCONFDIR "/swaylock/config", }; char *config_home = getenv("XDG_CONFIG_HOME"); if (!config_home || config_home[0] == '\0') { config_paths[1] = "$HOME/.config/swaylock/config"; } wordexp_t p; char *path; for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) { if (wordexp(config_paths[i], &p, 0) == 0) { path = strdup(p.we_wordv[0]); wordfree(&p); if (file_exists(path)) { return path; } free(path); } } return NULL; } static int load_config(char *path, struct swaylock_state *state, enum line_mode *line_mode) { FILE *config = fopen(path, "r"); if (!config) { swaylock_log(LOG_ERROR, "Failed to read config. Running without it."); return 0; } char *line = NULL; size_t line_size = 0; ssize_t nread; int line_number = 0; int result = 0; while ((nread = getline(&line, &line_size, config)) != -1) { line_number++; if (line[nread - 1] == '\n') { line[--nread] = '\0'; } if (!*line || line[0] == '#') { continue; } swaylock_log(LOG_DEBUG, "Config Line #%d: %s", line_number, line); char *flag = malloc(nread + 3); if (flag == NULL) { free(line); fclose(config); swaylock_log(LOG_ERROR, "Failed to allocate memory"); return 0; } sprintf(flag, "--%s", line); char *argv[] = {"swaylock", flag}; result = parse_options(2, argv, state, line_mode, NULL); free(flag); if (result != 0) { break; } } free(line); fclose(config); return 0; } static struct swaylock_state state; static void display_in(int fd, short mask, void *data) { if (wl_display_dispatch(state.display) == -1) { state.run_display = false; } } static void comm_in(int fd, short mask, void *data) { if (read_comm_reply()) { // Authentication succeeded state.run_display = false; } else { state.auth_state = AUTH_STATE_INVALID; schedule_auth_idle(&state); ++state.failed_attempts; damage_state(&state); } } static void term_in(int fd, short mask, void *data) { state.run_display = false; } // Check for --debug 'early' we also apply the correct loglevel // to the forked child, without having to first proces all of the // configuration (including from file) before forking and (in the // case of the shadow backend) dropping privileges void log_init(int argc, char **argv) { static struct option long_options[] = { {"debug", no_argument, NULL, 'd'}, {0, 0, 0, 0} }; int c; optind = 1; while (1) { int opt_idx = 0; c = getopt_long(argc, argv, "-:d", long_options, &opt_idx); if (c == -1) { break; } switch (c) { case 'd': swaylock_log_init(LOG_DEBUG); return; } } swaylock_log_init(LOG_ERROR); } int main(int argc, char **argv) { log_init(argc, argv); initialize_pw_backend(argc, argv); srand(time(NULL)); enum line_mode line_mode = LM_LINE; state.failed_attempts = 0; state.args = (struct swaylock_args){ .mode = BACKGROUND_MODE_FILL, .font = strdup("sans-serif"), .font_size = 0, .radius = 50, .thickness = 10, .indicator_x_position = 0, .indicator_y_position = 0, .override_indicator_x_position = false, .override_indicator_y_position = false, .ignore_empty = false, .show_indicator = true, .show_caps_lock_indicator = false, .show_caps_lock_text = true, .show_keyboard_layout = false, .hide_keyboard_layout = false, .show_failed_attempts = false, .indicator_idle_visible = false, .ready_fd = -1, }; wl_list_init(&state.images); set_default_colors(&state.args.colors); char *config_path = NULL; int result = parse_options(argc, argv, NULL, NULL, &config_path); if (result != 0) { free(config_path); return result; } if (!config_path) { config_path = get_config_path(); } if (config_path) { swaylock_log(LOG_DEBUG, "Found config at %s", config_path); int config_status = load_config(config_path, &state, &line_mode); free(config_path); if (config_status != 0) { free(state.args.font); return config_status; } } if (argc > 1) { swaylock_log(LOG_DEBUG, "Parsing CLI Args"); int result = parse_options(argc, argv, &state, &line_mode, NULL); if (result != 0) { free(state.args.font); return result; } } if (line_mode == LM_INSIDE) { state.args.colors.line = state.args.colors.inside; } else if (line_mode == LM_RING) { state.args.colors.line = state.args.colors.ring; } state.password.len = 0; state.password.buffer_len = 1024; state.password.buffer = password_buffer_create(state.password.buffer_len); if (!state.password.buffer) { return EXIT_FAILURE; } if (pipe(sigusr_fds) != 0) { swaylock_log(LOG_ERROR, "Failed to pipe"); return EXIT_FAILURE; } if (fcntl(sigusr_fds[1], F_SETFL, O_NONBLOCK) == -1) { swaylock_log(LOG_ERROR, "Failed to make pipe end nonblocking"); return EXIT_FAILURE; } wl_list_init(&state.surfaces); state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); state.display = wl_display_connect(NULL); if (!state.display) { free(state.args.font); swaylock_log(LOG_ERROR, "Unable to connect to the compositor. " "If your compositor is running, check or set the " "WAYLAND_DISPLAY environment variable."); return EXIT_FAILURE; } state.eventloop = loop_create(); struct wl_registry *registry = wl_display_get_registry(state.display); wl_registry_add_listener(registry, ®istry_listener, &state); if (wl_display_roundtrip(state.display) == -1) { swaylock_log(LOG_ERROR, "wl_display_roundtrip() failed"); return EXIT_FAILURE; } if (!state.compositor) { swaylock_log(LOG_ERROR, "Missing wl_compositor"); return 1; } if (!state.subcompositor) { swaylock_log(LOG_ERROR, "Missing wl_subcompositor"); return 1; } if (!state.shm) { swaylock_log(LOG_ERROR, "Missing wl_shm"); return 1; } if (!state.ext_session_lock_manager_v1) { swaylock_log(LOG_ERROR, "Missing ext-session-lock-v1"); return 1; } state.ext_session_lock_v1 = ext_session_lock_manager_v1_lock(state.ext_session_lock_manager_v1); ext_session_lock_v1_add_listener(state.ext_session_lock_v1, &ext_session_lock_v1_listener, &state); if (wl_display_roundtrip(state.display) == -1) { free(state.args.font); return 1; } state.test_surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 1, 1); state.test_cairo = cairo_create(state.test_surface); struct swaylock_surface *surface; wl_list_for_each(surface, &state.surfaces, link) { create_surface(surface); } while (!state.locked) { if (wl_display_dispatch(state.display) < 0) { swaylock_log(LOG_ERROR, "wl_display_dispatch() failed"); return 2; } } if (state.args.ready_fd >= 0) { if (write(state.args.ready_fd, "\n", 1) != 1) { swaylock_log(LOG_ERROR, "Failed to send readiness notification"); return 2; } close(state.args.ready_fd); state.args.ready_fd = -1; } if (state.args.daemonize) { daemonize(); } loop_add_fd(state.eventloop, wl_display_get_fd(state.display), POLLIN, display_in, NULL); loop_add_fd(state.eventloop, get_comm_reply_fd(), POLLIN, comm_in, NULL); loop_add_fd(state.eventloop, sigusr_fds[0], POLLIN, term_in, NULL); struct sigaction sa; sa.sa_handler = do_sigusr; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGUSR1, &sa, NULL); state.run_display = true; while (state.run_display) { errno = 0; if (wl_display_flush(state.display) == -1 && errno != EAGAIN) { break; } loop_poll(state.eventloop); } ext_session_lock_v1_unlock_and_destroy(state.ext_session_lock_v1); wl_display_roundtrip(state.display); free(state.args.font); cairo_destroy(state.test_cairo); cairo_surface_destroy(state.test_surface); return 0; } 0707010000001F000081A400000000000000000000000166C8F38500000F05000000000000000000000000000000000000001B00000000swaylock-1.8.0/meson.buildproject( 'swaylock', 'c', version: '1.8.0', license: 'MIT', meson_version: '>=0.59.0', default_options: [ 'c_std=c11', 'warning_level=2', 'werror=true', ], ) add_project_arguments( [ '-Wno-unused-parameter', '-Wno-unused-result', '-Wundef', '-Wvla', ], language: 'c', ) cc = meson.get_compiler('c') is_freebsd = host_machine.system().startswith('freebsd') if is_freebsd add_project_arguments('-D_C11_SOURCE', language: 'c') endif wayland_client = dependency('wayland-client', version: '>=1.20.0') wayland_protos = dependency('wayland-protocols', version: '>=1.25', fallback: 'wayland-protocols') wayland_scanner = dependency('wayland-scanner', version: '>=1.15.0', native: true) xkbcommon = dependency('xkbcommon') cairo = dependency('cairo') gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) libpam = cc.find_library('pam', required: get_option('pam')) crypt = cc.find_library('crypt', required: not libpam.found()) math = cc.find_library('m') rt = cc.find_library('rt') git = find_program('git', required: false) scdoc = find_program('scdoc', required: get_option('man-pages')) wayland_scanner_prog = find_program(wayland_scanner.get_variable('wayland_scanner'), native: true) version = meson.project_version() if git.found() git_commit_hash = run_command([git, 'describe', '--always', '--tags'], check: false) git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false) if git_commit_hash.returncode() == 0 and git_branch.returncode() == 0 version = '@0@ (" __DATE__ ", branch \'@1@\')'.format(git_commit_hash.stdout().strip(), git_branch.stdout().strip()) endif endif wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') wayland_scanner_code = generator( wayland_scanner_prog, output: '@BASENAME@-protocol.c', arguments: ['private-code', '@INPUT@', '@OUTPUT@'], ) wayland_scanner_client = generator( wayland_scanner_prog, output: '@BASENAME@-client-protocol.h', arguments: ['client-header', '@INPUT@', '@OUTPUT@'], ) client_protocols = [ wl_protocol_dir / 'staging/ext-session-lock/ext-session-lock-v1.xml', ] protos_src = [] foreach xml : client_protocols protos_src += wayland_scanner_code.process(xml) protos_src += wayland_scanner_client.process(xml) endforeach conf_data = configuration_data() conf_data.set_quoted('SYSCONFDIR', get_option('prefix') / get_option('sysconfdir')) conf_data.set_quoted('SWAYLOCK_VERSION', version) conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found()) subdir('include') dependencies = [ cairo, gdk_pixbuf, math, rt, xkbcommon, wayland_client, ] sources = [ 'background-image.c', 'cairo.c', 'comm.c', 'log.c', 'loop.c', 'main.c', 'password.c', 'password-buffer.c', 'pool-buffer.c', 'render.c', 'seat.c', 'unicode.c', ] if libpam.found() sources += ['pam.c'] dependencies += [libpam] else warning('The swaylock binary must be setuid when compiled without libpam') warning('You must do this manually post-install: chmod a+s /path/to/swaylock') sources += ['shadow.c'] dependencies += [crypt] endif swaylock_inc = include_directories('include') executable('swaylock', sources + protos_src, include_directories: [swaylock_inc], dependencies: dependencies, install: true ) if libpam.found() install_data( 'pam/swaylock', install_dir: get_option('sysconfdir') / 'pam.d' ) endif if scdoc.found() mandir = get_option('mandir') man_files = [ 'swaylock.1.scd', ] foreach filename : man_files topic = filename.split('.')[-3].split('/')[-1] section = filename.split('.')[-2] output = '@0@.@1@'.format(topic, section) custom_target( output, input: filename, output: output, command: scdoc, feed: true, capture: true, install: true, install_dir: '@0@/man@1@'.format(mandir, section) ) endforeach endif subdir('completions') 07070100000020000081A400000000000000000000000166C8F3850000025C000000000000000000000000000000000000002100000000swaylock-1.8.0/meson_options.txtoption('pam', type: 'feature', value: 'auto', description: 'Use PAM instead of shadow') option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions') option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions') option('fish-completions', type: 'boolean', value: true, description: 'Install fish shell completions') 07070100000021000041ED00000000000000000000000266C8F38500000000000000000000000000000000000000000000001300000000swaylock-1.8.0/pam07070100000022000081A400000000000000000000000166C8F38500000C71000000000000000000000000000000000000001500000000swaylock-1.8.0/pam.c#define _POSIX_C_SOURCE 200809L #include <pwd.h> #include <security/pam_appl.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "comm.h" #include "log.h" #include "password-buffer.h" #include "swaylock.h" static char *pw_buf = NULL; void initialize_pw_backend(int argc, char **argv) { if (getuid() != geteuid() || getgid() != getegid()) { swaylock_log(LOG_ERROR, "swaylock is setuid, but was compiled with the PAM" " backend. Run 'chmod a-s %s' to fix. Aborting.", argv[0]); exit(EXIT_FAILURE); } if (!spawn_comm_child()) { exit(EXIT_FAILURE); } } static int handle_conversation(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *data) { /* PAM expects an array of responses, one for each message */ struct pam_response *pam_reply = calloc(num_msg, sizeof(struct pam_response)); if (pam_reply == NULL) { swaylock_log(LOG_ERROR, "Allocation failed"); return PAM_ABORT; } *resp = pam_reply; for (int i = 0; i < num_msg; ++i) { switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: case PAM_PROMPT_ECHO_ON: pam_reply[i].resp = strdup(pw_buf); // PAM clears and frees this if (pam_reply[i].resp == NULL) { swaylock_log(LOG_ERROR, "Allocation failed"); return PAM_ABORT; } break; case PAM_ERROR_MSG: case PAM_TEXT_INFO: break; } } return PAM_SUCCESS; } static const char *get_pam_auth_error(int pam_status) { switch (pam_status) { case PAM_AUTH_ERR: return "invalid credentials"; case PAM_CRED_INSUFFICIENT: return "swaylock cannot authenticate users; check /etc/pam.d/swaylock " "has been installed properly"; case PAM_AUTHINFO_UNAVAIL: return "authentication information unavailable"; case PAM_MAXTRIES: return "maximum number of authentication tries exceeded"; default:; static char msg[64]; snprintf(msg, sizeof(msg), "unknown error (%d)", pam_status); return msg; } } void run_pw_backend_child(void) { struct passwd *passwd = getpwuid(getuid()); char *username = passwd->pw_name; const struct pam_conv conv = { .conv = handle_conversation, .appdata_ptr = NULL, }; pam_handle_t *auth_handle = NULL; if (pam_start("swaylock", username, &conv, &auth_handle) != PAM_SUCCESS) { swaylock_log(LOG_ERROR, "pam_start failed"); exit(EXIT_FAILURE); } /* This code does not run as root */ swaylock_log(LOG_DEBUG, "Prepared to authorize user %s", username); int pam_status = PAM_SUCCESS; while (1) { ssize_t size = read_comm_request(&pw_buf); if (size < 0) { exit(EXIT_FAILURE); } else if (size == 0) { break; } int pam_status = pam_authenticate(auth_handle, 0); password_buffer_destroy(pw_buf, size); pw_buf = NULL; bool success = pam_status == PAM_SUCCESS; if (!success) { swaylock_log(LOG_ERROR, "pam_authenticate failed: %s", get_pam_auth_error(pam_status)); } if (!write_comm_reply(success)) { exit(EXIT_FAILURE); } } pam_setcred(auth_handle, PAM_REFRESH_CRED); if (pam_end(auth_handle, pam_status) != PAM_SUCCESS) { swaylock_log(LOG_ERROR, "pam_end failed"); exit(EXIT_FAILURE); } exit((pam_status == PAM_SUCCESS) ? EXIT_SUCCESS : EXIT_FAILURE); } 07070100000023000081A400000000000000000000000166C8F385000000A1000000000000000000000000000000000000001C00000000swaylock-1.8.0/pam/swaylock# # PAM configuration file for the swaylock screen locker. By default, it includes # the 'login' configuration file (see /etc/pam.d/login) # auth include login 07070100000024000081A400000000000000000000000166C8F3850000073D000000000000000000000000000000000000002100000000swaylock-1.8.0/password-buffer.c#define _POSIX_C_SOURCE 200809L #include "password-buffer.h" #include "log.h" #include "swaylock.h" #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <limits.h> #include <sys/mman.h> static bool mlock_supported = true; static long int page_size = 0; static long int get_page_size() { if (!page_size) { page_size = sysconf(_SC_PAGESIZE); } return page_size; } // password_buffer_lock expects addr to be page alligned static bool password_buffer_lock(char *addr, size_t size) { int retries = 5; while (mlock(addr, size) != 0 && retries > 0) { switch (errno) { case EAGAIN: retries--; if (retries == 0) { swaylock_log(LOG_ERROR, "mlock() supported but failed too often."); return false; } break; case EPERM: swaylock_log_errno(LOG_ERROR, "Unable to mlock() password memory: Unsupported!"); mlock_supported = false; return true; default: swaylock_log_errno(LOG_ERROR, "Unable to mlock() password memory."); return false; } } return true; } // password_buffer_unlock expects addr to be page alligned static bool password_buffer_unlock(char *addr, size_t size) { if (mlock_supported) { if (munlock(addr, size) != 0) { swaylock_log_errno(LOG_ERROR, "Unable to munlock() password memory."); return false; } } return true; } char *password_buffer_create(size_t size) { void *buffer; int result = posix_memalign(&buffer, get_page_size(), size); if (result) { //posix_memalign doesn't set errno according to the man page errno = result; swaylock_log_errno(LOG_ERROR, "failed to alloc password buffer"); return NULL; } if (!password_buffer_lock(buffer, size)) { free(buffer); return NULL; } return buffer; } void password_buffer_destroy(char *buffer, size_t size) { clear_buffer(buffer, size); password_buffer_unlock(buffer, size); free(buffer); } 07070100000025000081A400000000000000000000000166C8F385000015DB000000000000000000000000000000000000001A00000000swaylock-1.8.0/password.c#include <assert.h> #include <errno.h> #include <pwd.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <xkbcommon/xkbcommon.h> #include "comm.h" #include "log.h" #include "loop.h" #include "seat.h" #include "swaylock.h" #include "unicode.h" void clear_buffer(char *buf, size_t size) { // Use volatile keyword so so compiler can't optimize this out. volatile char *buffer = buf; volatile char zero = '\0'; for (size_t i = 0; i < size; ++i) { buffer[i] = zero; } } void clear_password_buffer(struct swaylock_password *pw) { clear_buffer(pw->buffer, pw->buffer_len); pw->len = 0; } static bool backspace(struct swaylock_password *pw) { if (pw->len != 0) { pw->len -= utf8_last_size(pw->buffer); pw->buffer[pw->len] = 0; return true; } return false; } static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { size_t utf8_size = utf8_chsize(codepoint); if (pw->len + utf8_size + 1 >= pw->buffer_len) { // TODO: Display error return; } utf8_encode(&pw->buffer[pw->len], codepoint); pw->buffer[pw->len + utf8_size] = 0; pw->len += utf8_size; } static void set_input_idle(void *data) { struct swaylock_state *state = data; state->input_idle_timer = NULL; state->input_state = INPUT_STATE_IDLE; damage_state(state); } static void set_auth_idle(void *data) { struct swaylock_state *state = data; state->auth_idle_timer = NULL; state->auth_state = AUTH_STATE_IDLE; damage_state(state); } static void schedule_input_idle(struct swaylock_state *state) { if (state->input_idle_timer) { loop_remove_timer(state->eventloop, state->input_idle_timer); } state->input_idle_timer = loop_add_timer( state->eventloop, 1500, set_input_idle, state); } static void cancel_input_idle(struct swaylock_state *state) { if (state->input_idle_timer) { loop_remove_timer(state->eventloop, state->input_idle_timer); state->input_idle_timer = NULL; } } void schedule_auth_idle(struct swaylock_state *state) { if (state->auth_idle_timer) { loop_remove_timer(state->eventloop, state->auth_idle_timer); } state->auth_idle_timer = loop_add_timer( state->eventloop, 3000, set_auth_idle, state); } static void clear_password(void *data) { struct swaylock_state *state = data; state->clear_password_timer = NULL; state->input_state = INPUT_STATE_CLEAR; schedule_input_idle(state); clear_password_buffer(&state->password); damage_state(state); } static void schedule_password_clear(struct swaylock_state *state) { if (state->clear_password_timer) { loop_remove_timer(state->eventloop, state->clear_password_timer); } state->clear_password_timer = loop_add_timer( state->eventloop, 10000, clear_password, state); } static void cancel_password_clear(struct swaylock_state *state) { if (state->clear_password_timer) { loop_remove_timer(state->eventloop, state->clear_password_timer); state->clear_password_timer = NULL; } } static void submit_password(struct swaylock_state *state) { if (state->args.ignore_empty && state->password.len == 0) { return; } state->input_state = INPUT_STATE_IDLE; state->auth_state = AUTH_STATE_VALIDATING; cancel_password_clear(state); cancel_input_idle(state); if (!write_comm_request(&state->password)) { state->auth_state = AUTH_STATE_INVALID; schedule_auth_idle(state); } damage_state(state); } static void update_highlight(struct swaylock_state *state) { // Advance a random amount between 1/4 and 3/4 of a full turn state->highlight_start = (state->highlight_start + (rand() % 1024) + 512) % 2048; } void swaylock_handle_key(struct swaylock_state *state, xkb_keysym_t keysym, uint32_t codepoint) { switch (keysym) { case XKB_KEY_KP_Enter: /* fallthrough */ case XKB_KEY_Return: submit_password(state); break; case XKB_KEY_Delete: case XKB_KEY_BackSpace: if (state->xkb.control) { clear_password_buffer(&state->password); state->input_state = INPUT_STATE_CLEAR; cancel_password_clear(state); } else { if (backspace(&state->password) && state->password.len != 0) { state->input_state = INPUT_STATE_BACKSPACE; schedule_password_clear(state); update_highlight(state); } else { state->input_state = INPUT_STATE_CLEAR; cancel_password_clear(state); } } schedule_input_idle(state); damage_state(state); break; case XKB_KEY_Escape: clear_password_buffer(&state->password); state->input_state = INPUT_STATE_CLEAR; cancel_password_clear(state); schedule_input_idle(state); damage_state(state); break; case XKB_KEY_Caps_Lock: case XKB_KEY_Shift_L: case XKB_KEY_Shift_R: case XKB_KEY_Control_L: case XKB_KEY_Control_R: case XKB_KEY_Meta_L: case XKB_KEY_Meta_R: case XKB_KEY_Alt_L: case XKB_KEY_Alt_R: case XKB_KEY_Super_L: case XKB_KEY_Super_R: state->input_state = INPUT_STATE_NEUTRAL; schedule_password_clear(state); schedule_input_idle(state); damage_state(state); break; case XKB_KEY_m: /* fallthrough */ case XKB_KEY_d: case XKB_KEY_j: if (state->xkb.control) { submit_password(state); break; } // fallthrough case XKB_KEY_c: /* fallthrough */ case XKB_KEY_u: if (state->xkb.control) { clear_password_buffer(&state->password); state->input_state = INPUT_STATE_CLEAR; cancel_password_clear(state); schedule_input_idle(state); damage_state(state); break; } // fallthrough default: if (codepoint) { append_ch(&state->password, codepoint); state->input_state = INPUT_STATE_LETTER; schedule_password_clear(state); schedule_input_idle(state); update_highlight(state); damage_state(state); } break; } } 07070100000026000081A400000000000000000000000166C8F38500000B52000000000000000000000000000000000000001D00000000swaylock-1.8.0/pool-buffer.c#define _POSIX_C_SOURCE 200809L #include <assert.h> #include <cairo/cairo.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <time.h> #include <unistd.h> #include <wayland-client.h> #include "pool-buffer.h" static int anonymous_shm_open(void) { int retries = 100; do { // try a probably-unique name struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); pid_t pid = getpid(); char name[50]; snprintf(name, sizeof(name), "/swaylock-%x-%x", (unsigned int)pid, (unsigned int)ts.tv_nsec); // shm_open guarantees that O_CLOEXEC is set int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); if (fd >= 0) { shm_unlink(name); return fd; } --retries; } while (retries > 0 && errno == EEXIST); return -1; } static void buffer_release(void *data, struct wl_buffer *wl_buffer) { struct pool_buffer *buffer = data; buffer->busy = false; } static const struct wl_buffer_listener buffer_listener = { .release = buffer_release }; struct pool_buffer *create_buffer(struct wl_shm *shm, struct pool_buffer *buf, int32_t width, int32_t height, uint32_t format) { uint32_t stride = width * 4; size_t size = stride * height; void *data = NULL; if (size > 0) { int fd = anonymous_shm_open(); if (fd == -1) { return NULL; } if (ftruncate(fd, size) < 0) { close(fd); return NULL; } data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size); buf->buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, format); wl_buffer_add_listener(buf->buffer, &buffer_listener, buf); wl_shm_pool_destroy(pool); close(fd); } buf->size = size; buf->width = width; buf->height = height; buf->data = data; buf->surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, stride); buf->cairo = cairo_create(buf->surface); return buf; } void destroy_buffer(struct pool_buffer *buffer) { if (buffer->buffer) { wl_buffer_destroy(buffer->buffer); } if (buffer->cairo) { cairo_destroy(buffer->cairo); } if (buffer->surface) { cairo_surface_destroy(buffer->surface); } if (buffer->data) { munmap(buffer->data, buffer->size); } memset(buffer, 0, sizeof(struct pool_buffer)); } struct pool_buffer *get_next_buffer(struct wl_shm *shm, struct pool_buffer pool[static 2], uint32_t width, uint32_t height) { struct pool_buffer *buffer = NULL; for (size_t i = 0; i < 2; ++i) { if (pool[i].busy) { continue; } buffer = &pool[i]; } if (!buffer) { return NULL; } if (buffer->width != width || buffer->height != height) { destroy_buffer(buffer); } if (!buffer->buffer) { if (!create_buffer(shm, buffer, width, height, WL_SHM_FORMAT_ARGB8888)) { return NULL; } } buffer->busy = true; return buffer; } 07070100000027000081A400000000000000000000000166C8F38500002FC6000000000000000000000000000000000000001800000000swaylock-1.8.0/render.c#include <math.h> #include <stdlib.h> #include <wayland-client.h> #include "cairo.h" #include "background-image.h" #include "swaylock.h" #include "log.h" #define M_PI 3.14159265358979323846 const float TYPE_INDICATOR_RANGE = M_PI / 3.0f; const float TYPE_INDICATOR_BORDER_THICKNESS = M_PI / 128.0f; static void set_color_for_state(cairo_t *cairo, struct swaylock_state *state, struct swaylock_colorset *colorset) { if (state->input_state == INPUT_STATE_CLEAR) { cairo_set_source_u32(cairo, colorset->cleared); } else if (state->auth_state == AUTH_STATE_VALIDATING) { cairo_set_source_u32(cairo, colorset->verifying); } else if (state->auth_state == AUTH_STATE_INVALID) { cairo_set_source_u32(cairo, colorset->wrong); } else { if (state->xkb.caps_lock && state->args.show_caps_lock_indicator) { cairo_set_source_u32(cairo, colorset->caps_lock); } else if (state->xkb.caps_lock && !state->args.show_caps_lock_indicator && state->args.show_caps_lock_text) { uint32_t inputtextcolor = state->args.colors.text.input; state->args.colors.text.input = state->args.colors.text.caps_lock; cairo_set_source_u32(cairo, colorset->input); state->args.colors.text.input = inputtextcolor; } else { cairo_set_source_u32(cairo, colorset->input); } } } void render_frame_background(struct swaylock_surface *surface) { struct swaylock_state *state = surface->state; int buffer_width = surface->width * surface->scale; int buffer_height = surface->height * surface->scale; if (buffer_width == 0 || buffer_height == 0) { return; // not yet configured } wl_surface_set_buffer_scale(surface->surface, surface->scale); if (buffer_width != surface->last_buffer_width || buffer_height != surface->last_buffer_height) { struct pool_buffer buffer; if (!create_buffer(state->shm, &buffer, buffer_width, buffer_height, WL_SHM_FORMAT_ARGB8888)) { swaylock_log(LOG_ERROR, "Failed to create new buffer for frame background."); return; } cairo_t *cairo = buffer.cairo; cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_save(cairo); cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); cairo_set_source_u32(cairo, state->args.colors.background); cairo_paint(cairo); if (surface->image && state->args.mode != BACKGROUND_MODE_SOLID_COLOR) { cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); render_background_image(cairo, surface->image, state->args.mode, buffer_width, buffer_height); } cairo_restore(cairo); cairo_identity_matrix(cairo); wl_surface_attach(surface->surface, buffer.buffer, 0, 0); wl_surface_damage_buffer(surface->surface, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(surface->surface); destroy_buffer(&buffer); surface->last_buffer_width = buffer_width; surface->last_buffer_height = buffer_height; } else { wl_surface_commit(surface->surface); } } static void configure_font_drawing(cairo_t *cairo, struct swaylock_state *state, enum wl_output_subpixel subpixel, int arc_radius) { cairo_font_options_t *fo = cairo_font_options_create(); cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(subpixel)); cairo_set_font_options(cairo, fo); cairo_select_font_face(cairo, state->args.font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); if (state->args.font_size > 0) { cairo_set_font_size(cairo, state->args.font_size); } else { cairo_set_font_size(cairo, arc_radius / 3.0f); } cairo_font_options_destroy(fo); } void render_frame(struct swaylock_surface *surface) { struct swaylock_state *state = surface->state; // First, compute the text that will be drawn, if any, since this // determines the size/positioning of the surface char attempts[4]; // like i3lock: count no more than 999 char *text = NULL; const char *layout_text = NULL; bool draw_indicator = state->args.show_indicator && (state->auth_state != AUTH_STATE_IDLE || state->input_state != INPUT_STATE_IDLE || state->args.indicator_idle_visible); if (draw_indicator) { if (state->input_state == INPUT_STATE_CLEAR) { // This message has highest priority text = "Cleared"; } else if (state->auth_state == AUTH_STATE_VALIDATING) { text = "Verifying"; } else if (state->auth_state == AUTH_STATE_INVALID) { text = "Wrong"; } else { // Caps Lock has higher priority if (state->xkb.caps_lock && state->args.show_caps_lock_text) { text = "Caps Lock"; } else if (state->args.show_failed_attempts && state->failed_attempts > 0) { if (state->failed_attempts > 999) { text = "999+"; } else { snprintf(attempts, sizeof(attempts), "%d", state->failed_attempts); text = attempts; } } xkb_layout_index_t num_layout = xkb_keymap_num_layouts(state->xkb.keymap); if (!state->args.hide_keyboard_layout && (state->args.show_keyboard_layout || num_layout > 1)) { xkb_layout_index_t curr_layout = 0; // advance to the first active layout (if any) while (curr_layout < num_layout && xkb_state_layout_index_is_active(state->xkb.state, curr_layout, XKB_STATE_LAYOUT_EFFECTIVE) != 1) { ++curr_layout; } // will handle invalid index if none are active layout_text = xkb_keymap_layout_get_name(state->xkb.keymap, curr_layout); } } } // Compute the size of the buffer needed int arc_radius = state->args.radius * surface->scale; int arc_thickness = state->args.thickness * surface->scale; int buffer_diameter = (arc_radius + arc_thickness) * 2; int buffer_width = buffer_diameter; int buffer_height = buffer_diameter; if (text || layout_text) { cairo_set_antialias(state->test_cairo, CAIRO_ANTIALIAS_BEST); configure_font_drawing(state->test_cairo, state, surface->subpixel, arc_radius); if (text) { cairo_text_extents_t extents; cairo_text_extents(state->test_cairo, text, &extents); if (buffer_width < extents.width) { buffer_width = extents.width; } } if (layout_text) { cairo_text_extents_t extents; cairo_font_extents_t fe; double box_padding = 4.0 * surface->scale; cairo_text_extents(state->test_cairo, layout_text, &extents); cairo_font_extents(state->test_cairo, &fe); buffer_height += fe.height + 2 * box_padding; if (buffer_width < extents.width + 2 * box_padding) { buffer_width = extents.width + 2 * box_padding; } } } // Ensure buffer size is multiple of buffer scale - required by protocol buffer_height += surface->scale - (buffer_height % surface->scale); buffer_width += surface->scale - (buffer_width % surface->scale); int subsurf_xpos; int subsurf_ypos; // Center the indicator unless overridden by the user if (state->args.override_indicator_x_position) { subsurf_xpos = state->args.indicator_x_position - buffer_width / (2 * surface->scale) + 2 / surface->scale; } else { subsurf_xpos = surface->width / 2 - buffer_width / (2 * surface->scale) + 2 / surface->scale; } if (state->args.override_indicator_y_position) { subsurf_ypos = state->args.indicator_y_position - (state->args.radius + state->args.thickness); } else { subsurf_ypos = surface->height / 2 - (state->args.radius + state->args.thickness); } struct pool_buffer *buffer = get_next_buffer(state->shm, surface->indicator_buffers, buffer_width, buffer_height); if (buffer == NULL) { return; } // Render the buffer cairo_t *cairo = buffer->cairo; cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_identity_matrix(cairo); // Clear cairo_save(cairo); cairo_set_source_rgba(cairo, 0, 0, 0, 0); cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); cairo_paint(cairo); cairo_restore(cairo); float type_indicator_border_thickness = TYPE_INDICATOR_BORDER_THICKNESS * surface->scale; if (draw_indicator) { // Fill inner circle cairo_set_line_width(cairo, 0); cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, arc_radius - arc_thickness / 2, 0, 2 * M_PI); set_color_for_state(cairo, state, &state->args.colors.inside); cairo_fill_preserve(cairo); cairo_stroke(cairo); // Draw ring cairo_set_line_width(cairo, arc_thickness); cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, arc_radius, 0, 2 * M_PI); set_color_for_state(cairo, state, &state->args.colors.ring); cairo_stroke(cairo); // Draw a message configure_font_drawing(cairo, state, surface->subpixel, arc_radius); set_color_for_state(cairo, state, &state->args.colors.text); if (text) { cairo_text_extents_t extents; cairo_font_extents_t fe; double x, y; cairo_text_extents(cairo, text, &extents); cairo_font_extents(cairo, &fe); x = (buffer_width / 2) - (extents.width / 2 + extents.x_bearing); y = (buffer_diameter / 2) + (fe.height / 2 - fe.descent); cairo_move_to(cairo, x, y); cairo_show_text(cairo, text); cairo_close_path(cairo); cairo_new_sub_path(cairo); } // Typing indicator: Highlight random part on keypress if (state->input_state == INPUT_STATE_LETTER || state->input_state == INPUT_STATE_BACKSPACE) { double highlight_start = state->highlight_start * (M_PI / 1024.0); cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, arc_radius, highlight_start, highlight_start + TYPE_INDICATOR_RANGE); if (state->input_state == INPUT_STATE_LETTER) { if (state->xkb.caps_lock && state->args.show_caps_lock_indicator) { cairo_set_source_u32(cairo, state->args.colors.caps_lock_key_highlight); } else { cairo_set_source_u32(cairo, state->args.colors.key_highlight); } } else { if (state->xkb.caps_lock && state->args.show_caps_lock_indicator) { cairo_set_source_u32(cairo, state->args.colors.caps_lock_bs_highlight); } else { cairo_set_source_u32(cairo, state->args.colors.bs_highlight); } } cairo_stroke(cairo); // Draw borders cairo_set_source_u32(cairo, state->args.colors.separator); cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, arc_radius, highlight_start, highlight_start + type_indicator_border_thickness); cairo_stroke(cairo); cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, arc_radius, highlight_start + TYPE_INDICATOR_RANGE, highlight_start + TYPE_INDICATOR_RANGE + type_indicator_border_thickness); cairo_stroke(cairo); } // Draw inner + outer border of the circle set_color_for_state(cairo, state, &state->args.colors.line); cairo_set_line_width(cairo, 2.0 * surface->scale); cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, arc_radius - arc_thickness / 2, 0, 2 * M_PI); cairo_stroke(cairo); cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, arc_radius + arc_thickness / 2, 0, 2 * M_PI); cairo_stroke(cairo); // display layout text separately if (layout_text) { cairo_text_extents_t extents; cairo_font_extents_t fe; double x, y; double box_padding = 4.0 * surface->scale; cairo_text_extents(cairo, layout_text, &extents); cairo_font_extents(cairo, &fe); // upper left coordinates for box x = (buffer_width / 2) - (extents.width / 2) - box_padding; y = buffer_diameter; // background box cairo_rectangle(cairo, x, y, extents.width + 2.0 * box_padding, fe.height + 2.0 * box_padding); cairo_set_source_u32(cairo, state->args.colors.layout_background); cairo_fill_preserve(cairo); // border cairo_set_source_u32(cairo, state->args.colors.layout_border); cairo_stroke(cairo); // take font extents and padding into account cairo_move_to(cairo, x - extents.x_bearing + box_padding, y + (fe.height - fe.descent) + box_padding); cairo_set_source_u32(cairo, state->args.colors.layout_text); cairo_show_text(cairo, layout_text); cairo_new_sub_path(cairo); } } // Send Wayland requests wl_subsurface_set_position(surface->subsurface, subsurf_xpos, subsurf_ypos); wl_surface_set_buffer_scale(surface->child, surface->scale); wl_surface_attach(surface->child, buffer->buffer, 0, 0); wl_surface_damage_buffer(surface->child, 0, 0, INT32_MAX, INT32_MAX); wl_surface_commit(surface->child); wl_surface_commit(surface->surface); } 07070100000028000081A400000000000000000000000166C8F38500001A86000000000000000000000000000000000000001600000000swaylock-1.8.0/seat.c#include <assert.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> #include <xkbcommon/xkbcommon.h> #include "log.h" #include "swaylock.h" #include "seat.h" #include "loop.h" static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) { struct swaylock_seat *seat = data; struct swaylock_state *state = seat->state; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); swaylock_log(LOG_ERROR, "Unknown keymap format %d, aborting", format); exit(1); } char *map_shm = mmap(NULL, size - 1, PROT_READ, MAP_PRIVATE, fd, 0); if (map_shm == MAP_FAILED) { close(fd); swaylock_log(LOG_ERROR, "Unable to initialize keymap shm, aborting"); exit(1); } struct xkb_keymap *keymap = xkb_keymap_new_from_buffer( state->xkb.context, map_shm, size - 1, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(map_shm, size - 1); close(fd); assert(keymap); struct xkb_state *xkb_state = xkb_state_new(keymap); assert(xkb_state); xkb_keymap_unref(state->xkb.keymap); xkb_state_unref(state->xkb.state); state->xkb.keymap = keymap; state->xkb.state = xkb_state; } static void keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { // Who cares } static void keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { // Who cares } static void keyboard_repeat(void *data) { struct swaylock_seat *seat = data; struct swaylock_state *state = seat->state; seat->repeat_timer = loop_add_timer( state->eventloop, seat->repeat_period_ms, keyboard_repeat, seat); swaylock_handle_key(state, seat->repeat_sym, seat->repeat_codepoint); } static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state) { struct swaylock_seat *seat = data; struct swaylock_state *state = seat->state; enum wl_keyboard_key_state key_state = _key_state; xkb_keysym_t sym = xkb_state_key_get_one_sym(state->xkb.state, key + 8); uint32_t keycode = key_state == WL_KEYBOARD_KEY_STATE_PRESSED ? key + 8 : 0; uint32_t codepoint = xkb_state_key_get_utf32(state->xkb.state, keycode); if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) { swaylock_handle_key(state, sym, codepoint); } if (seat->repeat_timer) { loop_remove_timer(seat->state->eventloop, seat->repeat_timer); seat->repeat_timer = NULL; } if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED && seat->repeat_period_ms > 0) { seat->repeat_sym = sym; seat->repeat_codepoint = codepoint; seat->repeat_timer = loop_add_timer( seat->state->eventloop, seat->repeat_delay_ms, keyboard_repeat, seat); } } static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { struct swaylock_seat *seat = data; struct swaylock_state *state = seat->state; if (state->xkb.state == NULL) { return; } int layout_same = xkb_state_layout_index_is_active(state->xkb.state, group, XKB_STATE_LAYOUT_EFFECTIVE); if (!layout_same) { damage_state(state); } xkb_state_update_mask(state->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); int caps_lock = xkb_state_mod_name_is_active(state->xkb.state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED); if (caps_lock != state->xkb.caps_lock) { state->xkb.caps_lock = caps_lock; damage_state(state); } state->xkb.control = xkb_state_mod_name_is_active(state->xkb.state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); } static void keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay) { struct swaylock_seat *seat = data; if (rate <= 0) { seat->repeat_period_ms = -1; } else { // Keys per second -> milliseconds between keys seat->repeat_period_ms = 1000 / rate; } seat->repeat_delay_ms = delay; } static const struct wl_keyboard_listener keyboard_listener = { .keymap = keyboard_keymap, .enter = keyboard_enter, .leave = keyboard_leave, .key = keyboard_key, .modifiers = keyboard_modifiers, .repeat_info = keyboard_repeat_info, }; static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { wl_pointer_set_cursor(wl_pointer, serial, NULL, 0, 0); } static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { // Who cares } static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { // Who cares } static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { // Who cares } static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { // Who cares } static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { // Who cares } static void wl_pointer_axis_source(void *data, struct wl_pointer *wl_pointer, uint32_t axis_source) { // Who cares } static void wl_pointer_axis_stop(void *data, struct wl_pointer *wl_pointer, uint32_t time, uint32_t axis) { // Who cares } static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, uint32_t axis, int32_t discrete) { // Who cares } static const struct wl_pointer_listener pointer_listener = { .enter = wl_pointer_enter, .leave = wl_pointer_leave, .motion = wl_pointer_motion, .button = wl_pointer_button, .axis = wl_pointer_axis, .frame = wl_pointer_frame, .axis_source = wl_pointer_axis_source, .axis_stop = wl_pointer_axis_stop, .axis_discrete = wl_pointer_axis_discrete, }; static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum wl_seat_capability caps) { struct swaylock_seat *seat = data; if (seat->pointer) { wl_pointer_release(seat->pointer); seat->pointer = NULL; } if (seat->keyboard) { wl_keyboard_release(seat->keyboard); seat->keyboard = NULL; } if ((caps & WL_SEAT_CAPABILITY_POINTER)) { seat->pointer = wl_seat_get_pointer(wl_seat); wl_pointer_add_listener(seat->pointer, &pointer_listener, NULL); } if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { seat->keyboard = wl_seat_get_keyboard(wl_seat); wl_keyboard_add_listener(seat->keyboard, &keyboard_listener, seat); } } static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) { // Who cares } const struct wl_seat_listener seat_listener = { .capabilities = seat_handle_capabilities, .name = seat_handle_name, }; 07070100000029000081A400000000000000000000000166C8F38500000810000000000000000000000000000000000000001800000000swaylock-1.8.0/shadow.c#define _XOPEN_SOURCE // for crypt #include <assert.h> #include <pwd.h> #include <shadow.h> #include <stdlib.h> #include <stdbool.h> #include <sys/types.h> #include <unistd.h> #ifdef __GLIBC__ // GNU, you damn slimy bastard #include <crypt.h> #endif #include "comm.h" #include "log.h" #include "password-buffer.h" #include "swaylock.h" char *encpw = NULL; void initialize_pw_backend(int argc, char **argv) { /* This code runs as root */ struct passwd *pwent = getpwuid(getuid()); if (!pwent) { swaylock_log_errno(LOG_ERROR, "failed to getpwuid"); exit(EXIT_FAILURE); } encpw = pwent->pw_passwd; if (strcmp(encpw, "x") == 0) { struct spwd *swent = getspnam(pwent->pw_name); if (!swent) { swaylock_log_errno(LOG_ERROR, "failed to getspnam"); exit(EXIT_FAILURE); } encpw = swent->sp_pwdp; } if (setgid(getgid()) != 0) { swaylock_log_errno(LOG_ERROR, "Unable to drop root"); exit(EXIT_FAILURE); } if (setuid(getuid()) != 0) { swaylock_log_errno(LOG_ERROR, "Unable to drop root"); exit(EXIT_FAILURE); } if (setuid(0) != -1 || setgid(0) != -1) { swaylock_log_errno(LOG_ERROR, "Unable to drop root (we shouldn't be " "able to restore it after setuid/setgid)"); exit(EXIT_FAILURE); } /* This code does not run as root */ swaylock_log(LOG_DEBUG, "Prepared to authorize user %s", pwent->pw_name); if (!spawn_comm_child()) { exit(EXIT_FAILURE); } /* Buffer is only used by the child */ clear_buffer(encpw, strlen(encpw)); encpw = NULL; } void run_pw_backend_child(void) { assert(encpw != NULL); while (1) { char *buf; ssize_t size = read_comm_request(&buf); if (size < 0) { exit(EXIT_FAILURE); } else if (size == 0) { break; } const char *c = crypt(buf, encpw); password_buffer_destroy(buf, size); buf = NULL; if (c == NULL) { swaylock_log_errno(LOG_ERROR, "crypt failed"); exit(EXIT_FAILURE); } bool success = strcmp(c, encpw) == 0; if (!write_comm_reply(success)) { exit(EXIT_FAILURE); } sleep(2); } clear_buffer(encpw, strlen(encpw)); exit(EXIT_SUCCESS); } 0707010000002A000081A400000000000000000000000166C8F38500001790000000000000000000000000000000000000001E00000000swaylock-1.8.0/swaylock.1.scdswaylock(1) # NAME swaylock - Screen locker for Wayland # SYNOPSIS _swaylock_ [options...] Locks your Wayland session. # OPTIONS *-C, --config* <path> The config file to use. By default, the following paths are checked: _$HOME/.swaylock/config_, _$XDG\_CONFIG\_HOME/swaylock/config_, and _SYSCONFDIR/swaylock/config_. All flags aside from this one are valid options in the configuration file using the format _long-option=value_. For options such as _ignore-empty-password_, just supply the _long-option_. All leading dashes should be omitted and the equals sign is required for flags that take an argument. *-d, --debug* Enable debugging output. *-e, --ignore-empty-password* When an empty password is provided, do not validate it. *-F, --show-failed-attempts* Show current count of failed authentication attempts. *-f, --daemonize* Detach from the controlling terminal after locking. Note: this is the default behavior of i3lock. *-R, --ready-fd* <fd> File descriptor to send readiness notifications to. When the session has been locked, a single newline is written to the FD. At this point, the compositor guarantees that no security sensitive content is visible on-screen. *-h, --help* Show help message and quit. *-v, --version* Show the version number and quit. # APPEARANCE *-u, --no-unlock-indicator* Disable the unlock indicator. *-i, --image* [[<output>]:]<path> Display the given image, optionally only on the given output. Use -c to set a background color. If the path potentially contains a ':', prefix it with another ':' to prevent interpreting part of it as <output>. *-k, --show-keyboard-layout* Display the current xkb layout while typing. *-K, --hide-keyboard-layout* Force hiding the current xkb layout while typing, even if more than one layout is configured or the show-keyboard-layout option is set. *-L, --disable-caps-lock-text* Disable the Caps Lock text. *-l, --indicator-caps-lock* Show the current Caps Lock state also on the indicator. *-s, --scaling* Image scaling mode: _stretch_, _fill_, _fit_, _center_, _tile_, _solid\_color_. Use _solid\_color_ to display only the background color, even if a background image is specified. *-t, --tiling* Same as --scaling=tile. *-c, --color* <rrggbb[aa]> Turn the screen into the given color instead of white. If -i is used, this sets the background of the image to the given color. Defaults to white (FFFFFF). *--bs-hl-color* <rrggbb[aa]> Sets the color of backspace highlight segments. *--caps-lock-bs-hl-color* <rrggbb[aa]> Sets the color of backspace highlight segments when Caps Lock is active. *--caps-lock-key-hl-color* <rrggbb[aa]> Sets the color of the key press highlight segments when Caps Lock is active. *--font* <font> Sets the font of the text. *--font-size* <size> Sets a fixed font size for the indicator text. *--indicator-idle-visible* Sets the indicator to show even if idle. *--indicator-radius* <radius> Sets the indicator radius. The default value is 50. *--indicator-thickness* <thickness> Sets the indicator thickness. The default value is 10. *--indicator-x-position* <x> Sets the horizontal position of the indicator. *--indicator-y-position* <y> Sets the vertical position of the indicator. *--inside-color* <rrggbb[aa]> Sets the color of the inside of the indicator. *--inside-clear-color* <rrggbb[aa]> Sets the color of the inside of the indicator when cleared. *--inside-caps-lock-color* <rrggbb[aa]> Sets the color of the inside of the indicator when Caps Lock is active. *--inside-ver-color* <rrggbb[aa]> Sets the color of the inside of the indicator when verifying. *--inside-wrong-color* <rrggbb[aa]> Sets the color of the inside of the indicator when invalid. *--key-hl-color* <rrggbb[aa]> Sets the color of the key press highlight segments. *--layout-bg-color* <rrggbb[aa]> Sets the background color of the box containing the layout text. *--layout-border-color* <rrggbb[aa]> Sets the color of the border of the box containing the layout text. *--layout-text-color* <rrggbb[aa]> Sets the color of the layout text. *--line-color* <rrggbb[aa]> Sets the color of the line between the inside and ring. *--line-clear-color* <rrggbb[aa]> Sets the color of the line between the inside and ring when cleared. *--line-caps-lock-color* <rrggbb[aa]> Sets the color of the line between the inside and ring when Caps Lock is active. *--line-ver-color* <rrggbb[aa]> Sets the color of the line between the inside and ring when verifying. *--line-wrong-color* <rrggbb[aa]> Sets the color of the line between the inside and ring when invalid. *-n, --line-uses-inside* Use the inside color for the line between the inside and ring. *-r, --line-uses-ring* Use the ring color for the line between the inside and ring. *--ring-color* <rrggbb[aa]> Sets the color of the ring of the indicator when typing or idle. *--ring-clear-color* <rrggbb[aa]> Sets the color of the ring of the indicator when cleared. *--ring-caps-lock-color* <rrggbb[aa]> Sets the color of the ring of the indicator when Caps Lock is active. *--ring-ver-color* <rrggbb[aa]> Sets the color of the ring of the indicator when verifying. *--ring-wrong-color* <rrggbb[aa]> Sets the color of the ring of the indicator when invalid. *--separator-color* <rrggbb[aa]> Sets the color of the lines that separate highlight segments. *--text-color* <rrggbb[aa]> Sets the color of the text. *--text-clear-color* <rrggbb[aa]> Sets the color of the text when cleared. *--text-caps-lock-color* <rrggbb[aa]> Sets the color of the text when Caps Lock is active. *--text-ver-color* <rrggbb[aa]> Sets the color of the text when verifying. *--text-wrong-color* <rrggbb[aa]> Sets the color of the text when invalid. # SIGNALS *SIGUSR1* Unlock the screen and exit. # AUTHORS Maintained by Drew DeVault <sir@cmpwn.com>, who is assisted by other open source contributors. For more information about swaylock development, see https://github.com/swaywm/swaylock. 0707010000002B000081A400000000000000000000000166C8F385000004F3000000000000000000000000000000000000001900000000swaylock-1.8.0/unicode.c#include <stdint.h> #include <stddef.h> #include <string.h> #include "unicode.h" int utf8_last_size(const char *str) { int len = 0; char *pos = strchr(str, '\0'); while (pos > str) { --pos; ++len; if ((*pos & 0xc0) != 0x80) { return len; } } return 0; } size_t utf8_chsize(uint32_t ch) { if (ch < 0x80) { return 1; } else if (ch < 0x800) { return 2; } else if (ch < 0x10000) { return 3; } return 4; } size_t utf8_encode(char *str, uint32_t ch) { size_t len = 0; uint8_t first; if (ch < 0x80) { first = 0; len = 1; } else if (ch < 0x800) { first = 0xc0; len = 2; } else if (ch < 0x10000) { first = 0xe0; len = 3; } else { first = 0xf0; len = 4; } for (size_t i = len - 1; i > 0; --i) { str[i] = (ch & 0x3f) | 0x80; ch >>= 6; } str[0] = ch | first; return len; } static const struct { uint8_t mask; uint8_t result; int octets; } sizes[] = { { 0x80, 0x00, 1 }, { 0xE0, 0xC0, 2 }, { 0xF0, 0xE0, 3 }, { 0xF8, 0xF0, 4 }, { 0xFC, 0xF8, 5 }, { 0xFE, 0xF8, 6 }, { 0x80, 0x80, -1 }, }; int utf8_size(const char *s) { uint8_t c = (uint8_t)*s; for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); ++i) { if ((c & sizes[i].mask) == sizes[i].result) { return sizes[i].octets; } } return -1; } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!265 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor