diff --git a/user/swaylock-mobile/APKBUILD b/user/swaylock-mobile/APKBUILD new file mode 100644 index 0000000..3f2be8d --- /dev/null +++ b/user/swaylock-mobile/APKBUILD @@ -0,0 +1,78 @@ +# Contributor: Henrik Riomar +# Contributor: Michał Polański +# Maintainer: Jakub Jirutka +pkgname=swaylock-mobile +pkgver=1.6.11 +_pkgver=${pkgver/_/-} +pkgrel=0 +pkgdesc="Screen locker for Wayland with fancy effects" +url="https://github.com/jirutka/swaylock-effects" +arch="all" +license="MIT" +options="!check" # no test suite +makedepends=" + cairo-dev + libxkbcommon-dev + linux-pam-dev + meson + ninja + scdoc + wayland-dev + wayland-protocols + " +provider_priority=10 # lowest (other provider is swaylock aport) +provides="swaylock=$pkgver-r$pkgrel" +subpackages="$pkgname-dbg $pkgname-doc" +source="https://github.com/jirutka/swaylock-effects/archive/v$_pkgver/$pkgname-$_pkgver.tar.gz + add-mobile-keypad.patch" +builddir="$srcdir/swaylock-effects-$_pkgver" + +prepare() { + default_prepare + + sed -i 's/login/base-auth/g' pam/swaylock + + cat <<-__EOF__ >> pam/swaylock + + # Unlock GNOME Keyring if available + -auth optional pam_gnome_keyring.so + -session optional pam_gnome_keyring.so auto_start + + # Unlock KWallet if available + -auth optional pam_kwallet5.so + -session optional pam_kwallet5.so auto_start + __EOF__ +} + +build() { + # NOTE: completions are the same as the original swaylock provides. + abuild-meson \ + -Dgdk-pixbuf=disabled \ + -Dbash-completions=false \ + -Dfish-completions=false \ + -Dzsh-completions=false \ + . output + meson compile -C output --verbose +} + +package() { + DESTDIR="$pkgdir" meson install --no-rebuild -C output +} + +dbg() { + depends="!swaylock-dbg" + + default_dbg +} + +doc() { + provider_priority=10 # lowest (other provider is swaylock aport) + provides="swaylock-doc" + + default_doc +} + +sha512sums=" +ae8b5c5c36b11cb001a5dd30473051776962632675cde471d51ccfef000f44b5c279b3ac544040e854de6dc1a62eb8edccd5613fa1354795b40b3bd1cfba06a1 swaylock-mobile-1.6.11.tar.gz +756b1a84fc33ffd8480b460512704aec5270e9d39a2a4af66968860bc59d077b42e00ff6948f07da871ddd1dcb2d16af2abac8c4e7f20dbc0986f3d88b4e5fa3 add-mobile-keypad.patch +" diff --git a/user/swaylock-mobile/add-mobile-keypad.patch b/user/swaylock-mobile/add-mobile-keypad.patch new file mode 100644 index 0000000..93cd3c1 --- /dev/null +++ b/user/swaylock-mobile/add-mobile-keypad.patch @@ -0,0 +1,2668 @@ +diff --git a/INTEGRATION.md b/INTEGRATION.md +new file mode 100644 +index 0000000..3ca5df2 +--- /dev/null ++++ b/INTEGRATION.md +@@ -0,0 +1,51 @@ ++# Integrating swaylock into sxmo ++ ++By modifying some of the sxmo hooks (and adding a few), it is possible to replace sxmo's default "lock state" with swaylock instead ++ ++### Swaylock wrapper ++ ++The hook changes execute the wrapper script [run-screenlocker](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/scripts/run-screenlocker) instead of swaylock directly. This checks if swaylock exited with a success code or not, allowing us to restart it in the case of a crash. ++ ++***This must be on your $PATH, or things will go horribly wrong*** ++ ++### Modified hooks ++ ++- [sxmo_hook_inputhandler.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/sxmo_hook_inputhandler.sh) ++Powerbutton only turns the screen on/off, calls the lock hook before turning the screen off ++Corner swipe locks and turns off the screen ++ ++- [sxmo_hook_lock.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/sxmo_hook_lock.sh) ++Locks the screen, but only if currently in an unlocked state to prevent double locking ++Also calls the idlelock hook ++ ++- [sxmo_hook_proximitylock.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/sxmo_hook_proximitylock.sh) ++Calls the screen on hook instead of the unlock hook ++Disables the can_suspend mutex locking ++ ++- [sxmo_hook_screenoff.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/sxmo_hook_screenoff.sh) ++Stores the lock state in $SXMO_STATE.screen ++ ++- [sxmo_hook_unlock.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/sxmo_hook_unlock.sh) ++Uses the idlelock hook for setting the screenlocker ++ ++### New hooks ++ ++- [sxmo_hook_idlelocker.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/sxmo_hook_idlelocker.sh) ++Sets the idlelocker for screen on scenarios depending on $SXMO_STATE ++ ++- [sxmo_hook_screenon.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/sxmo_hook_screenon.sh) ++Handles turning on the screen, and related services ++ ++## Installation ++ ++- Add [these files](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/sxmo_hooks/) to `~/.config/sxmo/hooks/` (or modify your existing hooks) ++- Put [run-screenlocker](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/scripts/run-screenlocker) on your $PATH (e.g. `~/.local/bin/`) ++- Ensure sxmo_swaylock is installed as `swaylock` on your $PATH ++ ++## Known issues ++ ++- If swaylock is not installed/does not start properly, sxmo has a stroke when trying to lock the screen ++- If you get a call while the screen is off and locked, you cannot turn the screen on and have to wait for the call to expire. This might be caused by dmenu starting and stealing input handling, preventing the powerbutton from turning on the screen ++- Sometimes when turning on the phone while locked, screen input is disabled. This is rare and hard to debug, but an issue nonetheless ++- Disables the proximity lock suspend inhibitor, which might cause issues ++- When the phone is unlocked and the proximity sensor is active and covered and you press the power button, the screen turns on for a second then locks and turns off the screen +diff --git a/LICENSE b/LICENSE +index 6bf83e5..1e3ed7d 100644 +--- a/LICENSE ++++ b/LICENSE +@@ -1,6 +1,7 @@ + Copyright (c) 2016-present Drew DeVault + Copyright (c) 2020-2021 Martin Dørum + Copyright (c) 2021-present Jakub Jirutka ++Copyright (c) 2023-present John Crawford + + 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 +diff --git a/NOTIFICATIONS.md b/NOTIFICATIONS.md +new file mode 100644 +index 0000000..2099f72 +--- /dev/null ++++ b/NOTIFICATIONS.md +@@ -0,0 +1,38 @@ ++ ++ ++# sxmo_swaylock notifications ++ ++sxmo_swaylock has support to display notifications, which are fetched via the shell script [notifications.sh](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/scripts/notifications.sh) ++ ++# Using notifications ++ ++``` ++--notifications ++ Display notifications *--shell-directory must be set* ++ ++--notification-count ++ Number of notifications to display before displaying "+x more" ++ ++--shell-directory ++ The directory to look for 'notifications.sh' in ++``` ++ ++# Notification fetching ++ ++By default `notifications.sh` pulls in sxmo_common.sh and reads from the files in `$SXMO_NOTIFDIR`. It uses a shell script to support the easy creation of different notification fetch methods other than sxmo. ++ ++## Shell script requirements ++ ++If you wish to modify `notifications.sh`, it has to output notifications in a very specific way. The format is as follows ++ ++``` ++[length of output (not including this number)] ++[notification 1] ++[notification time string] ++. . . ++``` ++ ++Be sure to include a '\n' after each notification/timestamp ++ ++ ++ +diff --git a/README.md b/README.md +index 4af5f39..2d5f255 100644 +--- a/README.md ++++ b/README.md +@@ -1,103 +1,35 @@ +-# swaylock-effects ++# sxmo_swaylock + +-Swaylock-effects is a fork of [swaylock](https://github.com/swaywm/swaylock) +-which adds built-in screenshots and image manipulation effects like blurring. +-It's inspired by [i3lock-color](https://github.com/PandorasFox/i3lock-color), +-although the feature sets aren't perfectly overlapping. ++sxmo_swaylock is a fork of [swaylock-effects](https://github.com/jirutka/swaylock-effects) ++with the touchscreen keypad from [swaylock-mobile](https://codeberg.org/slatian/swaylock-mobile). ++This is intended to be used with [sxmo](https://sxmo.org/) on mobile devices, as sxmo currently ++does not have a proper password protected lockscreen + +-This repository ([jirutka/swaylock-effects](https://github.com/jirutka/swaylock-effects)) +-is a fork of [mortie/swaylock-effects](https://github.com/mortie/swaylock-effects) +-which is no longer maintained. ++## Features + +-![Screenshot](https://raw.githubusercontent.com/jirutka/swaylock-effects/master/screenshot.png) ++- Everything from [swaylock-effects](https://github.com/jirutka/swaylock-effects) (I have not tested that everything works) ++- Support for displaying [notifications](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/NOTIFICATIONS.md) ++- On screen 10 digit keypad for touchscreens ++- Flat style indicator from swaylock-mobile ++- Customizable indicator length (via --indicator-length) ++- Basic swipe gestures to toggle the keypad (via --swipe-gestures) ++- Battery indicator that replaces the swaylock typing indicator (via --battery-indicator) + +-## Example Command ++Current implementation is not super polished, but in it's current form suffices as a lockscreen and is ++better than what sxmo has by default. + +- swaylock \ +- --screenshots \ +- --clock \ +- --indicator \ +- --indicator-radius 100 \ +- --indicator-thickness 7 \ +- --effect-blur 7x5 \ +- --effect-vignette 0.5:0.5 \ +- --ring-color bb00cc \ +- --key-hl-color 880033 \ +- --line-color 00000000 \ +- --inside-color 00000088 \ +- --separator-color 00000000 \ +- --grace 2 \ +- --fade-in 0.2 ++[How to intergrate swaylock into sxmo](https://github.com/KaffeinatedKat/sxmo_swaylock/blob/master/INTEGRATION.md) + +-## New Features +- +-The main new features compared to upstream swaylock are: +- +-* `--screenshots` to use screenshots instead of an image on disk or a color +-* `--clock` to show date/time in the indicator +- * Use `--indicator` to make the indicator always active +- * Use `--timestr` and `--datestr` to set the date/time formats +- (using strftime-style formatting) +-* `--submit-on-touch` to use your touchscreen to submit a password. +- If you can unlock your device with anything else than your password, +- this might come helpful to trigger PAM's authentication process. +-* `--grace ` to set a password grace period, so that the password +- isn't required to unlock until some number of seconds have passed. +- * Used together with `--indicator`, the indicator is always shown, +- even in the grace period. +- * Used together with `--indicator-idle-visible`, the indicator is only +- visible after the grace period. +- * By default, a key press, a mouse event or a touch event will unlock +- during the grace period. Use `--grace-no-mouse` to not unlock as a response +- to a mouse event, and `--grace-no-touch` to not unlock as a response to +- a touch event. +-* `--fade-in ` to make the lock screen fade in. +-* Various effects which can be applied to the background image +- * `--effect-blur x`: Blur the image (thanks to yvbbrjdr's +- fast box blur algorithm in +- [i3lock-fancy-rapid](https://github.com/yvbbrjdr/i3lock-fancy-rapid)) +- * `--effect-pixelate `: Pixelate the image. +- * `--effect-scale `: Scale the image by a factor. This can be used +- to make other effects faster if you don't need the full resolution. +- * `--effect-greyscale`: Make the image greyscale. +- * `--effect-vignette :`: Apply a vignette effect (range is 0-1). +- * `--effect-compose ;;;`: Overlay another image. +- * `--effect-custom `: Load a custom effect from a C file or shared object. +- +-New feature ideas are welcome as issues (though I may never get around to +-implement them), new feature implementations are welcome as pull requests :) +- +-## Versions +- +-swaylock-effects continuously incorporates changes from the original [swaylock](https://github.com/swaywm/swaylock). +-The following table shows the relation between the swaylock-effect and swaylock versions. +- +-| swaylock-effects | swaylock (original) | +-| ---------------- | --------------------------------------------------------------------------------------------------- | +-| 1.6-0 | [1.5](https://github.com/swaywm/swaylock/tree/1.5) | +-| 1.6-1 | 1.5-7-g[a99afe6a](https://github.com/swaywm/swaylock/tree/a99afe6a7075c962da72b140f02e18318052d833) | +-| 1.6-2 | 1.5-9-g[235b925d](https://github.com/swaywm/swaylock/tree/235b925df7e1bb82d98f1ac8c02e8f85d0a54ee9) | +-| 1.6-3 | 1.5-9-g[235b925d](https://github.com/swaywm/swaylock/tree/235b925df7e1bb82d98f1ac8c02e8f85d0a54ee9) | +-| 1.6.10 | [1.6](https://github.com/swaywm/swaylock/tree/1.6) | +-| 1.6.11 | [1.6](https://github.com/swaywm/swaylock/tree/1.6) | ++## Planned Features + ++- Smooth animation for the keyboard swipe ++- More presise swipe gesture detection + more swipe gestures ++- Indicator modules (weather, etc) ++- Maybe a full keyboard instead of just the numbered keypad ++- More customization in regards to the keypad + + ## Installation + +-### From Packages +- +-* Alpine Linux: [swaylock-effects](https://pkgs.alpinelinux.org/packages?name=swaylock-effects) +-* Arch Linux (AUR): [swaylock-effects](https://aur.archlinux.org/packages/swaylock-effects/) / [swaylock-effects-git](https://aur.archlinux.org/packages/swaylock-effects-git/) +- +-The original [mortie/swaylock-effects](https://github.com/mortie/swaylock-effects) (now unmaintained) +-has been packaged for: +- +-* Fedora (Copr): [swaylock-effects](https://copr.fedorainfracloud.org/coprs/eddsalkield/swaylock-effects/) +- (thanks to Edd Salkield) +-* FreeBSD: [swaylock-effects](https://www.freshports.org/x11/swaylock-effects/) +-* Gentoo (GURU overlay): [swaylock-effects](https://gpo.zugaina.org/Overlays/guru/gui-apps/swaylock-effects) +-* T2 SDE: [swaylock-effects](https://t2sde.org/packages/swaylock-effects) +- + ### Compiling from Source + + Install dependencies: +@@ -129,75 +61,3 @@ On systems without PAM, you need to suid the swaylock binary: + + Swaylock will drop root permissions shortly after startup. + +-## Effects +- +-### Blur +- +-`--effect-blur x`: Blur the image. +- +-`` is a number specifying how big +-the blur is, `` is a number which specifies essentially how high quality the blur is +-(i.e how closely the effect will resemble a true gaussian blur). +- +-### Pixelate +- +-`--effect-pixelate `: Pixelate the image. +- +-`` is the amount of pixelation; a value of 10 will make each 10x10 square of pixels +-the same color. +- +-### Scale +- +-`--effect-scale `: Scale the image by a factor. +- +-This effect scales the internal buffer. This has a few uses: +- +-* Use `--effect-scale` in combination with `--scaling` to create a zoom effect: +- `--efect-scale 1.1 --scaling center` +-* Speed up other effects by making the resolution smaller: with +- `--effect-scale 0.5 --effect-blur 7x5 --effect-scale 2`, swaylock-effect needs to blur +- only 1/4 as many pixels. +- +-### Greyscale +- +-`--effect-greyscale`: Make the displayed image greyscale. +- +-### Vignette +- +-`--effect-vignette :`: Apply a vignette effect. +-Base and factor should be between 0 and 1. +- +-### Compose +- +-`--effect-compose ";;;"`: Overlay another image to your lock screen. +- +-* ``: Optional. The position on the screen to put the image, as `,`. +- * Can be a percentage (`10%,10%`), a number of pixels (`20,20`), or a mix (`30%,40`). +- * A negative number indicates that number of pixels away from the right/bottom instead of +- from the top/left; `-1,-1` would be the bottom right pixel. +- * Default: `50%,50%`. +-* ``: Optional. The size of the image on the screen, as `x`. +- * Can be a percentage (`10%x10%`), a number of pixels (`20x20`), or a mix (`30%x40`). +- * If the width is `-1`, the width is figured out based on the height and aspect ratio. +- * If the height is `-1`, the height is figured out based on the width and aspect ratio. +- * Default: The size of the image file. +-* ``: Optional. Determine which point of the image is placed at ``. +- * Possible values: `center`, `north`, `south`, `west`, `east`, +- `northwest`, `northeast`, southwest`, `southeast`. +- * With a `` of `northwest`, `` gives the location of the top/left +- corner of the image; with `southeast`, `` controls the bottom/right corner, +- `center` controls the middle of the image, etc. +- * Default: `center` if no `` is given; otherwise, intelligently decide a gravity +- based on position (`10,10` -> northwest, `-10,10` -> northeast, etc). +-* ``: The path to an image file. +- +-This command requires swaylock-effects to be compiled with gdk-pixbuf2. +-It supports all image formats gdk-pixbuf2 supports; on my system, that's +-png, jpeg, gif, svg, bmp, ico, tiff, wmf, ani, icns, pnm, qtif, tga, xbm and xpm. +- +-### Custom +- +-`--effect-custom `: Load a custom effect from a shared object. +- +-The .so must export a function `void swaylock_effect(uint32_t *data, int width, int height)` +-or a function `uint32_t swaylock_pixel(uint32_t pix, int x, int y, int width, int height)`. +diff --git a/include/seat.h b/include/seat.h +index daddd42..d96a545 100644 +--- a/include/seat.h ++++ b/include/seat.h +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + struct loop; + struct loop_timer; +diff --git a/include/swaylock.h b/include/swaylock.h +index ad259b6..26f3275 100644 +--- a/include/swaylock.h ++++ b/include/swaylock.h +@@ -1,7 +1,14 @@ + #ifndef _SWAYLOCK_H + #define _SWAYLOCK_H + #include ++#include + #include ++#include ++#include ++#include ++#include ++#include ++#include + #include + #include "background-image.h" + #include "cairo.h" +@@ -22,6 +29,17 @@ enum auth_state { + AUTH_STATE_GRACE, + }; + ++enum box_type { ++ TYPE_RENDER_KEY, ++ TYPE_RENDER_NOTIFICATION, ++}; ++ ++ ++struct swaylock_fetch { ++ int out[2]; ++ char notification_buffer[4096]; ++}; ++ + struct swaylock_colorset { + uint32_t input; + uint32_t cleared; +@@ -31,6 +49,9 @@ struct swaylock_colorset { + }; + + struct swaylock_colors { ++ uint32_t battery; ++ uint32_t battery_charging; ++ uint32_t battery_critical; + uint32_t background; + uint32_t bs_highlight; + uint32_t key_highlight; +@@ -44,21 +65,40 @@ struct swaylock_colors { + struct swaylock_colorset line; + struct swaylock_colorset ring; + struct swaylock_colorset text; ++ struct swaylock_colorset notif_text; ++ struct swaylock_colorset notif_time_text; + }; + + struct swaylock_args { +- struct swaylock_colors colors; +- enum background_mode mode; ++ struct swaylock_colors colors; enum background_mode mode; + char *font; ++ char *shell_dir; ++ char *notification_dir; ++ char *battery_path; ++ uint32_t battery_path_len; ++ uint32_t battery_critical; ++ uint32_t battery_fetch; ++ uint32_t shell_dir_len; ++ uint32_t margin; + uint32_t font_size; + uint32_t radius; + uint32_t thickness; + uint32_t indicator_x_position; + uint32_t indicator_y_position; ++ uint32_t indicator_length; ++ uint32_t notification_count; ++ bool battery_indicator; ++ bool notifications; ++ bool music; + bool override_indicator_x_position; + bool override_indicator_y_position; ++ bool override_indicator_length; ++ bool swipe_gestures; + bool ignore_empty; + bool show_indicator; ++ bool show_keypad; ++ bool show_music; ++ bool show_quickaction; + bool show_caps_lock_text; + bool show_caps_lock_indicator; + bool show_keyboard_layout; +@@ -99,13 +139,23 @@ struct swaylock_state { + struct zwlr_input_inhibit_manager_v1 *input_inhibit_manager; + struct zwlr_screencopy_manager_v1 *screencopy_manager; + struct wl_shm *shm; ++ struct swaylock_fetch fetch; + struct wl_list surfaces; + struct wl_list images; + struct swaylock_args args; + struct swaylock_password password; + struct swaylock_xkb xkb; + enum auth_state auth_state; ++ char* notifications_sh; ++ char notification_msgs[5][51], notification_stamps[5][51]; ++ size_t notification_amt, stamp_amt; ++ int swipe_x[50], swipe_y[50], swipe_count; + bool indicator_dirty; ++ char *battery_capacity_path; ++ char *battery_status_path; ++ char battery_capacity[3]; ++ char battery_status[1]; ++ bool battery_charging; + int render_randnum; + int failed_attempts; + size_t n_screenshots_done; +@@ -128,14 +178,22 @@ struct swaylock_surface { + struct wl_output *output; + uint32_t output_global_name; + struct zxdg_output_v1 *xdg_output; ++ struct wl_surface *indicator_child; // surface made into subsurface ++ struct wl_subsurface *indicator_subsurface; + struct wl_surface *surface; + struct wl_surface *child; // surface made into subsurface + struct wl_subsurface *subsurface; ++ struct wl_surface *keypad_child; ++ struct wl_subsurface *keypad_subsurface; ++ struct wl_surface *notification_child; ++ struct wl_subsurface *notification_subsurface; + struct zwlr_layer_surface_v1 *layer_surface; + struct zwlr_screencopy_frame_v1 *screencopy_frame; + struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1; + struct pool_buffer buffers[2]; + struct pool_buffer indicator_buffers[2]; ++ struct pool_buffer keypad_buffers[2]; ++ struct pool_buffer notification_buffers[2]; + struct pool_buffer *current_buffer; + struct swaylock_fade fade; + int events_pending; +@@ -143,6 +201,8 @@ struct swaylock_surface { + bool frame_pending, dirty; + uint32_t width, height; + uint32_t indicator_width, indicator_height; ++ uint32_t keypad_width, keypad_height; ++ uint32_t notification_witdh, notification_height; + int32_t scale; + enum wl_output_subpixel subpixel; + enum wl_output_transform transform; +@@ -158,14 +218,21 @@ struct swaylock_image { + struct wl_list link; + }; + ++cairo_t *cairo_init(struct swaylock_surface *surface); + void swaylock_handle_key(struct swaylock_state *state, + xkb_keysym_t keysym, uint32_t codepoint); + void swaylock_handle_mouse(struct swaylock_state *state); + void swaylock_handle_touch(struct swaylock_state *state); + void render_frame_background(struct swaylock_surface *surface, bool commit); + void render_background_fade(struct swaylock_surface *surface, uint32_t time); +-void render_frame(struct swaylock_surface *surface); ++void render_indicator_frame(struct swaylock_surface *surface); ++void render_keypad_frame(struct swaylock_surface *surface); ++void render_notification_frame(struct swaylock_surface *surface); + void render_frames(struct swaylock_state *state); ++void render_notifications(cairo_t *cario, struct swaylock_state *state, int spacing, ++ int key_height, int key_width, int pos_x, int pos_y); ++void draw_button(cairo_t *cairo, struct swaylock_surface *surface, char *text, int buffer_width, int buffer_height, ++ int x_divisions, int y_divisions, int x_pos, int y_pos); + void damage_surface(struct swaylock_surface *surface); + void damage_state(struct swaylock_state *state); + void clear_password_buffer(struct swaylock_password *pw); +@@ -175,4 +242,8 @@ void initialize_pw_backend(int argc, char **argv); + void run_pw_backend_child(void); + void clear_buffer(char *buf, size_t size); + ++int fetch_notifications(struct swaylock_state *state); ++int parse_notifications(struct swaylock_state *state, char *notifs, int size); ++int fetch_battery(); ++ + #endif +diff --git a/meson.build b/meson.build +index 50db6fb..0fe9465 100644 +--- a/meson.build ++++ b/meson.build +@@ -90,9 +90,9 @@ client_protocols = [ + [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], + [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], + [wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], +- ['wlr-layer-shell-unstable-v1.xml'], +- ['wlr-input-inhibitor-unstable-v1.xml'], +- ['wlr-screencopy-unstable-v1.xml'], ++ ['wayland-protocols/wlr-layer-shell-unstable-v1.xml'], ++ ['wayland-protocols/wlr-input-inhibitor-unstable-v1.xml'], ++ ['wayland-protocols/wlr-screencopy-unstable-v1.xml'], + ] + + foreach p : client_protocols +@@ -130,19 +130,20 @@ dependencies = [ + ] + + sources = [ +- 'background-image.c', +- 'cairo.c', +- 'comm.c', +- 'log.c', +- 'loop.c', +- 'main.c', +- 'password.c', +- 'pool-buffer.c', +- 'render.c', +- 'seat.c', +- 'unicode.c', +- 'effects.c', +- 'fade.c', ++ 'src/background-image.c', ++ 'src/cairo.c', ++ 'src/comm.c', ++ 'src/log.c', ++ 'src/loop.c', ++ 'src/main.c', ++ 'src/password.c', ++ 'src/pool-buffer.c', ++ 'src/render.c', ++ 'src/seat.c', ++ 'src/unicode.c', ++ 'src/effects.c', ++ 'src/fade.c', ++ 'src/fetch.c', + ] + + if libpam.found() +@@ -151,7 +152,7 @@ if libpam.found() + 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'] ++ sources += ['src/shadow.c'] + dependencies += [crypt] + endif + +diff --git a/scripts/notifications.sh b/scripts/notifications.sh +new file mode 100755 +index 0000000..9c3ecc0 +--- /dev/null ++++ b/scripts/notifications.sh +@@ -0,0 +1,39 @@ ++#!/bin/bash ++ ++# Include common sxmo definitions ++. sxmo_common.sh ++ ++DATE="$(date +%s)" ++ ++get_notifs() { ++ NOTIFS="" ++ for NOTIFFILE in $(ls -tr "$SXMO_NOTIFDIR"); do ++ MSG="$(tail -n+3 "$SXMO_NOTIFDIR/$NOTIFFILE" | tr "\n^" " ")" ++ ++ NOTIFS="${MSG::-1} ++$(time_string "$SXMO_NOTIFDIR/$NOTIFFILE") ++$NOTIFS" ++ ++ done ++ ++ printf "%d\n%s" "$(echo $NOTIFS | wc -c)" "$NOTIFS" ++} ++ ++time_string() { ++ FILEDATE="$(stat --printf %X $1 | cut -d'.' -f1)" ++ SECONDS=$(($DATE - $FILEDATE)) ++ ++ if [ ${SECONDS} -lt 60 ]; then ++ echo "Now" ++ elif [ $(($SECONDS / 60)) -lt 60 ]; then ++ echo "$(($SECONDS / 60))m ago" ++ elif [ $(($SECONDS / 60 / 60)) -lt 24 ]; then ++ echo "$(($SECONDS / 60 / 60))h ago" ++ elif [ $(($SECONDS / 60 / 60)) -lt 48 ]; then ++ echo "Yesterday at $(date -d @$FILEDATE +%R)" ++ else ++ echo "$(date -d @$FILEDATE +"%Y-%m-%d")" ++ fi ++} ++ ++get_notifs +diff --git a/scripts/run-screenlocker b/scripts/run-screenlocker +new file mode 100755 +index 0000000..dc45a7d +--- /dev/null ++++ b/scripts/run-screenlocker +@@ -0,0 +1,8 @@ ++sxmo_wm.sh inputevent touchscreen on ++ ++# I have swaylock-mobile installed as swaylock, will change that in the future ++while ! swaylock ; do ++ true ++done ++ ++sxmo_hook_unlock.sh +diff --git a/background-image.c b/src/background-image.c +similarity index 100% +rename from background-image.c +rename to src/background-image.c +diff --git a/cairo.c b/src/cairo.c +similarity index 99% +rename from cairo.c +rename to src/cairo.c +index be216da..2acd9a1 100644 +--- a/cairo.c ++++ b/src/cairo.c +@@ -43,6 +43,7 @@ cairo_surface_t *cairo_surface_duplicate(cairo_surface_t *src) { + return cairo_image_surface_create_for_data(new_data, format, width, height, stride); + } + ++ + #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); +diff --git a/comm.c b/src/comm.c +similarity index 100% +rename from comm.c +rename to src/comm.c +diff --git a/effects.c b/src/effects.c +similarity index 100% +rename from effects.c +rename to src/effects.c +diff --git a/fade.c b/src/fade.c +similarity index 100% +rename from fade.c +rename to src/fade.c +diff --git a/src/fetch.c b/src/fetch.c +new file mode 100644 +index 0000000..5dde315 +--- /dev/null ++++ b/src/fetch.c +@@ -0,0 +1,100 @@ ++#define _POSIX_C_SOURCE ++#include "log.h" ++#include "swaylock.h" ++#include ++#include ++#include ++ ++ ++int fetch_notifications(struct swaylock_state *state) { ++ //memset(state->fetch.notification_buffer, 0, 4096); ++ int buff_size = 0; ++ ++ // Check for errors and disable notifications ++ if (strcmp(state->args.shell_dir, "") == 0) { ++ swaylock_log(LOG_ERROR, "--shell-directory not set, disabling notifications"); ++ state->args.notifications = false; ++ return 1; ++ } else if (access(state->notifications_sh, F_OK) != 0) { ++ swaylock_log(LOG_ERROR, "notifications.sh not found at '%s', disabling notifications", state->notifications_sh); ++ state->args.notifications = false; ++ return 1; ++ } ++ ++ int pid = fork(); ++ ++ if (pid == 0) { ++ dup2(state->fetch.out[1], 1); ++ ++ char *args[] = { state->notifications_sh, NULL }; ++ execvp(state->notifications_sh, args); ++ _exit(0); ++ } ++ ++ ++ int x = 0; ++ while (1) { ++ read(state->fetch.out[0], &state->fetch.notification_buffer, 1); ++ ++ if (*state->fetch.notification_buffer == '\n') { ++ buff_size /= 10; ++ break; ++ } ++ buff_size += (*state->fetch.notification_buffer - '0'); ++ buff_size *= 10; ++ x++; ++ if (x > 100) { ++ swaylock_log(LOG_ERROR, "Notification script printed 100 values before the first newline, I doubt your notification list is a googol bytes long"); ++ return 1; ++ } ++ } ++ ++ // Script returns size of 1 if there are no notifications ++ if (buff_size <= 1) { ++ return 0; ++ } ++ ++ read(state->fetch.out[0], &state->fetch.notification_buffer, buff_size); ++ swaylock_log(LOG_DEBUG, "Notification script length: %d", buff_size); ++ ++ return parse_notifications(state, state->fetch.notification_buffer, buff_size); ++} ++ ++int parse_notifications(struct swaylock_state *state, char *notifs, int size) { ++ size_t notif_size = 0; ++ bool stamp = false; ++ state->notification_amt = 0; ++ state->stamp_amt = 0; ++ state->notification_amt = 0; ++ ++ for (int i = 0; i < size; i++) { ++ // Store the current iteration position ++ notif_size = i; ++ // Add to size till a newline is found ++ while (notifs[notif_size] != '\n') { notif_size++; } ++ // Subtract i to get the size of the messages ++ notif_size -= i; ++ if (notif_size > 45) { ++ notif_size = 45; ++ } else if (notif_size <= 0) { ++ return 0; // End of output ++ } ++ ++ // Append to timestamp list ++ if (stamp) { ++ memcpy(state->notification_stamps[state->stamp_amt], notifs+i, notif_size); ++ state->notification_stamps[state->stamp_amt++][notif_size] = '\0'; ++ stamp = false; ++ // Append the notification msg list ++ } else { ++ memcpy(state->notification_msgs[state->notification_amt], notifs+i, notif_size); ++ state->notification_msgs[state->notification_amt++][notif_size] = '\0'; ++ stamp = true; ++ } ++ ++ notif_size = 0; ++ while (notifs[i] != '\n') { i++; } ++ } ++ ++ return 0; ++} +diff --git a/log.c b/src/log.c +similarity index 100% +rename from log.c +rename to src/log.c +diff --git a/loop.c b/src/loop.c +similarity index 100% +rename from loop.c +rename to src/loop.c +diff --git a/main.c b/src/main.c +similarity index 89% +rename from main.c +rename to src/main.c +index a361c16..e88c258 100644 +--- a/main.c ++++ b/src/main.c +@@ -1,3 +1,4 @@ ++#include + #define _POSIX_C_SOURCE 200809L + #include + #include +@@ -257,6 +258,11 @@ static void destroy_surface(struct swaylock_surface *surface) { + destroy_buffer(&surface->buffers[1]); + destroy_buffer(&surface->indicator_buffers[0]); + destroy_buffer(&surface->indicator_buffers[1]); ++ destroy_buffer(&surface->keypad_buffers[0]); ++ destroy_buffer(&surface->keypad_buffers[1]); ++ destroy_buffer(&surface->notification_buffers[0]); ++ destroy_buffer(&surface->notification_buffers[1]); ++ + wl_output_destroy(surface->output); + free(surface); + } +@@ -297,6 +303,13 @@ static void create_surface(struct swaylock_surface *surface) { + assert(surface->subsurface); + wl_subsurface_set_sync(surface->subsurface); + ++ surface->keypad_child = wl_compositor_create_surface(state->compositor); ++ assert(surface->keypad_child); ++ surface->keypad_subsurface = wl_subcompositor_get_subsurface(state->subcompositor, surface->keypad_child, surface->surface); ++ assert(surface->keypad_subsurface); ++ wl_subsurface_set_sync(surface->keypad_subsurface); ++ ++ + if (state->ext_session_lock_v1) { + surface->ext_session_lock_surface_v1 = ext_session_lock_v1_get_lock_surface( + state->ext_session_lock_v1, surface->surface, surface->output); +@@ -340,7 +353,8 @@ static void initially_render_surface(struct swaylock_surface *surface) { + + if (!surface->state->ext_session_lock_v1) { + render_frame_background(surface, true); +- render_frame(surface); ++ render_indicator_frame(surface); ++ render_keypad_frame(surface); + } + } + +@@ -353,6 +367,8 @@ static void layer_surface_configure(void *data, + surface->height = height; + surface->indicator_width = 0; + surface->indicator_height = 0; ++ surface->keypad_width = 0; ++ surface->keypad_height = 0; + zwlr_layer_surface_v1_ack_configure(layer_surface, serial); + + if (!surface->configured && --surface->events_pending == 0) { +@@ -387,7 +403,8 @@ static void ext_session_lock_surface_v1_handle_configure(void *data, + render_frame_background(surface, false); + ext_session_lock_surface_v1_ack_configure(lock_surface, serial); + wl_surface_commit(surface->surface); +- render_frame(surface); ++ render_indicator_frame(surface); ++ render_keypad_frame(surface); + } + + static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener = { +@@ -415,7 +432,8 @@ static void surface_frame_handle_done(void *data, struct wl_callback *callback, + surface->dirty = true; + } + +- render_frame(surface); ++ render_indicator_frame(surface); ++ render_keypad_frame(surface); + } + } + +@@ -902,15 +920,18 @@ static void set_default_colors(struct swaylock_colors *colors) { + colors->caps_lock_bs_highlight = 0xDB3300FF; + colors->caps_lock_key_highlight = 0x33DB00FF; + colors->separator = 0x000000FF; ++ colors->battery = 0x337D00FF; ++ colors->battery_charging = 0xFFEA00FF; ++ colors->battery_critical = 0xFA0000C0; + colors->layout_background = 0x000000C0; + colors->layout_border = 0x00000000; + colors->layout_text = 0xFFFFFFFF; + colors->inside = (struct swaylock_colorset){ + .input = 0x000000C0, +- .cleared = 0xE5A445C0, ++ .cleared = 0x000000C0, + .caps_lock = 0x000000C0, +- .verifying = 0x0072FFC0, +- .wrong = 0xFA0000C0, ++ .verifying = 0x000000C0, ++ .wrong = 0x000000C0, + }; + colors->line = (struct swaylock_colorset){ + .input = 0x000000FF, +@@ -928,10 +949,24 @@ static void set_default_colors(struct swaylock_colors *colors) { + }; + colors->text = (struct swaylock_colorset){ + .input = 0xE5A445FF, +- .cleared = 0x000000FF, ++ .cleared = 0xE5A445FF, + .caps_lock = 0xE5A445FF, +- .verifying = 0x000000FF, +- .wrong = 0x000000FF, ++ .verifying = 0xE5A445FF, ++ .wrong = 0xE5A445FF, ++ }; ++ colors->notif_text = (struct swaylock_colorset){ ++ .input = 0xFFFFFFFF, ++ .cleared = 0xFFFFFFFF, ++ .caps_lock = 0xFFFFFFFF, ++ .verifying = 0xFFFFFFFF, ++ .wrong = 0xFFFFFFFF, ++ }; ++ colors->notif_time_text = (struct swaylock_colorset){ ++ .input = 0x474747FF, ++ .cleared = 0x474747FF, ++ .caps_lock = 0x474747FF, ++ .verifying = 0x474747FF, ++ .wrong = 0x474747FF, + }; + } + +@@ -945,15 +980,24 @@ 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_TRACE, ++ LO_MARGIN, ++ LO_SWIPE_GESTURES, ++ LO_SHELL_DIR, ++ LO_NOTIFICATIONS, ++ LO_NOTIF_COUNT, + LO_BS_HL_COLOR = 256, + LO_CAPS_LOCK_BS_HL_COLOR, + LO_CAPS_LOCK_KEY_HL_COLOR, + LO_FONT, + LO_FONT_SIZE, ++ LO_BATTERY, ++ LO_BATTERY_REFRESH, ++ LO_BATTERY_CRITICAL, + LO_IND_IDLE_VISIBLE, + LO_IND_RADIUS, + LO_IND_X_POSITION, + LO_IND_Y_POSITION, ++ LO_IND_LENGTH, + LO_IND_THICKNESS, + LO_INSIDE_COLOR, + LO_INSIDE_CLEAR_COLOR, +@@ -1008,6 +1052,10 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + {"daemonize", no_argument, NULL, 'f'}, + {"help", no_argument, NULL, 'h'}, + {"image", required_argument, NULL, 'i'}, ++ {"shell-directory", required_argument, NULL, LO_SHELL_DIR}, ++ {"notifications", no_argument, NULL, LO_NOTIFICATIONS}, ++ {"notification-count", required_argument, NULL, LO_NOTIF_COUNT}, ++ {"swipe-gestures", no_argument, NULL, LO_SWIPE_GESTURES}, + {"screenshots", no_argument, NULL, 'S'}, + {"disable-caps-lock-text", no_argument, NULL, 'L'}, + {"indicator-caps-lock", no_argument, NULL, 'l'}, +@@ -1025,11 +1073,15 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + {"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}, ++ {"battery-indicator", required_argument, NULL, LO_BATTERY}, ++ {"battery-refresh", required_argument, NULL, LO_BATTERY_REFRESH}, ++ {"battery-critical", required_argument, NULL, LO_BATTERY_CRITICAL}, + {"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}, ++ {"indicator-length", required_argument, NULL, LO_IND_LENGTH}, + {"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}, +@@ -1044,6 +1096,7 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + {"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}, ++ {"margin", required_argument, NULL, LO_MARGIN}, + {"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}, +@@ -1122,6 +1175,21 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + "Same as --scaling=tile.\n" + " -u, --no-unlock-indicator " + "Disable the unlock indicator.\n" ++ " --shell-directory " ++ "Path to the directory containing the shell scripts\n" ++ " --notifications " ++ "Display notifications when the keypad is down.\n" ++ " --notification-count " ++ "Amount of notifications to display at once.\n" ++ " --swipe-gestures " ++ "Swipe up and down to reveal/hide keypad.\n" ++ " --battery-indicator " ++ "Replace the swaylock typing indicator with a battery bar\n" ++ " Must specify the path to the battery (eg. /sys/class/power_supply/BAT0)\n" ++ " --battery-refresh " ++ "How often swaylock checks the battery in seconds (default: 2)" ++ " --battery-critical " ++ "The point at which the battery indicator changes to red (default: 20%)" + " --indicator " + "Always show the indicator.\n" + " --clock " +@@ -1154,6 +1222,8 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + "Sets the horizontal position of the indicator.\n" + " --indicator-y-position " + "Sets the vertical position of the indicator.\n" ++ " --indicator-length " ++ "Sets the length of the indicator.\n" + " --inside-color " + "Sets the color of the inside of the indicator.\n" + " --inside-clear-color " +@@ -1334,6 +1404,29 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + fprintf(stdout, "swaylock version " SWAYLOCK_VERSION "\n"); + exit(EXIT_SUCCESS); + break; ++ case LO_SHELL_DIR: ++ if (state) { ++ state->args.shell_dir_len = strlen(optarg); ++ state->args.shell_dir = malloc(sizeof(char*) * state->args.shell_dir_len); ++ memcpy(state->args.shell_dir, optarg, state->args.shell_dir_len); ++ } ++ break; ++ case LO_NOTIF_COUNT: ++ if (state) { ++ state->args.notification_count = atoi(optarg); ++ } ++ break; ++ case LO_NOTIFICATIONS: ++ if (state) { ++ state->args.notifications = true; ++ } ++ break; ++ case LO_SWIPE_GESTURES: ++ if (state) { ++ state->args.swipe_gestures = true; ++ state->args.show_keypad = false; ++ } ++ break; + case LO_BS_HL_COLOR: + if (state) { + state->args.colors.bs_highlight = parse_color(optarg); +@@ -1360,6 +1453,38 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + state->args.font_size = atoi(optarg); + } + break; ++ case LO_BATTERY: ++ if (state) { ++ state->args.battery_indicator = true; ++ state->args.colors.ring = state->args.colors.inside; ++ ++ state->args.battery_path_len = strlen(optarg); ++ state->args.battery_path = malloc(sizeof(char*) * state->args.battery_path_len); ++ memcpy(state->args.battery_path, optarg, state->args.battery_path_len); ++ ++ state->battery_capacity_path = malloc(sizeof(char*) * (state->args.battery_path_len + 9)); ++ memcpy(state->battery_capacity_path, state->args.battery_path, state->args.battery_path_len); ++ memcpy(state->battery_capacity_path+state->args.battery_path_len, "capacity", 8); ++ state->battery_capacity_path[state->args.battery_path_len + 9] = '\0'; ++ swaylock_log(LOG_DEBUG, "%s", state->battery_capacity_path); ++ ++ state->battery_status_path = malloc(sizeof(char*) * (state->args.battery_path_len + 7)); ++ memcpy(state->battery_status_path, state->args.battery_path, state->args.battery_path_len); ++ memcpy(state->battery_status_path+state->args.battery_path_len, "status", 7); ++ state->battery_status_path[state->args.battery_path_len + 8] = '\0'; ++ swaylock_log(LOG_DEBUG, "%s", state->battery_status_path); ++ } ++ break; ++ case LO_BATTERY_REFRESH: ++ if (state) { ++ state->args.battery_fetch = atoi(optarg); ++ } ++ break; ++ case LO_BATTERY_CRITICAL: ++ if (state) { ++ state->args.battery_critical = atoi(optarg); ++ } ++ break; + case LO_IND_IDLE_VISIBLE: + if (state) { + state->args.indicator_idle_visible = true; +@@ -1387,6 +1512,12 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + state->args.indicator_y_position = atoi(optarg); + } + break; ++ case LO_IND_LENGTH: ++ if (state) { ++ state->args.override_indicator_length = true; ++ state->args.indicator_length = atoi(optarg); ++ } ++ break; + case LO_INSIDE_COLOR: + if (state) { + state->args.colors.inside.input = parse_color(optarg); +@@ -1462,6 +1593,11 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, + state->args.colors.ring.input = parse_color(optarg); + } + break; ++ case LO_MARGIN: ++ if (state) { ++ state->args.margin = strtol(optarg, NULL, 0); ++ } ++ break; + case LO_RING_CLEAR_COLOR: + if (state) { + state->args.colors.ring.cleared = parse_color(optarg); +@@ -1757,9 +1893,33 @@ static void comm_in(int fd, short mask, void *data) { + static void timer_render(void *data) { + struct swaylock_state *state = (struct swaylock_state *)data; + damage_state(state); ++ ++ if (state->args.notifications) { ++ fetch_notifications(state); ++ } ++ + loop_add_timer(state->eventloop, 1000, timer_render, state); + } + ++static void get_battery_timer(void *data) { ++ struct swaylock_state *state = (struct swaylock_state *)data; ++ int cap; ++ int stat; ++ ++ cap = open(state->battery_capacity_path, O_RDONLY); ++ stat = open(state->battery_status_path, O_RDONLY); ++ ++ read(cap, state->battery_capacity, 3); ++ read(stat, state->battery_status, 1); ++ ++ if (*state->battery_status == 'C') { state->battery_charging = true; } ++ else { state->battery_charging = false; } ++ ++ close(cap); ++ close(stat); ++ loop_add_timer(state->eventloop, state->args.battery_fetch * 1000, get_battery_timer, state); ++} ++ + int main(int argc, char **argv) { + swaylock_log_init(LOG_ERROR); + initialize_pw_backend(argc, argv); +@@ -1768,16 +1928,30 @@ int main(int argc, char **argv) { + enum line_mode line_mode = LM_LINE; + state.failed_attempts = 0; + state.indicator_dirty = false; ++ state.swipe_count = 0; ++ state.notification_amt = 0; ++ state.stamp_amt = 0; + state.args = (struct swaylock_args){ ++ .shell_dir = "", ++ .shell_dir_len = 0, ++ .show_keypad = true, ++ .swipe_gestures = false, ++ .notifications = false, ++ .battery_indicator = false, ++ .battery_critical = 20, ++ .battery_fetch = 2, ++ .notification_count = 4, + .mode = BACKGROUND_MODE_FILL, + .font = strdup("sans-serif"), + .font_size = 0, ++ .margin = 20, + .radius = 75, + .thickness = 10, + .indicator_x_position = 0, + .indicator_y_position = 0, + .override_indicator_x_position = false, + .override_indicator_y_position = false, ++ .override_indicator_length = false, + .ignore_empty = false, + .show_indicator = true, + .show_caps_lock_indicator = false, +@@ -1797,6 +1971,7 @@ int main(int argc, char **argv) { + .allow_fade = true, + .password_grace_period = 0, + }; ++ + wl_list_init(&state.images); + set_default_colors(&state.args.colors); + +@@ -1829,6 +2004,24 @@ int main(int argc, char **argv) { + } + } + ++ // Allocate and define notification script path ++ if (strcmp(state.args.shell_dir, "") != 0) { ++ state.notifications_sh = malloc(sizeof(char*) * state.args.shell_dir_len + 17); ++ memcpy(state.notifications_sh, state.args.shell_dir, state.args.shell_dir_len); ++ memcpy(state.notifications_sh+state.args.shell_dir_len, "notifications.sh", 17); ++ swaylock_log(LOG_DEBUG, "notification script path set at '%s'", state.notifications_sh); ++ } ++ ++ ++ if (state.args.notifications) { ++ if (pipe(state.fetch.out) == -1) { ++ int err = errno; ++ swaylock_log(LOG_ERROR, "Fetch notification: pipe failed: %s", strerror(err)); ++ state.args.notifications = false; ++ } ++ fetch_notifications(&state); ++ } ++ + if (line_mode == LM_INSIDE) { + state.args.colors.line = state.args.colors.inside; + } else if (line_mode == LM_RING) { +@@ -1949,6 +2142,8 @@ int main(int argc, char **argv) { + + loop_add_timer(state.eventloop, 1000, timer_render, &state); + ++ if (state.args.battery_indicator) { get_battery_timer(&state); } ++ + if (state.args.fade_in) { + loop_add_timer(state.eventloop, state.args.fade_in, end_allow_fade_period, &state); + } +@@ -1963,6 +2158,7 @@ int main(int argc, char **argv) { + loop_add_timer(state.eventloop, state.args.password_grace_period, end_grace_period, &state); + } + ++ + // Re-draw once to start the draw loop + damage_state(&state); + +@@ -1983,6 +2179,12 @@ int main(int argc, char **argv) { + wl_display_flush(state.display); + } + ++ if (strcmp(state.args.shell_dir, "") != 0) { free(state.notifications_sh); } ++ if (state.args.battery_indicator) { ++ free(state.args.battery_path); ++ free(state.battery_capacity_path); ++ free(state.battery_status_path); ++ } + free(state.args.font); + return 0; + } +diff --git a/src/notification.c b/src/notification.c +new file mode 100644 +index 0000000..1305d7b +--- /dev/null ++++ b/src/notification.c +@@ -0,0 +1,31 @@ ++#include ++#include ++ ++//#include "swaylock.h" ++ ++void fetch_notifications(/*struct swaylock_state *state*/) { ++ int out[2]; ++ char buff[2048]; ++ ++ if (pipe(out) == -1) { ++ printf("pipe failed"); ++ return; ++ } ++ ++ int pid = fork(); ++ ++ if (pid == 0) { ++ dup2(out[1], 1); ++ ++ char *args[] = { "/home/coffee/swaylock-effects/scripts/notifications.sh", "/home/coffee/swaylock-effects/notifs/", NULL }; ++ execvp("/home/coffee/swaylock-effects/scripts/notifications.sh", args); ++ } ++ ++ read(out[0], buff, 2048); ++ printf("notifications: %s\n", buff); ++} ++ ++ ++int main(void) { ++ fetch_notifications(); ++} +diff --git a/password.c b/src/password.c +similarity index 99% +rename from password.c +rename to src/password.c +index a77ae5c..62da787 100644 +--- a/password.c ++++ b/src/password.c +@@ -175,6 +175,7 @@ void swaylock_handle_key(struct swaylock_state *state, + break; + } + // fallthrough ++ case 0: + default: + if (codepoint) { + append_ch(&state->password, codepoint); +diff --git a/pool-buffer.c b/src/pool-buffer.c +similarity index 100% +rename from pool-buffer.c +rename to src/pool-buffer.c +diff --git a/render.c b/src/render.c +similarity index 52% +rename from render.c +rename to src/render.c +index 655c5b1..4004794 100644 +--- a/render.c ++++ b/src/render.c +@@ -1,10 +1,14 @@ + #include ++#include ++#include + #include + #include + #include ++#include + #include + #include "cairo.h" + #include "background-image.h" ++#include "log.h" + #include "swaylock.h" + + #define M_PI 3.14159265358979323846 +@@ -63,6 +67,110 @@ static void timetext(struct swaylock_surface *surface, char **tstr, char **dstr) + setlocale(LC_TIME, prevloc); + } + ++cairo_t *cairo_init(struct swaylock_surface *surface) { ++ cairo_t *cairo = surface->current_buffer->cairo; ++ cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); ++ 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(surface->subpixel)); ++ cairo_set_font_options(cairo, fo); ++ cairo_font_options_destroy(fo); ++ 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); ++ ++ return cairo; ++} ++ ++ ++void draw_notification(cairo_t *cairo, struct swaylock_state *state, ++ char text[30], char *timestamp, int pos_x, int pos_y, int width, int height) { ++ ++ set_color_for_state(cairo, state, &state->args.colors.inside); ++ cairo_rectangle(cairo, pos_x, pos_y, width, height); ++ cairo_fill(cairo); ++ // Draw notification text ++ cairo_text_extents_t extents; ++ cairo_font_extents_t fe; ++ cairo_text_extents(cairo, text, &extents); ++ cairo_font_extents(cairo, &fe); ++ set_color_for_state(cairo, state, &state->args.colors.notif_text); ++ cairo_move_to(cairo, pos_x + 20, pos_y + height - 20); ++ cairo_show_text(cairo, text); ++ ++ // Draw timestamp ++ cairo_select_font_face (cairo, state->args.font, CAIRO_FONT_SLANT_OBLIQUE, CAIRO_FONT_WEIGHT_BOLD); ++ set_color_for_state(cairo, state, &state->args.colors.notif_time_text); ++ cairo_text_extents(cairo, timestamp, &extents); ++ cairo_font_extents(cairo, &fe); ++ cairo_move_to(cairo, pos_x + width - extents.width - 20, pos_y + 40); ++ cairo_show_text(cairo, timestamp); ++ cairo_select_font_face (cairo, state->args.font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); ++} ++ ++void draw_keypad_key(cairo_t *cairo, struct swaylock_state *state, ++ char *text, int pos_x, int pos_y, int width, int height) { ++ // Draw button ++ set_color_for_state(cairo, state, &state->args.colors.inside); ++ cairo_rectangle(cairo, pos_x, pos_y, width, height); ++ cairo_fill(cairo); ++ ++ // Draw border ++ cairo_set_source_u32(cairo, state->args.colors.separator); ++ cairo_set_line_width(cairo, 4); ++ ++ cairo_rectangle(cairo, pos_x, pos_y, width, height); ++ cairo_stroke(cairo); ++ // Draw text ++ cairo_text_extents_t extents; ++ cairo_font_extents_t fe; ++ cairo_text_extents(cairo, text, &extents); ++ cairo_font_extents(cairo, &fe); ++ set_color_for_state(cairo, state, &state->args.colors.text); ++ cairo_move_to(cairo, pos_x + (width - extents.width) / 2, pos_y + height / 2 + fe.ascent / 2); ++ cairo_show_text(cairo, text); ++} ++ ++ ++void draw_button(cairo_t *cairo, struct swaylock_surface *surface, char *text, int buffer_width, int buffer_height, ++ int x_divisions, int y_divisions, int x_pos, int y_pos) { ++ int length = buffer_width / x_divisions; ++ int height = buffer_height / y_divisions; ++ int x_spacer = 0, y_spacer = 0; ++ ++ for (int x = 0; x < x_divisions; x++) { ++ for (int y = 0; y < y_divisions; y++) { ++ // Reset y_spacer at new loop ++ if (y == 0) y_spacer = 0; ++ ++ // Draw the button and return ++ if (y == y_pos && x == x_pos) { ++ cairo_rectangle(cairo, surface->scale + x_spacer, surface->scale + y_spacer, length, height); ++ cairo_stroke(cairo); ++ // Draw text ++ cairo_text_extents_t extents; ++ cairo_font_extents_t fe; ++ cairo_text_extents(cairo, text, &extents); ++ cairo_font_extents(cairo, &fe); ++ set_color_for_state(cairo, surface->state, &surface->state->args.colors.text); ++ cairo_move_to(cairo, surface->scale + x_spacer + (length - extents.width) / 2, surface->scale + y_spacer + height / 2 + fe.ascent / 2); ++ cairo_show_text(cairo, text); ++ ++ return; ++ } ++ y_spacer += height; ++ } ++ x_spacer += length; ++ } ++} ++ ++ + void render_frame_background(struct swaylock_surface *surface, bool commit) { + struct swaylock_state *state = surface->state; + +@@ -116,11 +224,13 @@ void render_background_fade(struct swaylock_surface *surface, uint32_t time) { + fade_update(&surface->fade, time); + + render_frame_background(surface, true); +- render_frame(surface); ++ render_indicator_frame(surface); ++ render_keypad_frame(surface); + } + +-void render_frame(struct swaylock_surface *surface) { ++void render_indicator_frame(struct swaylock_surface *surface) { + struct swaylock_state *state = surface->state; ++ render_frame_background(surface, true); + + int arc_radius = state->args.radius * surface->scale; + int arc_thickness = state->args.thickness * surface->scale; +@@ -151,7 +261,15 @@ void render_frame(struct swaylock_surface *surface) { + (state->args.radius + state->args.thickness); + } + +- wl_subsurface_set_position(surface->subsurface, subsurf_xpos, subsurf_ypos); ++ if (state->args.override_indicator_length) { ++ new_width = state->args.indicator_length; ++ } ++ ++ if (state->args.show_quickaction) { ++ new_height += 150; ++ } ++ ++ wl_subsurface_set_position(surface->subsurface, subsurf_xpos, subsurf_ypos / 2); + + surface->current_buffer = get_next_buffer(state->shm, + surface->indicator_buffers, buffer_width, buffer_height); +@@ -163,25 +281,7 @@ void render_frame(struct swaylock_surface *surface) { + wl_surface_attach(surface->child, NULL, 0, 0); + wl_surface_commit(surface->child); + +- cairo_t *cairo = surface->current_buffer->cairo; +- cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); +- 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(surface->subpixel)); +- cairo_set_font_options(cairo, fo); +- cairo_font_options_destroy(fo); +- 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; ++ cairo_t *cairo = cairo_init(surface); + + // This is a bit messy. + // After the fork, upstream added their own --indicator-idle-visible option, +@@ -194,21 +294,33 @@ void render_frame(struct swaylock_surface *surface) { + + if (state->args.indicator || + (upstream_show_indicator && state->auth_state != AUTH_STATE_GRACE)) { +- // Fill inner circle ++ // Fill background box + cairo_set_line_width(cairo, 0); +- cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, +- arc_radius - arc_thickness / 2, 0, 2 * M_PI); ++ cairo_rectangle(cairo, 0, 0, buffer_width, buffer_height); + 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); ++ // Draw indicator ++ cairo_rectangle(cairo, 0, 0, buffer_width, arc_thickness); + set_color_for_state(cairo, state, &state->args.colors.ring); ++ cairo_fill_preserve(cairo); + cairo_stroke(cairo); + ++ // Draw battery percentage ++ if (state->args.battery_indicator) { ++ uint32_t charge = atoi(state->battery_capacity); ++ ++ // Change color based on charge level ++ if (state->battery_charging) { cairo_set_source_u32(cairo, state->args.colors.battery_charging); } ++ else if (charge < state->args.battery_critical) { cairo_set_source_u32(cairo, state->args.colors.battery_critical); } ++ else { cairo_set_source_u32(cairo, state->args.colors.battery); } ++ ++ cairo_rectangle(cairo, 0, 0, (buffer_width*charge)/100.0, arc_thickness); ++ cairo_fill_preserve(cairo); ++ cairo_stroke(cairo); ++ } ++ + // Draw a message + char *text = NULL; + char *text_l1 = NULL; +@@ -345,53 +457,51 @@ void render_frame(struct swaylock_surface *surface) { + if (state->auth_state == AUTH_STATE_INPUT + || state->auth_state == AUTH_STATE_BACKSPACE) { + +- static double highlight_start = 0; +- if (state->indicator_dirty) { +- highlight_start += +- (rand() % (int)(M_PI * 100)) / 100.0 + M_PI * 0.5; +- state->indicator_dirty = false; +- } ++ if (state->args.battery_indicator == false) { ++ // Fallback to swaylock typing indicator ++ static double highlight_start = 0; ++ int highlight_width = (arc_radius*TYPE_INDICATOR_RANGE/M_PI); ++ float border_width = 2.0 * surface->scale; + +- cairo_arc(cairo, buffer_width / 2, buffer_diameter / 2, +- arc_radius, highlight_start, +- highlight_start + TYPE_INDICATOR_RANGE); +- if (state->auth_state == AUTH_STATE_INPUT) { +- 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); ++ if (state->indicator_dirty) { ++ highlight_start = ++ (rand() % (int)(buffer_width - highlight_width - border_width * 2)); ++ state->indicator_dirty = false; + } +- } +- 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_set_line_width(cairo, arc_thickness); ++ cairo_rectangle(cairo, highlight_start, 0, highlight_width, arc_thickness); + +- 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); ++ if (state->auth_state == AUTH_STATE_INPUT) { ++ 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_fill_preserve(cairo); ++ } + } + +- // Draw inner + outer border of the circle +- set_color_for_state(cairo, state, &state->args.colors.line); ++ // Draw borders ++ cairo_set_source_u32(cairo, state->args.colors.separator); + 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_rectangle(cairo, surface->scale, surface->scale, buffer_width-(surface->scale*2), buffer_height-(surface->scale*2)); ++ ++ //draw_button(cairo, surface, "hi", buffer_width, buffer_height, 5, 5, 4, 3); ++ cairo_stroke(cairo); ++ ++ //cairo_set_source_u32(cairo, state->args.colors.separator); ++ cairo_rectangle(cairo, surface->scale, surface->scale, buffer_width, arc_thickness); + cairo_stroke(cairo); + + // display layout text separately +@@ -439,7 +549,9 @@ void render_frame(struct swaylock_surface *surface) { + destroy_buffer(surface->current_buffer); + surface->indicator_width = new_width; + surface->indicator_height = new_height; +- render_frame(surface); ++ wl_surface_damage_buffer(surface->surface, subsurf_xpos, subsurf_ypos, buffer_width, buffer_height); ++ render_keypad_frame(surface); ++ render_indicator_frame(surface); + return; + } + +@@ -451,9 +563,155 @@ void render_frame(struct swaylock_surface *surface) { + wl_surface_commit(surface->surface); + } + +-void render_frames(struct swaylock_state *state) { +- struct swaylock_surface *surface; +- wl_list_for_each(surface, &state->surfaces, link) { +- render_frame(surface); ++void render_notifications(cairo_t *cairo, struct swaylock_state *state, int spacing, ++ int key_height, int key_width, int pos_x, int pos_y) { ++ ++ cairo_set_font_size(cairo, 30); ++ ++ for (uint32_t x = 0; x < state->notification_amt; x++) { ++ int y = pos_y - ((spacing + key_height) * x); ++ if (x >= state->args.notification_count) { ++ char more_notifs[50]; ++ ++ sprintf(more_notifs, "+%ld more . . .", state->notification_amt - x); ++ draw_notification(cairo, state, more_notifs, "", pos_x, y, key_width*3+spacing*2, key_height); ++ return; ++ } else { ++ draw_notification(cairo, state, state->notification_msgs[x], state->notification_stamps[x], pos_x, y, key_width*3+spacing*2, key_height); ++ } + } + } ++ ++ ++void render_keypad_frame(struct swaylock_surface *surface) { ++ struct swaylock_state *state = surface->state; ++ ++ int ind_radius = state->args.radius * surface->scale; ++ int ind_thickness = state->args.thickness * surface->scale; ++ int margin = state->args.margin * surface->scale; ++ ++ if ((uint32_t)(ind_radius*2 + margin*2 + ind_thickness*2) > surface->width) { ++ ind_radius = surface->width/2 - margin - ind_thickness; ++ } ++ ++ if ((uint32_t)(ind_radius*2 + margin*2 + ind_thickness*2) > surface->height) { ++ ind_radius = surface->height/2 - margin - ind_thickness; ++ } ++ ++ int buffer_width = surface->keypad_width; ++ int buffer_height = surface->keypad_height; ++ ++ int subsurf_xpos = state->args.margin; ++ int subsurf_ypos = surface->height - (buffer_height / surface->scale); ++ ++ int horizontal_padding = 8.0 * surface->scale; ++ int vertical_padding = 4.0 * surface->scale; ++ ++ int spacing = 4.0 * surface->scale; ++ ++ subsurf_ypos -= margin; ++ ++ int new_width = surface->width * surface->scale; //buffer_width; ++ int new_height = buffer_height; ++ ++ wl_subsurface_set_position(surface->keypad_subsurface, subsurf_xpos, subsurf_ypos); ++ ++ surface->current_buffer = get_next_buffer(state->shm, ++ surface->keypad_buffers, buffer_width, buffer_height); ++ if (surface->current_buffer == NULL) { ++ return; ++ } ++ ++ // Hide subsurface until we want it visible ++ wl_surface_attach(surface->keypad_child, NULL, 0, 0); ++ wl_surface_commit(surface->keypad_child); ++ ++ cairo_t *cairo = cairo_init(surface); ++ ++ 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, surface->scale * 16); ++ } ++ ++ cairo_text_extents_t extents; ++ cairo_font_extents_t fe; ++ cairo_text_extents(cairo, "000", &extents); ++ cairo_font_extents(cairo, &fe); ++ ++ int keypad_min_width = extents.width * 3 + horizontal_padding * 6 + spacing * 4; ++ if (buffer_width < keypad_min_width) { ++ new_width = keypad_min_width; ++ } ++ ++ int keypad_min_height = fe.height * 5 + vertical_padding * 10 + spacing * 6; ++ if (buffer_height < keypad_min_height) { ++ new_height = keypad_min_height; ++ } ++ ++ int key_width = (buffer_width - spacing * 4) / 3; ++ int key_height = (buffer_height - spacing * 6) / 5; ++ ++ int pos_x = spacing; ++ int pos_y = (spacing * 5 + key_height * 4); ++ ++ if (state->args.show_keypad) { ++ char label[2]; ++ ++ label[1] = '\0'; ++ ++ for (int y = 0; y < 4; y++) { ++ for (int x = 0; x < 3; x++) { ++ int pos_x = spacing * (x+1) + key_width * x; ++ int pos_y = spacing * (y+1) + key_height * y; ++ //Draw key label ++ label[0] = '1' + y * 3 + x; ++ if (label[0] == ';') { ++ label[0] = '0'; ++ } else if (label[0] == ':') { ++ label[0] = 'X'; ++ } ++ draw_keypad_key(cairo, state, label, pos_x, pos_y, key_width, key_height); ++ } ++ } ++ ++ draw_keypad_key(cairo, state, "Unlock", pos_x, pos_y, key_width*3+spacing*2, key_height); ++ ++ } else if (state->args.show_keypad == 0 && state->args.notifications) { ++ render_notifications(cairo, state, spacing, key_height, key_width, pos_x, pos_y); ++ } ++ ++ ++ ++ // Make sure the keypad fits on the screen ++ if ((uint32_t)(new_width + margin*2) > (surface->width * surface->scale)) { ++ new_width = surface->width * surface->scale - margin*2; ++ } ++ ++ if ((uint32_t)(new_height + margin*2) > (surface->height * surface->scale)) { ++ new_height = surface->height * surface->scale - margin*2; ++ } ++ ++ // Ensure buffer size is multiple of buffer scale - required by protocol ++ if (new_height % surface->scale) new_height += surface->scale - (new_height % surface->scale); ++ if (new_width % surface->scale) new_width += surface->scale - (new_width % surface->scale); ++ ++ if (buffer_width != new_width || buffer_height != new_height) { ++ destroy_buffer(surface->current_buffer); ++ surface->keypad_width = new_width; ++ surface->keypad_height = new_height; ++ wl_surface_damage_buffer(surface->surface, subsurf_xpos, subsurf_ypos, buffer_width, buffer_height); ++ render_keypad_frame(surface); ++ render_indicator_frame(surface); ++ return; ++ } ++ ++ wl_surface_set_buffer_scale(surface->keypad_child, surface->scale); ++ wl_surface_attach(surface->keypad_child, surface->current_buffer->buffer, 0, 0); ++ wl_surface_damage_buffer(surface->surface, subsurf_xpos, subsurf_ypos, buffer_width * surface->scale, buffer_height * surface->scale); ++ wl_surface_commit(surface->keypad_child); ++ ++ wl_surface_commit(surface->surface); ++} +diff --git a/seat.c b/src/seat.c +similarity index 65% +rename from seat.c +rename to src/seat.c +index 440bcb7..049f609 100644 +--- a/seat.c ++++ b/src/seat.c +@@ -186,37 +186,167 @@ static const struct wl_pointer_listener pointer_listener = { + .axis_discrete = wl_pointer_axis_discrete, + }; + +-static void wl_touch_down(void *data, struct wl_touch *touch, uint32_t serial, +- uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y) { +- swaylock_handle_touch((struct swaylock_state *)data); ++void wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial, ++ uint32_t time, struct wl_surface *surface, int32_t id, ++ wl_fixed_t x, wl_fixed_t y) { ++ uint32_t touch_x, touch_y; ++ struct swaylock_seat *seat = data; ++ struct swaylock_state *state = seat->state; ++ ++ bool is_for_keypad_surface = false; ++ ++ //Find out to wich surface this belongs ++ struct swaylock_surface *this_surface; ++ wl_list_for_each(this_surface, &state->surfaces, link) { ++ if (this_surface->keypad_child == surface) { ++ is_for_keypad_surface = true; ++ break; ++ } else if (this_surface->indicator_child == surface || ++ this_surface->surface == surface) { ++ break; ++ } ++ } ++ ++ touch_x = wl_fixed_to_int(x) * this_surface->scale; ++ touch_y = wl_fixed_to_int(y) * this_surface->scale; ++ ++ if (is_for_keypad_surface) { ++ int key_x = touch_x / (this_surface->keypad_width / 3); ++ int key_y = touch_y / (this_surface->keypad_height / 5); ++ ++ if (seat->state->args.show_keypad) { ++ switch (key_y) { ++ case 0: /* fallthrough */ ++ case 1: ++ case 2: ++ if (key_x >= 0 && key_x< 3) { ++ swaylock_handle_key(state, 0, '1' + key_x + key_y * 3); ++ } ++ break; ++ case 3: ++ switch (key_x) { ++ case 0: ++ swaylock_handle_key(state, XKB_KEY_Escape, 0); ++ break; ++ case 1: ++ swaylock_handle_key(state, 0, '0'); ++ break; ++ case 2: ++ swaylock_handle_key(state, XKB_KEY_Delete, 0); ++ break; ++ default: ++ break; ++ } ++ break; ++ case 4: ++ swaylock_handle_key(state, XKB_KEY_Return, '\n'); ++ break; ++ default: ++ break; ++ } ++ } ++ } + } + +-static void wl_touch_up(void *data, struct wl_touch *touch, uint32_t serial, ++void wl_touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial, + uint32_t time, int32_t id) { +- // Who cares ++ ++ struct swaylock_seat *seat = data; ++ struct swaylock_state *state = seat->state; ++ ++ // Erase the swipe buffer when touch is ended ++ state->swipe_count = 0; ++ ++ memset(&state->swipe_x, 0, 128); ++ memset(&state->swipe_y, 0, 128); + } + +-static void wl_touch_motion(void *data, struct wl_touch *touch, uint32_t time, ++void wl_touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time, + int32_t id, wl_fixed_t x, wl_fixed_t y) { +- swaylock_handle_touch((struct swaylock_state *)data); ++ ++ struct swaylock_seat *seat = data; ++ struct swaylock_state *state = seat->state; ++ uint32_t touch_x, touch_y; ++ int vertical_distance; ++ ++ touch_x = wl_fixed_to_int(x); ++ touch_y = wl_fixed_to_int(y); ++ ++ ++ // Exit if swipe gestures disabled ++ if (state->args.swipe_gestures == false) { ++ return; ++ } ++ ++ ++ if (state->swipe_count < 128) { ++ state->swipe_x[state->swipe_count] = touch_x; ++ state->swipe_y[state->swipe_count] = touch_y; ++ state->swipe_count++; ++ } else { return; } ++ ++ vertical_distance = abs(state->swipe_y[0] - state->swipe_y[state->swipe_count - 1]); ++ ++ // Swipe up ++ if (state->swipe_y[0] > state->swipe_y[state->swipe_count - 1] && vertical_distance > 350) { ++ ++ if (state->args.show_quickaction) { ++ state->args.show_quickaction = false; ++ ++ } else if (state->args.show_keypad == false) { ++ state->args.show_keypad = true; ++ ++ } ++ ++ state->swipe_count = 0; ++ damage_state(state); ++ ++ // Swipe down ++ } else if (state->swipe_y[0] < state->swipe_y[state->swipe_count - 1] ++ && vertical_distance > 350) { ++ ++ if (state->args.show_keypad) { ++ state->args.show_keypad = false; ++ ++ } else if (state->args.show_quickaction == false) { ++ state->args.show_quickaction = true; ++ ++ } ++ ++ state->swipe_count = 0; ++ damage_state(state); ++ } ++} ++ ++void wl_touch_frame(void *data, struct wl_touch *wl_touch) { ++ // Who cares ++} ++ ++void wl_touch_cancel(void *data, struct wl_touch *wl_touch) { ++ // Who cares + } + +-static void wl_touch_frame(void *data, struct wl_touch *touch) { ++void wl_touch_shape(void *data, struct wl_touch *wl_touch, int32_t id, ++ wl_fixed_t major, wl_fixed_t minor) { + // Who cares + } + +-static void wl_touch_cancel(void *data, struct wl_touch *touch) { ++void wl_touch_orientation(void *data, struct wl_touch *wl_touch, int32_t id, ++ wl_fixed_t orientation) { + // Who cares + } + + static const struct wl_touch_listener touch_listener = { +- .down = wl_touch_down, +- .up = wl_touch_up, +- .motion = wl_touch_motion, +- .frame = wl_touch_frame, +- .cancel = wl_touch_cancel, ++ .down = wl_touch_down, ++ .up = wl_touch_up, ++ .motion = wl_touch_motion, ++ .frame = wl_touch_frame, ++ .cancel = wl_touch_cancel, ++ .shape = wl_touch_shape, ++ .orientation = wl_touch_orientation, + }; + ++ + static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + enum wl_seat_capability caps) { + struct swaylock_seat *seat = data; +@@ -224,6 +354,10 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + wl_pointer_release(seat->pointer); + seat->pointer = NULL; + } ++ if (seat->touch) { ++ wl_touch_release(seat->touch); ++ seat->touch = NULL; ++ } + if (seat->keyboard) { + wl_keyboard_release(seat->keyboard); + seat->keyboard = NULL; +@@ -232,14 +366,14 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, + seat->pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(seat->pointer, &pointer_listener, seat->state); + } ++ if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { ++ seat->touch = wl_seat_get_touch(wl_seat); ++ wl_touch_add_listener(seat->touch, &touch_listener, seat); ++ } + if ((caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + seat->keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(seat->keyboard, &keyboard_listener, seat); + } +- if ((caps & WL_SEAT_CAPABILITY_TOUCH)) { +- seat->touch = wl_seat_get_touch(wl_seat); +- wl_touch_add_listener(seat->touch, &touch_listener, seat->state); +- } + } + + static void seat_handle_name(void *data, struct wl_seat *wl_seat, +diff --git a/shadow.c b/src/shadow.c +similarity index 100% +rename from shadow.c +rename to src/shadow.c +diff --git a/unicode.c b/src/unicode.c +similarity index 100% +rename from unicode.c +rename to src/unicode.c +diff --git a/sxmo_hooks/sxmo_hook_idlelocker.sh b/sxmo_hooks/sxmo_hook_idlelocker.sh +new file mode 100755 +index 0000000..f2cd348 +--- /dev/null ++++ b/sxmo_hooks/sxmo_hook_idlelocker.sh +@@ -0,0 +1,47 @@ ++#!/bin/sh ++ ++. sxmo_common.sh ++ ++# This hook is called everytime the idle locker is updated (the screenoff hook manages its own idle locker) ++ ++if grep -q "unlock" "$SXMO_STATE" ; then ++ idle_time="${SXMO_UNLOCK_IDLE_TIME:-120}" ++elif grep -q off "$SXMO_STATE.screen" ; then ++ # if locked and screen is off start going to idle ++ idle_time="" ++else ++ idle_time=8 ++fi ++ ++sxmo_daemons.sh stop idle_locker ++ ++if ! [ -z "$idle_time" ] ; then ++ # Go to lock after 120 seconds of inactivity ++ if ! [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then ++ case "$SXMO_WM" in ++ sway) ++ sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \ ++ timeout "$idle_time" 'sh -c " ++ swaymsg mode default; ++ sxmo_hook_lock.sh; ++ exec sxmo_hook_screenoff.sh ++ "' ++ ;; ++ dwm) ++ sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \ ++ timeout "$idle_time" "sxmo_hook_lock.sh" ++ ;; ++ esac ++ fi ++else ++ # Start a periodic daemon (8s) "try to go to crust" after 8 seconds ++ # Start a periodic daemon (2s) blink after 5 seconds ++ # Resume tasks stop daemons ++ sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \ ++ timeout 8 'sxmo_daemons.sh start going_deeper sxmo_run_periodically.sh 5 sh -c "sxmo_hook_check_state_mutexes.sh && exec sxmo_mutex.sh can_suspend holdexec sxmo_suspend.sh"' \ ++ resume 'sxmo_daemons.sh stop going_deeper' \ ++ timeout 5 'sxmo_daemons.sh start periodic_blink sxmo_run_periodically.sh 2 sxmo_uniq_exec.sh sxmo_led.sh blink red blue' \ ++ resume 'sxmo_daemons.sh stop periodic_blink' \ ++ timeout 12 'sxmo_daemons.sh start periodic_state_mutex_check sxmo_run_periodically.sh 10 sxmo_hook_check_state_mutexes.sh' \ ++ resume 'sxmo_daemons.sh stop periodic_state_mutex_check' ++fi +diff --git a/sxmo_hooks/sxmo_hook_inputhandler.sh b/sxmo_hooks/sxmo_hook_inputhandler.sh +new file mode 100755 +index 0000000..2aa4a7c +--- /dev/null ++++ b/sxmo_hooks/sxmo_hook_inputhandler.sh +@@ -0,0 +1,371 @@ ++#!/bin/sh ++# configversion: 061f1ec838ab73997514c2281424b1e6 ++# SPDX-License-Identifier: AGPL-3.0-only ++# Copyright 2022 Sxmo Contributors ++ ++# This script handles input actions, it is called by lisgd for gestures ++# and by dwm for button presses ++ ++ACTION="$1" ++ ++# include common definitions ++# shellcheck source=scripts/core/sxmo_common.sh ++. sxmo_common.sh ++ ++# this action will move the lock state $1 levels higher ++lock_screen_action() { ++ state="$(cat "$SXMO_STATE.screen")" ++ if [ "$state" = "on" ] ; then ++ sxmo_hook_lock.sh ++ sxmo_hook_screenoff.sh ++ else ++ sxmo_hook_screenon.sh ++ fi ++} ++ ++XPROPOUT="$(sxmo_wm.sh focusedwindow)" ++WMCLASS="$(printf %s "$XPROPOUT" | grep app: | cut -d" " -f2- | tr '[:upper:]' '[:lower:]')" ++WMNAME="$(printf %s "$XPROPOUT" | grep title: | cut -d" " -f2- | tr '[:upper:]' '[:lower:]')" ++ ++sxmo_debug "ACTION: $ACTION WMCLASS: $WMCLASS WMNAME: $WMNAME XPROPOUT: $XPROPOUT" ++ ++if ! grep -q unlock "$SXMO_STATE"; then ++ case "$ACTION" in ++ "powerbutton_one") ++ lock_screen_action ++ ;; ++ "powerbutton_two"|"powerbutton_three") ++ lock_screen_action 2 ++ ;; ++ "voldown_one") ++ sxmo_audio.sh vol down 5 ++ exit ++ ;; ++ "voldown_two") ++ sxmo_audio.sh vol down 10 ++ exit ++ ;; ++ "voldown_three") ++ sxmo_audio.sh vol down 15 ++ exit ++ ;; ++ "volup_one") ++ sxmo_audio.sh vol up 5 ++ exit ++ ;; ++ "volup_two") ++ sxmo_audio.sh vol up 10 ++ exit ++ ;; ++ "volup_three") ++ sxmo_audio.sh vol up 15 ++ exit ++ ;; ++ esac ++ #we're locked, don't process the rest of the script ++ exit 0 ++fi ++ ++#special context-sensitive handling ++case "$WMCLASS" in ++ *"mpv"*) ++ case "$ACTION" in ++ "oneright") ++ sxmo_type.sh -k Left ++ exit 0 ++ ;; ++ "oneleft") ++ sxmo_type.sh -k Right ++ exit 0 ++ ;; ++ "oneup") ++ sxmo_type.sh m ++ exit 0 ++ ;; ++ "onedown") ++ sxmo_type.sh p ++ exit 0 ++ ;; ++ esac ++ ;; ++ *"foot"*|*"st"*|*"vte"*) ++ # First we try to handle the app running inside st: ++ case "$WMNAME" in ++ *"weechat"*) ++ case "$ACTION" in ++ *"oneleft") ++ sxmo_type.sh -M Alt -k a ++ exit 0 ++ ;; ++ *"oneright") ++ sxmo_type.sh -M Alt -k less ++ exit 0 ++ ;; ++ *"oneup") ++ sxmo_type.sh -k Page_Down ++ exit 0 ++ ;; ++ *"onedown") ++ sxmo_type.sh -k Page_Up ++ exit 0 ++ ;; ++ esac ++ ;; ++ *" sms") ++ case "$ACTION" in ++ *"upbottomedge") ++ number="$(printf %s "$WMNAME" | sed -e 's|^\"||' -e 's|\"$||' | cut -f1 -d' ')" ++ sxmo_terminal.sh sxmo_modemtext.sh conversationloop "$number" & ++ exit 0 ++ ;; ++ esac ++ ;; ++ *"tuir"*) ++ if [ "$ACTION" = "rightbottomedge" ]; then ++ sxmo_type.sh o ++ exit 0 ++ elif [ "$ACTION" = "leftbottomedge" ]; then ++ sxmo_type.sh s ++ exit 0 ++ fi ++ ;; ++ *"less"*) ++ case "$ACTION" in ++ "leftbottomedge") ++ sxmo_type.sh q ++ exit 0 ++ ;; ++ "leftrightedge_short") ++ sxmo_type.sh q ++ exit 0 ++ ;; ++ *"onedown") ++ sxmo_type.sh u ++ exit 0 ++ ;; ++ *"oneup") ++ sxmo_type.sh d ++ exit 0 ++ ;; ++ *"oneleft") ++ sxmo_type.sh ":n" -k Return ++ exit 0 ++ ;; ++ *"oneright") ++ sxmo_type.sh ":p" -k Return ++ exit 0 ++ ;; ++ esac ++ ;; ++ *"amfora"*) ++ case "$ACTION" in ++ "downright") ++ sxmo_type.sh -k Tab ++ exit 0 ++ ;; ++ "upleft") ++ sxmo_type.sh -M Shift -k Tab ++ exit 0 ++ ;; ++ *"onedown") ++ sxmo_type.sh u ++ exit 0 ++ ;; ++ *"oneup") ++ sxmo_type.sh d ++ exit 0 ++ ;; ++ *"oneright") ++ sxmo_type.sh -k Return ++ exit 0 ++ ;; ++ "upright") ++ sxmo_type.sh -M Ctrl t ++ exit 0 ++ ;; ++ *"oneleft") ++ sxmo_type.sh b ++ exit 0 ++ ;; ++ "downleft") ++ sxmo_type.sh -M Ctrl w ++ exit 0 ++ ;; ++ esac ++ ;; ++ esac ++ # Now we try generic actions for terminal ++ case "$ACTION" in ++ *"onedown") ++ case "$WMCLASS" in ++ *"foot"*) ++ sxmo_type.sh -M Shift -k Page_Up ++ exit 0 ++ ;; ++ *"st"*) ++ sxmo_type.sh -M Ctrl -M Shift -k b ++ exit 0 ++ ;; ++ esac ++ ;; ++ *"oneup") ++ case "$WMCLASS" in ++ *"foot"*) ++ sxmo_type.sh -M Shift -k Page_Down ++ exit 0 ++ ;; ++ *"st"*) ++ sxmo_type.sh -M Ctrl -M Shift -k f ++ exit 0 ++ ;; ++ esac ++ ;; ++ esac ++esac ++ ++#standard handling ++case "$ACTION" in ++ "powerbutton_one") ++ if echo "$WMCLASS" | grep -i "megapixels"; then ++ sxmo_type.sh -k space ++ else ++ lock_screen_action ++ fi ++ exit 0 ++ ;; ++ "powerbutton_two") ++ lock_screen_action 2 ++ exit 0 ++ ;; ++ "powerbutton_three") ++ sxmo_terminal.sh ++ exit 0 ++ ;; ++ "voldown_one") ++ sxmo_keyboard.sh toggle ++ exit ++ ;; ++ "voldown_two") ++ sxmo_wm.sh togglelayout ++ exit ++ ;; ++ "voldown_three") ++ sxmo_killwindow.sh ++ exit ++ ;; ++ "volup_one") ++ sxmo_appmenu.sh ++ exit ++ ;; ++ "volup_two") ++ sxmo_appmenu.sh sys ++ exit ++ ;; ++ "volup_three") ++ sxmo_wmmenu.sh ++ exit ++ ;; ++ "rightleftedge") ++ sxmo_wm.sh previousworkspace ++ exit 0 ++ ;; ++ "leftrightedge") ++ sxmo_wm.sh nextworkspace ++ exit 0 ++ ;; ++ "twoleft") ++ sxmo_wm.sh movepreviousworkspace ++ exit 0 ++ ;; ++ "tworight") ++ sxmo_wm.sh movenextworkspace ++ exit 0 ++ ;; ++ "righttopedge") ++ sxmo_brightness.sh up & ++ exit 0 ++ ;; ++ "lefttopedge") ++ sxmo_brightness.sh down & ++ exit 0 ++ ;; ++ "upleftedge") ++ sxmo_audio.sh vol up & ++ exit 0 ++ ;; ++ "downleftedge") ++ sxmo_audio.sh vol down & ++ exit 0 ++ ;; ++ "upbottomedge") ++ sxmo_keyboard.sh open ++ exit 0 ++ ;; ++ "downbottomedge") ++ sxmo_keyboard.sh close ++ exit 0 ++ ;; ++ "downtopedge") ++ sxmo_dmenu.sh isopen || sxmo_appmenu.sh & ++ exit 0 ++ ;; ++ "twodowntopedge") ++ sxmo_dmenu.sh isopen || sxmo_appmenu.sh sys & ++ exit 0 ++ ;; ++ "uptopedge") ++ sxmo_dmenu.sh close ++ if pgrep mako >/dev/null; then ++ makoctl dismiss --all ++ elif pgrep dunst >/dev/null; then ++ dunstctl close-all ++ fi ++ exit 0 ++ ;; ++ "twodownbottomedge") ++ sxmo_killwindow.sh ++ exit 0 ++ ;; ++ "uprightedge") ++ sxmo_type.sh -k Up ++ exit 0 ++ ;; ++ "downrightedge") ++ sxmo_type.sh -k Down ++ exit 0 ++ ;; ++ "leftrightedge_short") ++ sxmo_type.sh -k Left ++ exit 0 ++ ;; ++ "rightrightedge_short") ++ sxmo_type.sh -k Right ++ exit 0 ++ ;; ++ "rightbottomedge") ++ sxmo_type.sh -k Return ++ exit 0 ++ ;; ++ "leftbottomedge") ++ sxmo_type.sh -k BackSpace ++ exit 0 ++ ;; ++ "topleftcorner") ++ sxmo_appmenu.sh sys & ++ exit 0 ++ ;; ++ "toprightcorner") ++ sxmo_appmenu.sh scripts & ++ exit 0 ++ ;; ++ "bottomleftcorner") ++ sxmo_dmenu.sh close ++ sxmo_hook_lock.sh ++ sxmo_hook_screenoff.sh ++ exit 0 ++ ;; ++ "bottomrightcorner") ++ sxmo_rotate.sh & ++ exit 0 ++ ;; ++esac +diff --git a/sxmo_hooks/sxmo_hook_lock.sh b/sxmo_hooks/sxmo_hook_lock.sh +new file mode 100755 +index 0000000..9b12cbc +--- /dev/null ++++ b/sxmo_hooks/sxmo_hook_lock.sh +@@ -0,0 +1,25 @@ ++#!/bin/sh ++# configversion: 5407ec9ac25cbd1e9bdcbe30e7bc84dc ++# SPDX-License-Identifier: AGPL-3.0-only ++# Copyright 2022 Sxmo Contributors ++ ++# include common definitions ++# shellcheck source=scripts/core/sxmo_common.sh ++. sxmo_common.sh ++ ++grep -q unlock "$SXMO_STATE" || exit ++ ++sxmo_log "transitioning to stage lock" ++printf lock > "$SXMO_STATE" ++ ++# This hook is called when the system reaches a locked state ++ ++sxmo_hook_statusbar.sh state_change ++ ++superctl stop sxmo_hook_lisgd ++ ++SXMO_REASON=screenlocker run-screenlocker& ++ ++sxmo_hook_idlelocker.sh ++ ++sxmo_superd_signal.sh sxmo_desktop_widget -USR2 +diff --git a/sxmo_hooks/sxmo_hook_proximitylock.sh b/sxmo_hooks/sxmo_hook_proximitylock.sh +new file mode 100755 +index 0000000..d5eda80 +--- /dev/null ++++ b/sxmo_hooks/sxmo_hook_proximitylock.sh +@@ -0,0 +1,67 @@ ++#!/bin/sh ++# configversion: bd662f3a7848555a73dcd32a3fd7a421 ++# SPDX-License-Identifier: AGPL-3.0-only ++# Copyright 2022 Sxmo Contributors ++ ++# include common definitions ++# shellcheck source=scripts/core/sxmo_common.sh ++. sxmo_common.sh ++ ++# This hook enables the proximity lock. ++ ++finish() { ++ kill "$EVENTMONITORPID" ++ kill "$AWKPID" ++ rm "$tmp" ++ ++ if ! grep -q "$INITIALSTATE" "$SXMO_STATE"; then ++ sxmo_hook_screen"$INITIALSTATE".sh ++ fi ++ ++ # De-activate thresholds ++ printf 0 > "$prox_path/events/in_proximity_thresh_falling_value" ++ # The in_proximity_scale affects the maximum threshold value ++ # (see static const int stk3310_ps_max[4]) ++ printf 6553 > "$prox_path/events/in_proximity_thresh_rising_value" ++ ++ #sxmo_mutex.sh can_suspend free "Proximity lock is running" ++ exit 0 ++} ++ ++INITIALSTATE="$(cat "$SXMO_STATE.screen")" ++trap 'finish' TERM INT ++ ++#sxmo_mutex.sh can_suspend lock "Proximity lock is running" ++ ++# Permissions for these set by udev rules. ++prox_raw_bus="$(find /sys/devices/platform/soc -name 'in_proximity_raw' | head -n1)" ++prox_path="$(dirname "$prox_raw_bus")" ++prox_name="$(cat "$prox_path/name")" # e.g. stk3310 ++ ++printf "%d" "${SXMO_PROX_FALLING:-50}" > "$prox_path/events/in_proximity_thresh_falling_value" ++printf "%d" "${SXMO_PROX_RISING:-100}" > "$prox_path/events/in_proximity_thresh_rising_value" ++ ++tmp="$(mktemp -u)" ++mkfifo "$tmp" ++ ++# TODO: stdbuf not needed with linux-tools-iio >=5.17 ++stdbuf -o L iio_event_monitor "$prox_name" >> "$tmp" & ++EVENTMONITORPID=$! ++ ++export SXMO_REASON=proximitylock ++ ++awk ' ++ /rising/{system("sxmo_hook_screenoff.sh")} ++ /falling/{system("sxmo_hook_screenon.sh")} ++' "$tmp" & ++AWKPID=$! ++ ++initial_distance="$(cat "$prox_raw_bus")" ++if [ "$initial_distance" -gt 50 ] && [ "$INITIALSTATE" != "off" ]; then ++ sxmo_hook_screenoff.sh ++elif [ "$initial_distance" -lt 100 ] && [ "$INITIALSTATE" != "on" ]; then ++ sxmo_hook_screenon.sh ++fi ++ ++wait "$EVENTMONITORPID" ++wait "$AWKPID" +diff --git a/sxmo_hooks/sxmo_hook_screenoff.sh b/sxmo_hooks/sxmo_hook_screenoff.sh +new file mode 100755 +index 0000000..7fb09cf +--- /dev/null ++++ b/sxmo_hooks/sxmo_hook_screenoff.sh +@@ -0,0 +1,38 @@ ++#!/bin/sh ++# configversion: a861024910eceb507671197080281140 ++# SPDX-License-Identifier: AGPL-3.0-only ++# Copyright 2022 Sxmo Contributors ++ ++# include common definitions ++# shellcheck source=scripts/core/sxmo_common.sh ++. sxmo_common.sh ++ ++# This hook is called when the system reaches a off state (screen off) ++ ++sxmo_log "transitioning to screen off" ++printf off > "$SXMO_STATE.screen" ++ ++export SXMO_REASON="" ++ ++sxmo_uniq_exec.sh sxmo_led.sh blink blue red & ++LEDPID=$! ++sxmo_hook_statusbar.sh state_change ++ ++sxmo_wm.sh dpms on ++sxmo_wm.sh inputevent touchscreen off ++superctl stop sxmo_hook_lisgd ++ ++wait "$LEDPID" ++ ++case "$SXMO_WM" in ++ dwm) ++ # dmenu will grab input focus (i.e. power button) so kill it before going to ++ # screenoff unless proximity lock is running (i.e. there's a phone call). ++ if ! (sxmo_daemons.sh running proximity_lock -q || \ ++ sxmo_daemons.sh running calling_proximity_lock -q); then ++ sxmo_dmenu.sh close ++ fi ++ ;; ++esac ++ ++sxmo_hook_idlelocker.sh +diff --git a/sxmo_hooks/sxmo_hook_screenon.sh b/sxmo_hooks/sxmo_hook_screenon.sh +new file mode 100755 +index 0000000..2eac1b3 +--- /dev/null ++++ b/sxmo_hooks/sxmo_hook_screenon.sh +@@ -0,0 +1,42 @@ ++#!/bin/sh ++# configversion: 5407ec9ac25cbd1e9bdcbe30e7bc84dc ++# SPDX-License-Identifier: AGPL-3.0-only ++# Copyright 2022 Sxmo Contributors ++ ++# include common definitions ++# shellcheck source=scripts/core/sxmo_common.sh ++. sxmo_common.sh ++ ++# don't turn on for proximitylock events when locked ++[ "$SXMO_REASON" = "proximitylock" ] && grep -q '^lock$' "$SXMO_STATE" && exit ++ ++export SXMO_REASON="" ++ ++sxmo_log "transitioning to screen on" ++printf on > "$SXMO_STATE.screen" ++ ++# This hook is called when the system wants to turn the screen on ++ ++sxmo_uniq_exec.sh sxmo_led.sh blink blue & ++LEDPID=$! ++sxmo_hook_statusbar.sh state_change ++ ++sxmo_wm.sh dpms off ++sxmo_wm.sh inputevent touchscreen on ++grep -q unlock "$SXMO_STATE" && superctl start sxmo_hook_lisgd ++ ++# avoid dangling purple blinking when usb wakeup + power button… ++sxmo_daemons.sh stop periodic_blink ++ ++wait "$LEDPID" ++ ++# Go to screenoff after 8 seconds of inactivity ++#if ! [ -e "$XDG_CACHE_HOME/sxmo/sxmo.noidle" ]; then ++# sxmo_daemons.sh start idle_locker sxmo_idle.sh -w \ ++# timeout 8 "sh -c 'sxmo_hook_lock.sh\ ++# sxmo_hook_screenoff.sh" ++#fi ++ ++sxmo_hook_idlelocker.sh ++ ++sxmo_superd_signal.sh sxmo_desktop_widget -USR2 +diff --git a/sxmo_hooks/sxmo_hook_unlock.sh b/sxmo_hooks/sxmo_hook_unlock.sh +new file mode 100755 +index 0000000..d76bf77 +--- /dev/null ++++ b/sxmo_hooks/sxmo_hook_unlock.sh +@@ -0,0 +1,32 @@ ++#!/bin/sh ++# configversion: 040920a594309449edef1213b05965fd ++# SPDX-License-Identifier: AGPL-3.0-only ++# Copyright 2022 Sxmo Contributors ++ ++# include common definitions ++# shellcheck source=scripts/core/sxmo_common.sh ++. sxmo_common.sh ++ ++# This hook is called when the system becomes unlocked again ++ ++sxmo_log "transitioning to stage unlock" ++printf unlock > "$SXMO_STATE" ++ ++sxmo_uniq_exec.sh sxmo_led.sh blink red green & ++LEDPID=$! ++sxmo_hook_statusbar.sh state_change ++ ++sxmo_wm.sh dpms off ++sxmo_wm.sh inputevent touchscreen on ++superctl start sxmo_hook_lisgd ++ ++wait "$LEDPID" ++ ++NETWORKRTCSCAN="/sys/module/$SXMO_WIFI_MODULE/parameters/rtw_scan_interval_thr" ++if [ -w "$NETWORKRTCSCAN" ]; then ++ echo 16000 > "$NETWORKRTCSCAN" ++fi ++ ++sxmo_hook_idlelocker.sh ++ ++sxmo_superd_signal.sh sxmo_desktop_widget -USR2 +diff --git a/wlr-input-inhibitor-unstable-v1.xml b/wayland-protocols/wlr-input-inhibitor-unstable-v1.xml +similarity index 100% +rename from wlr-input-inhibitor-unstable-v1.xml +rename to wayland-protocols/wlr-input-inhibitor-unstable-v1.xml +diff --git a/wlr-layer-shell-unstable-v1.xml b/wayland-protocols/wlr-layer-shell-unstable-v1.xml +similarity index 100% +rename from wlr-layer-shell-unstable-v1.xml +rename to wayland-protocols/wlr-layer-shell-unstable-v1.xml +diff --git a/wlr-screencopy-unstable-v1.xml b/wayland-protocols/wlr-screencopy-unstable-v1.xml +similarity index 100% +rename from wlr-screencopy-unstable-v1.xml +rename to wayland-protocols/wlr-screencopy-unstable-v1.xml