diff --git a/Makefile b/Makefile index b31c533..f144119 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ PREFIX:=/usr PROGRAMS = \ programs/sxmo_setpineled \ - programs/sxmo_screenlock \ programs/sxmo_megiaudioroute \ programs/sxmo_vibratepine @@ -18,9 +17,6 @@ shellcheck: programs/sxmo_setpineled: programs/sxmo_setpineled.c gcc -o programs/sxmo_setpineled programs/sxmo_setpineled.c -programs/sxmo_screenlock: programs/sxmo_screenlock.c - gcc -o programs/sxmo_screenlock programs/sxmo_screenlock.c -lX11 - programs/sxmo_megiaudioroute: programs/sxmo_megiaudioroute.c gcc -o programs/sxmo_megiaudioroute programs/sxmo_megiaudioroute.c @@ -28,7 +24,7 @@ programs/sxmo_vibratepine: programs/sxmo_vibratepine.c gcc -o programs/sxmo_vibratepine programs/sxmo_vibratepine.c clean: - rm -f programs/sxmo_setpineled programs/sxmo_screenlock programs/sxmo_megiaudioroute programs/sxmo_vibratepine + rm -f programs/sxmo_setpineled programs/sxmo_megiaudioroute programs/sxmo_vibratepine install: $(PROGRAMS) cd configs && find . -type f -exec install -D -m 0644 "{}" "$(DESTDIR)$(PREFIX)/share/sxmo/{}" \; && cd .. @@ -55,8 +51,6 @@ install: $(PROGRAMS) install -D -m 0755 programs/sxmo_setpineled $(DESTDIR)$(PREFIX)/bin/ - install -D -m 0755 programs/sxmo_screenlock $(DESTDIR)$(PREFIX)/bin/ - install -D programs/sxmo_megiaudioroute $(DESTDIR)$(PREFIX)/bin/ install -D programs/sxmo_vibratepine $(DESTDIR)$(PREFIX)/bin/ diff --git a/configs/default_hooks/postwake b/configs/default_hooks/postwake new file mode 100644 index 0000000..d8d20a3 --- /dev/null +++ b/configs/default_hooks/postwake @@ -0,0 +1,39 @@ +#!/usr/bin/env sh + +. "$(which sxmo_common.sh)" + +REDLED_PATH="/sys/class/leds/red:indicator/brightness" +BLUELED_PATH="/sys/class/leds/blue:indicator/brightness" + +finish() { + kill $BLINKPID + + echo 0 > "$REDLED_PATH" + echo 0 > "$BLUELED_PATH" + + # Going back to crust + if [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; then + sxmo_screenlock.sh crust "$SXMO_RTCWAKEINTERVAL" + fi + + exit 0 +} + +trap 'finish' TERM INT EXIT + +blink() { + while [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; do + echo 1 > "$REDLED_PATH" + echo 0 > "$BLUELED_PATH" + sleep 0.25 + echo 0 > "$REDLED_PATH" + echo 1 > "$BLUELED_PATH" + sleep 0.25 + done +} + +blink & +BLINKPID=$! + +# Replace this by wathever you want to do +sleep 5 diff --git a/configs/default_hooks/rtcwake b/configs/default_hooks/rtcwake new file mode 100644 index 0000000..7c0af62 --- /dev/null +++ b/configs/default_hooks/rtcwake @@ -0,0 +1,39 @@ +#!/usr/bin/env sh + +. "$(which sxmo_common.sh)" + +REDLED_PATH="/sys/class/leds/red:indicator/brightness" +BLUELED_PATH="/sys/class/leds/blue:indicator/brightness" + +finish() { + kill $BLINKPID + + echo 0 > "$REDLED_PATH" + echo 0 > "$BLUELED_PATH" + + # Going back to crust + if [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; then + sxmo_screenlock.sh rtc "$SXMO_RTCWAKEINTERVAL" + fi + + exit 0 +} + +trap 'finish' TERM INT EXIT + +blink() { + while [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; do + echo 1 > "$REDLED_PATH" + echo 0 > "$BLUELED_PATH" + sleep 0.5 + echo 0 > "$REDLED_PATH" + echo 1 > "$BLUELED_PATH" + sleep 0.5 + done +} + +blink & +BLINKPID=$! + +# Replace this by wathever you want to do +sleep 10 diff --git a/programs/sxmo_screenlock.c b/programs/sxmo_screenlock.c deleted file mode 100644 index 0e78193..0000000 --- a/programs/sxmo_screenlock.c +++ /dev/null @@ -1,553 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Types -enum State { - StateNoInput, // Screen on / input lock - StateNoInputNoScreen, // Screen off / input lock - StateSuspend, // Deep sleep - StateSuspendPending, // Suspend 'woken up', must leave state in <5s, or kicks to StateSuspend - StateDead // Exit the appliation -}; -enum Color { - Red, - Blue, - Purple, - Off -}; - -// Fn declarations -int checkrtcwake(); -void configuresuspendsettingsandwakeupsources(); -time_t convert_rtc_time(struct rtc_time * rtc); -void die(const char *err, ...); -int getoldbrightness(); -void init_rtc(); -void lockscreen(Display *dpy, int screen, int blank); -void unblankscreen(); -void blankscreen(); -void readinputloop(Display *dpy, int screen); -int presuspend(); -void postwake(); -void setpineled(enum Color c); -int setup_rtc_wakeup(); -void sigterm(); -void syncstate(); -void usage(); -void writefile(char *filepath, char *str); - -// Variables -Display *dpy; -Window root; -enum State state = StateNoInput; -int suspendtimeouts = 35; -int suspendpendingsceenon = 0; -int suspendpendingtimeouts = 0; -KeySym lastkeysym = XK_Cancel; -int lastkeyn = 0; -char oldbrightness[10] = "200"; -char * brightnessfile = "/sys/devices/platform/backlight/backlight/backlight/brightness"; -char * powerstatefile = "/sys/power/state"; -int rtc_fd = 0; //file descriptor -time_t wakeinterval = 0; //wake every x seconds -time_t waketime = 0; //next wakeup time according to the RTC clock -int slept = 0; //indicates whether the process has slept (crust) or not -int blanked = 0; //indicated whether the display blanked or not - -#define RTC_DEVICE "/dev/rtc0" - -time_t -convert_rtc_time(struct rtc_time * rtc) { - struct tm tm; - memset(&tm, 0, sizeof tm); - tm.tm_sec = rtc->tm_sec; - tm.tm_min = rtc->tm_min; - tm.tm_hour = rtc->tm_hour; - tm.tm_mday = rtc->tm_mday; - tm.tm_mon = rtc->tm_mon; - tm.tm_year = rtc->tm_year; - tm.tm_isdst = -1; /* assume the system knows better than the RTC */ - return mktime(&tm); -} - -int setup_rtc_wakeup() { - //(code adapted from util-linux's rtcwake) - struct tm *tm; - struct rtc_wkalrm wake; - struct rtc_time now_rtc; - - if (ioctl(rtc_fd, RTC_RD_TIME, &now_rtc) < 0) { - fprintf(stderr, "Error reading rtc time\n"); - } - const time_t now = convert_rtc_time(&now_rtc); - waketime = now + wakeinterval; - - tm = localtime(&waketime); - - wake.time.tm_sec = tm->tm_sec; - wake.time.tm_min = tm->tm_min; - wake.time.tm_hour = tm->tm_hour; - wake.time.tm_mday = tm->tm_mday; - wake.time.tm_mon = tm->tm_mon; - wake.time.tm_year = tm->tm_year; - /* wday, yday, and isdst fields are unused by Linux */ - wake.time.tm_wday = -1; - wake.time.tm_yday = -1; - wake.time.tm_isdst = -1; - - fprintf(stderr, "Setting RTC wakeup to %ld: (UTC) %s", waketime, asctime(tm)); - - if (ioctl(rtc_fd, RTC_ALM_SET, &wake.time) < 0) { - fprintf(stderr, "error setting rtc alarm\n"); - return -1; - } - if (ioctl(rtc_fd, RTC_AIE_ON, 0) < 0) { - fprintf(stderr, "error enabling rtc alarm\n"); - return -1; - } - return 0; -} - -void -configuresuspendsettingsandwakeupsources() -{ - // Disable all wakeup sources - struct dirent *wakeupsource; - char wakeuppath[100]; - DIR *wakeupsources = opendir("/sys/class/wakeup"); - if (wakeupsources == NULL) - die("Couldn't open directory /sys/class/wakeup\n"); - while ((wakeupsource = readdir(wakeupsources)) != NULL) { - sprintf( - wakeuppath, - "/sys/class/wakeup/%.50s/device/power/wakeup", - wakeupsource->d_name - ); - fprintf(stderr, "Disabling wakeup source: %s", wakeupsource->d_name); - writefile(wakeuppath, "disabled"); - fprintf(stderr, ".. ok\n"); - } - closedir(wakeupsources); - - // Enable powerbutton wakeup source - fprintf(stderr, "Enable powerbutton wakeup source\n"); - writefile( - "/sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp221-pek/power/wakeup", - "enabled" - ); - - // Enable IRQ wakeup source (incoming call) 5.10 - fprintf(stderr, "Enable 5.10 IRQ wakeup source\n"); - writefile( - "/sys/devices/platform/gpio-keys/power/wakeup", - "enabled" - ); - - // Enable IRQ wakeup source (incoming call) 5.9 (no longer exists in 5.10) - fprintf(stderr, "Enable 5.9 IRQ wakeup source\n"); - writefile( - "/sys/devices/platform/soc/1c28c00.serial/serial1/serial1-0/power/wakeup", - "enabled" - ); - - // Enable rtc wakeup source - fprintf(stderr, "Enable rtc wakeup source\n"); - writefile( - "/sys/devices/platform/soc/1f00000.rtc/power/wakeup", - "enabled" - ); - - //set RTC wake - if (wakeinterval > 0) setup_rtc_wakeup(); - - // E.g. make sure we're using CRUST - fprintf(stderr, "Flip mem_sleep setting to use crust\n"); - writefile("/sys/power/mem_sleep", "deep"); - -} - -void -die(const char *err, ...) -{ - fprintf(stderr, "Screenlock error: %s\n", err); - state = StateDead; - syncstate(); - exit(1); -} - -void -sigterm() -{ - state = StateDead; - syncstate(); - if (wakeinterval) { - ioctl(rtc_fd, RTC_AIE_OFF, 0); - close(rtc_fd); - } - fprintf(stderr, "Screenlock terminating on signal\n"); - exit(0); -} - -int -getoldbrightness() { - char * buffer = 0; - long length; - FILE * f = fopen(brightnessfile, "r"); - if (f) { - fseek(f, 0, SEEK_END); - length = ftell(f); - fseek(f, 0, SEEK_SET); - buffer = malloc(length); - if (buffer) { - fread(buffer, 1, length, f); - } - fclose(f); - } - if (buffer) { - sprintf(oldbrightness, "%d", atoi(buffer)); - } -} - - -void -lockscreen(Display *dpy, int screen, int blank) -{ - // Loosely derived from suckless' slock's lockscreen binding logic but - // alot more coarse, intentionally so can be triggered while grab_key - // for dwm multikey path already holding.. - int i, ptgrab, kbgrab; - root = RootWindow(dpy, screen); - if (blank == 1) { - blankscreen(); - } - for (i = 0, ptgrab = kbgrab = -1; i < 9999999; i++) { - if (ptgrab != GrabSuccess) { - ptgrab = XGrabPointer(dpy, root, False, - ButtonPressMask | ButtonReleaseMask | - PointerMotionMask, GrabModeAsync, - GrabModeAsync, None, None, CurrentTime); - } - if (kbgrab != GrabSuccess) { - kbgrab = XGrabKeyboard(dpy, root, True, - GrabModeAsync, GrabModeAsync, CurrentTime); - } - if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) { - XSelectInput(dpy, root, SubstructureNotifyMask); - return; - } - usleep(100000); - } -} - -void -blankscreen() -{ - if (!blanked) { - system("xset dpms force off"); - blanked = 1; - } -} - -void -unblankscreen() -{ - if (blanked) { - system("xset dpms force on"); - blanked = 0; - } -} - -void -readinputloop(Display *dpy, int screen) { - KeySym keysym; - XEvent ev; - char buf[32]; - fd_set fdset; - int xfd; - int selectresult; - struct timeval xeventtimeout = {1, 0}; - xfd = ConnectionNumber(dpy); - - for (;;) { - FD_ZERO(&fdset); - FD_SET(xfd, &fdset); - if (state == StateSuspendPending) - selectresult = select(FD_SETSIZE, &fdset, NULL, NULL, &xeventtimeout); - else - selectresult = select(FD_SETSIZE, &fdset, NULL, NULL, NULL); - - if (FD_ISSET(xfd, &fdset) && XPending(dpy)) { - XNextEvent(dpy, &ev); - if (ev.type == KeyRelease) { - XLookupString(&ev.xkey, buf, sizeof(buf), &keysym, 0); - if (lastkeysym == keysym) { - lastkeyn++; - } else { - lastkeysym = keysym; - lastkeyn = 1; - } - - if (lastkeyn < 3) - continue; - - lastkeyn = 0; - lastkeysym = XK_Cancel; - if (slept) postwake(); - switch (keysym) { - case XF86XK_AudioRaiseVolume: - suspendpendingsceenon = state == StateNoInput; - suspendpendingtimeouts = 0; - state = StateSuspend; - break; - case XF86XK_AudioLowerVolume: - if (state == StateNoInput) state = StateNoInputNoScreen; - else if (state == StateNoInputNoScreen) state = StateNoInput; - else if (state == StateSuspendPending && suspendpendingsceenon) state = StateNoInputNoScreen; - else state = StateNoInput; - break; - case XF86XK_PowerOff: - waketime = 0; - state = StateDead; - break; - } - syncstate(); - } - } else if (state == StateSuspendPending) { - suspendpendingtimeouts++; - // # E.g. after suspendtimeouts seconds kick back into suspend - if (suspendpendingtimeouts > suspendtimeouts) state = StateSuspend; - syncstate(); - } - - - if (state == StateDead) break; - } -} - -void -setpineled(enum Color c) -{ - if (c == Red) { - writefile("/sys/class/leds/red:indicator/brightness", "1"); - writefile("/sys/class/leds/blue:indicator/brightness", "0"); - } else if (c == Blue) { - writefile("/sys/class/leds/red:indicator/brightness", "0"); - writefile("/sys/class/leds/blue:indicator/brightness", "1"); - } else if (c == Purple) { - writefile("/sys/class/leds/red:indicator/brightness", "1"); - writefile("/sys/class/leds/blue:indicator/brightness", "1"); - } else if (c == Off) { - writefile("/sys/class/leds/red:indicator/brightness", "0"); - writefile("/sys/class/leds/blue:indicator/brightness", "0"); - } -} - -int -presuspend() { - //called prior to suspension, a non-zero return value cancels suspension - return system("sxmo_presuspend.sh"); -} - -void -postwake() { - //called after fully waking up (not used for temporary rtc wakeups) - system("sxmo_postwake.sh"); - slept = 0; -} - -int -checkrtcwake() -{ - struct rtc_time now; - if (ioctl(rtc_fd, RTC_RD_TIME, &now) < 0) { - fprintf(stderr, "Error reading rtc time\n"); - return -1; - } - - const long int timediff = convert_rtc_time(&now) - waketime; - fprintf(stderr, "Checking rtc wake? timediff=%ld\n", timediff); - if (timediff >= 0 && timediff <= 3) { - fprintf(stderr, "Calling RTC wake script\n"); - setpineled(Blue); - return system("sxmo_rtcwake.sh"); - } - return 0; -} - -void -syncstate() -{ - int rtcresult; - if (state == StateSuspend) { - if (presuspend() != 0) { - state = StateDead; - } else { - fprintf(stderr, "Screenlock entering suspend state (pred mode)\n"); - writefile(brightnessfile, "0"); - blankscreen(); - slept = 1; - setpineled(Red); - configuresuspendsettingsandwakeupsources(); - writefile(powerstatefile, "mem"); - //---- program blocks here due to sleep ----- // - // Just woke up again - fprintf(stderr, "Screenlock woke up\n"); - fprintf(stderr, "Lower scan interval for quicker reconnection to wireless network\n"); - writefile("/sys/module/8723cs/parameters/rtw_scan_interval_thr", "1200"); //ms - //^-- this will be undone again by a networkmanager hook after connection has been established - // or by a delayed script if no connection can be established after a while (to conserve battery) - fprintf(stderr, "Woke up\n"); - if (waketime > 0) { - rtcresult = checkrtcwake(); - } else { - rtcresult = 0; - } - if (rtcresult == 0) { - state = StateSuspendPending; - suspendpendingtimeouts = 0; - } else { - postwake(); - state = StateDead; - } - } - syncstate(); - } else if (state == StateNoInput) { - fprintf(stderr, "Screenlock in no Input state (blue mode)\n"); - setpineled(Blue); - unblankscreen(); - writefile(brightnessfile, oldbrightness); - } else if (state == StateNoInputNoScreen) { - fprintf(stderr, "Screenlock in no screen state (purple mode)\n"); - setpineled(Purple); - writefile(brightnessfile, "0"); - blankscreen(); - } else if (state == StateSuspendPending) { - fprintf(stderr, "Screenlock is pending suspension\n"); - if (suspendpendingsceenon) unblankscreen(); - writefile(brightnessfile, suspendpendingsceenon ? oldbrightness : "0"); - if (!suspendpendingsceenon) blankscreen(); - setpineled(Off); - usleep(1000 * 100); - setpineled(suspendpendingsceenon ? Blue : Purple); - } else if (state == StateDead) { - unblankscreen(); - writefile(brightnessfile, oldbrightness); - setpineled(Off); - } -} - - - - -void -writefile(char *filepath, char *str) -{ - int f; - f = open(filepath, O_WRONLY); - if (f != -1) { - write(f, str, strlen(str)); - close(f); - } else { - fprintf(stderr, "Couldn't open filepath <%s>\n", filepath); - } -} - -void usage() { - fprintf(stderr, "Usage: sxmo_screenlock [--screen-off] [--suspend] [--wake-interval n] [--setuid]\n"); -} - - -void init_rtc() { - rtc_fd = open(RTC_DEVICE, O_RDONLY); - if (rtc_fd < 0) { - fprintf(stderr, "Error opening rtc device: %d\n", rtc_fd); - die("Unable to open rtc device"); - exit(EXIT_FAILURE); - } -} - -int -main(int argc, char **argv) { - int screen; - int i; - enum State target = StateNoInput; - - signal(SIGTERM, sigterm); - - const char* suspendtimeouts_str = getenv("SXMO_SUSPENDTIMEOUTS"); - if (suspendtimeouts_str != NULL) suspendtimeouts = atoi(suspendtimeouts_str); - - const char* rtcwakeinterval = getenv("SXMO_RTCWAKEINTERVAL"); - if (rtcwakeinterval != NULL) wakeinterval = atoi(rtcwakeinterval); - - const char* screen_off = getenv("SXMO_LOCK_SCREEN_OFF"); - if (screen_off != NULL && atoi(screen_off)) target = StateNoInputNoScreen; - - const char* suspend = getenv("SXMO_LOCK_SUSPEND"); - if (suspend != NULL && atoi(suspend)) target = StateSuspend; - - //parse command line arguments - for (i = 1; i < argc; i++) { - if(!strcmp(argv[i], "-h")) { - usage(); - return 0; - } else if(!strcmp(argv[i], "--screen-off")) { - target = StateNoInputNoScreen; - } else if(!strcmp(argv[i], "--suspend")) { - target = StateSuspend; - } else if(!strcmp(argv[i], "--wake-interval")) { - wakeinterval = (time_t) atoi(argv[++i]); - } else if(!strcmp(argv[i], "--setuid")) { - if (setuid(0)) - die("setuid(0) failed"); - } else { - fprintf(stderr, "Invalid argument: %s\n", argv[i]); - return 2; - } - } - - if (!(dpy = XOpenDisplay(NULL))) - die("Cannot open display"); - - getoldbrightness(); - - if (wakeinterval) init_rtc(); - - fprintf(stderr, "Screenlock starting\n"); - - XkbSetDetectableAutoRepeat(dpy, True, NULL); - screen = XDefaultScreen(dpy); - XSync(dpy, 0); - syncstate(); - lockscreen(dpy, screen, target == StateNoInputNoScreen || target == StateSuspend); - if ((target == StateNoInputNoScreen) || (target == StateSuspend)) { - state = StateNoInputNoScreen; - syncstate(); - } - if (target == StateSuspend) { - state = StateSuspend; - syncstate(); - } - readinputloop(dpy, screen); - if (wakeinterval) { - ioctl(rtc_fd, RTC_AIE_OFF, 0); - close(rtc_fd); - } - fprintf(stderr, "Screenlock terminating normally\n"); - return 0; -} diff --git a/scripts/core/sxmo_appmenu.sh b/scripts/core/sxmo_appmenu.sh index 4bcd315..3221c8c 100755 --- a/scripts/core/sxmo_appmenu.sh +++ b/scripts/core/sxmo_appmenu.sh @@ -166,9 +166,9 @@ programchoicesinit() { power ) # Power menu CHOICES=" - $icon_lck Lock ^ 0 ^ sxmo_lock.sh - $icon_lck Lock (Screen off) ^ 0 ^ sxmo_lock.sh --screen-off - $icon_zzz Suspend ^ 0 ^ sxmo_lock.sh --suspend + $icon_lck Lock ^ 0 ^ sxmo_screenlock.sh lock && sxmo_unlocklistener.sh + $icon_lck Lock (Screen off) ^ 0 ^ sxmo_screenlock.sh off && sxmo_unlocklistener.sh + $icon_zzz Suspend ^ 0 ^ sxmo_screenlock.sh crust $icon_out Logout ^ 0 ^ pkill -9 dwm $icon_rld Reboot ^ 0 ^ sxmo_terminal.sh sudo reboot $icon_pwr Poweroff ^ 0 ^ sxmo_terminal.sh sudo poweroff diff --git a/scripts/core/sxmo_common.sh b/scripts/core/sxmo_common.sh index 16f50d1..38cbcd0 100644 --- a/scripts/core/sxmo_common.sh +++ b/scripts/core/sxmo_common.sh @@ -19,6 +19,10 @@ export LOGDIR="$XDG_DATA_HOME"/sxmo/modem export CONTACTFILE="$XDG_CONFIG_HOME/sxmo/contacts.tsv" # shellcheck disable=SC2034 export MODEMSTATEFILE="$XDG_RUNTIME_DIR/sxmo.modem.state" +# shellcheck disable=SC2034 +export UNSUSPENDREASONFILE="$XDG_RUNTIME_DIR/sxmo.suspend.reason" +# shellcheck disable=SC2034 +export LASTSTATE="$XDG_RUNTIME_DIR/sxmo.suspend.laststate" command -v "$KEYBOARD" > /dev/null || export KEYBOARD=svkbd-mobile-intl command -v "$EDITOR" > /dev/null || export EDITOR=vis diff --git a/scripts/core/sxmo_inputhandler.sh b/scripts/core/sxmo_inputhandler.sh index a0a6e0e..8fdc6ad 100755 --- a/scripts/core/sxmo_inputhandler.sh +++ b/scripts/core/sxmo_inputhandler.sh @@ -9,6 +9,44 @@ ACTION="$1" # shellcheck source=scripts/core/sxmo_common.sh . "$(dirname "$0")/sxmo_common.sh" +crust() { + if [ -n "$SXMO_RTCWAKEINTERVAL" ]; then + sxmo_screenlock.sh rtc "$SXMO_RTCWAKEINTERVAL" + else + sxmo_screenlock.sh crust + fi +} + +lock_screen() { + if [ "$SXMO_LOCK_SCREEN_OFF" = "1" ]; then + sxmo_screenlock.sh off + else + sxmo_screenlock.sh lock + fi + if [ "$SXMO_LOCK_SUSPEND" = "1" ]; then + crust + fi +} + +if [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; then + case "$ACTION" in + "volup_three") + crust + ;; + "voldown_three") + if [ "$(sxmo_screenlock.sh getCurState)" = "lock" ]; then + sxmo_screenlock.sh off + else + lock_screen + fi + ;; + "powerbutton_three") + sxmo_screenlock.sh unlock + ;; + esac + exit +fi + XPROPOUT="$(xprop -id "$(xdotool getactivewindow)")" WMCLASS="$(echo "$XPROPOUT" | grep WM_CLASS | cut -d ' ' -f3-)" WMNAME=$(echo "$XPROPOUT" | grep -E "^WM_NAME" | cut -d ' ' -f3-) @@ -153,7 +191,7 @@ if [ "$HANDLE" -ne 0 ]; then sxmo_appmenu.sh sys ;; "volup_three") - sxmo_lock.sh + lock_screen ;; "voldown_one") xdotool key --clearmodifiers Super+space @@ -174,7 +212,7 @@ if [ "$HANDLE" -ne 0 ]; then sxmo_appmenu.sh scripts & ;; "bottomleftcorner") - sxmo_lock.sh & + lock_screen ;; "bottomrightcorner") sxmo_rotate.sh & diff --git a/scripts/core/sxmo_proximitylock.sh b/scripts/core/sxmo_proximitylock.sh index 608c272..820893c 100644 --- a/scripts/core/sxmo_proximitylock.sh +++ b/scripts/core/sxmo_proximitylock.sh @@ -1,17 +1,12 @@ #!/usr/bin/env sh -islocked() { - pgrep -f sxmo_lock.sh > /dev/null -} - -syncstate() { - islocked && STATE=locked || STATE=free +isLocked() { + curState="$(sxmo_screenlock.sh getCurState)" + [ "$curState" = "lock" ] || [ "$curState" = "off" ] } finish() { - kill "$(jobs -p)" - syncstate - [ free = "$STATE" ] && [ true = "$WASLOCKED" ] && sxmo_lock.sh & + sxmo_screenlock.sh "$INITIALSTATE" exit 0 } @@ -27,26 +22,15 @@ TARGET=30 mainloop() { while true; do distance="$(distance)" - # here we do not syncstate to allow user manual lock - if [ locked = "$STATE" ] && [ "$distance" -lt "$TARGET" ]; then - pkill -f sxmo_lock.sh - STATE=free - elif [ free = "$STATE" ] && [ "$distance" -gt "$TARGET" ]; then - islocked && pkill -f sxmo_lock.sh # we want screen-off on proximity - sxmo_lock.sh --screen-off & - STATE=locked + if isLocked && [ "$distance" -lt "$TARGET" ]; then + sxmo_screenlock.sh unlock + elif ! isLocked && [ "$distance" -gt "$TARGET" ]; then + sxmo_screenlock.sh off fi sleep 0.5 done } -syncstate -if [ locked = "$STATE" ]; then - WASLOCKED=true - - # we dont want to loose the initial lock if the phone is forgotten somewhere - # without proximity as this will prevent going back to crust - sxmo_movement.sh waitmovement -fi +INITIALSTATE="$(sxmo_screenlock.sh getCurState)" mainloop diff --git a/scripts/core/sxmo_resetscaninterval.sh b/scripts/core/sxmo_resetscaninterval.sh deleted file mode 100755 index 20384c2..0000000 --- a/scripts/core/sxmo_resetscaninterval.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -# this script resets the wireless scan interval (value is in ms) -# it is invoked with a delay after waking from sleep -# to prevent the scan interval from being too quick, and thus -# too battery consuming, whilst no networks are found - -# the kernel parameter must be writable for the user -# or this script must have the setsuid bit set! - -echo 16000 > /sys/module/8723cs/parameters/rtw_scan_interval_thr diff --git a/scripts/core/sxmo_screenlock.sh b/scripts/core/sxmo_screenlock.sh new file mode 100755 index 0000000..8043816 --- /dev/null +++ b/scripts/core/sxmo_screenlock.sh @@ -0,0 +1,196 @@ +#!/usr/bin/env sh + +# include common definitions +# shellcheck source=scripts/core/sxmo_common.sh +. "$(dirname "$0")/sxmo_common.sh" + +# Run xinput and get touchscreen id +TOUCH_POINTER_ID="${TOUCH_POINTER_ID:-"8"}" + +REDLED_PATH="/sys/class/leds/red:indicator/brightness" +BLUELED_PATH="/sys/class/leds/blue:indicator/brightness" + +WAKEUPRTC="/sys/class/wakeup/wakeup1/active_count" +MODEMUPRTC="/sys/class/wakeup/wakeup10/active_count" +NETWORKRTCSCAN="/sys/module/8723cs/parameters/rtw_scan_interval_thr" + +OLD_RTC_WAKECOUNT="$XDG_RUNTIME_DIR/wakeup.rtc.count" +OLD_MODEM_WAKECOUNT="$XDG_RUNTIME_DIR/wakeup.modem.count" + +saveAllEventCounts() { + cat "$WAKEUPRTC" > "$OLD_RTC_WAKECOUNT" + cat "$MODEMUPRTC" > "$OLD_MODEM_WAKECOUNT" + # TODO: add logic for modem wakeup +} + +whichWake() { + if [ "$(cat $WAKEUPRTC)" -gt "$(cat $OLD_RTC_WAKECOUNT)" ] ; then + echo "rtc" + elif [ "$(cat $MODEMUPRTC)" -gt "$(cat $OLD_MODEM_WAKECOUNT)" ] ; then + echo "modem" + else + # button does not have a active count so if it's none of the above, it has to be the button + echo "button" + fi +} + +getCurState() { + if xinput list-props "$TOUCH_POINTER_ID" | grep "Device Enabled" | grep -q "0$"; then + if xset q | grep -q "Off: 3"; then + echo "off" + else + echo "lock" + fi + else + echo "unlock" + fi +} + +updateLed() { + case "$(getCurState)" in + "off") + echo 1 > "$REDLED_PATH" + echo 1 > "$BLUELED_PATH" + ;; + "lock") + echo 0 > "$REDLED_PATH" + echo 1 > "$BLUELED_PATH" + ;; + "unlock") + echo 0 > "$REDLED_PATH" + echo 0 > "$BLUELED_PATH" + ;; + esac +} + +if [ "$1" = "lock" ] ; then + # always echo last state first so that user can use it in their hooks + # TODO: Document LASTSTATE + getCurState > "$LASTSTATE" + # Do we want this hook after disabling all the input devices so users can enable certain devices? + if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/lock" ]; then + "$XDG_CONFIG_HOME/sxmo/hooks/lock" + fi + + xset dpms 0 0 0 + xset dpms force on + + # TODO: Could be improved by running xinput and disabling ALL input devices automatically but would need + # to decide on the hook issues. Do we want a prelock and postlock? Or should users + # be expected to edit the source code for disabling certain input devices? + # this code allows us to not use the slock locking mechanism in the original sxmo_lock.sh + # when combined with a working slock (see ~iv's) implementation, this should be secure. + xinput disable "$TOUCH_POINTER_ID" + killall lisgd + + updateLed + exit 0 +elif [ "$1" = "unlock" ] ; then + getCurState > "$LASTSTATE" + if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/unlock" ]; then + "$XDG_CONFIG_HOME/sxmo/hooks/unlock" + fi + + xset dpms 0 0 0 + xset dpms force on + xinput enable "$TOUCH_POINTER_ID" + sxmo_lisgdstart.sh + + updateLed + exit 0 +elif [ "$1" = "off" ] ; then + getCurState > "$LASTSTATE" + # TODO: document this hook + if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/screenoff" ]; then + "$XDG_CONFIG_HOME/sxmo/hooks/screenoff" + fi + + xset dpms 0 0 3 + xset dpms force off + # stop responding to input + xinput disable "$TOUCH_POINTER_ID" + killall lisgd + + updateLed + exit 0 +elif [ "$1" = "crust" ] ; then + getCurState > "$LASTSTATE" + + if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/presuspend" ]; then + "$XDG_CONFIG_HOME/sxmo/hooks/presuspend" + fi + + echo 1 > "$REDLED_PATH" + echo 0 > "$BLUELED_PATH" + xset dpms force off + + # configure crust + # TODO: disable all wakeup sources other than button, rtc, and modem. + # TODO: make sure there is logic in whichWake and saveAllEventCounts functions + # Do I need to unbind? https://git.sr.ht/~mil/sxmo-utils/commit/bcf4f5c24968df0055d15a9fca649f67de9ced6a + echo "deep" > /sys/power/mem_sleep # deep sleep + + echo "mem" > /sys/power/state + + echo "crust" > "$LASTSTATE" + + updateLed + xset dpms force on + + # all we know is it's not the rtc. Maybe modem? + # TODO: Check mmcli or something or sxmo's notifs when + # https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/issues/356 + # https://gitlab.com/postmarketOS/pmaports/-/merge_requests/2066 + # fixed + # TODO: Document UNSUSPENDREASONFILE + echo "nonrtc" > "$UNSUSPENDREASONFILE" + + if [ "$(whichWake)" = "button" ] && [ -x "$XDG_CONFIG_HOME/sxmo/hooks/postwake" ]; then + "$XDG_CONFIG_HOME/sxmo/hooks/postwake" + fi + + exit 0 +elif [ "$1" = "rtc" ] ; then + getCurState > "$LASTSTATE" + # USER MUST USE sxmo_screenlock.sh rtc rather than using rtcwake directly. + # With this new version of lock, we dont check the exit code of the user hook. User must execute "sxmo_screenlock.sh rtc $TIME" at the end of their hook (depending on whether they want to re-rtc) + echo 1 > "$REDLED_PATH" + echo 0 > "$BLUELED_PATH" + + saveAllEventCounts + + if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/presuspend" ]; then + "$XDG_CONFIG_HOME/sxmo/hooks/presuspend" + fi + + xset dpms force off + rtcwake -m mem -s "$2" + whichWake > "$UNSUSPENDREASONFILE" + + echo "crust" > "$LASTSTATE" + + updateLed + + if [ "$(whichWake)" = "rtc" ]; then + WAKEHOOK="$XDG_CONFIG_HOME/sxmo/hooks/rtcwake"; + elif [ "$(whichWake)" = "button" ]; then + WAKEHOOK="$XDG_CONFIG_HOME/sxmo/hooks/postwake"; + fi + + if [ "$(whichWake)" != "rtc" ]; then + xset dpms force on + fi + + if [ -x "$WAKEHOOK" ]; then + echo 1200 > "$NETWORKRTCSCAN" + "$WAKEHOOK" + echo 16000 > "$NETWORKRTCSCAN" + fi + exit 0 +elif [ "$1" = "getCurState" ] ; then + getCurState + exit 0 +fi + + +echo "usage: sxmo_screenlock.sh [lock|unlock|off|crust|rtc|getCurState]" diff --git a/scripts/modem/sxmo_modemcall.sh b/scripts/modem/sxmo_modemcall.sh index b2b98a6..d565180 100755 --- a/scripts/modem/sxmo_modemcall.sh +++ b/scripts/modem/sxmo_modemcall.sh @@ -171,7 +171,7 @@ incallmenuloop() { echo "sxmo_modemcall: Current flags are $FLAGS">&2 CHOICES=" $([ "$WINDOWIFIED" = 0 ] && echo "$icon_wn2 Windowify" || echo "$icon_wn2 Unwindowify") ^ togglewindowify - $([ "$WINDOWIFIED" = 0 ] && echo "$icon_lck Screenlock ^ togglewindowify; sxmo_screenlock &") + $([ "$WINDOWIFIED" = 0 ] && echo "$icon_lck Screenlock ^ togglewindowify; sxmo_screenlock.sh lock &") $icon_aru Volume up ^ sxmo_vol.sh up $icon_ard Volume down ^ sxmo_vol.sh down $icon_phn Earpiece $(echo -- "$FLAGS" | grep -q -- -e && echo "$icon_chk") ^ toggleflagset -e @@ -239,8 +239,6 @@ incomingcallmenu() { NUMBER=$(vid_to_number "$1") CONTACTNAME=$(number_to_contactname "$NUMBER") - # wait for sxmo to be unlocked to display menus - while pgrep sxmo_screenlock > /dev/null; do sleep 0.3; done PICKED="$( printf %b "$icon_phn Pickup\n$icon_phx Hangup\n$icon_mut Mute\n" | dmenu -c -l 5 -p "$CONTACTNAME" diff --git a/scripts/modem/sxmo_modemmonitor.sh b/scripts/modem/sxmo_modemmonitor.sh index 1f64631..f94d6e3 100755 --- a/scripts/modem/sxmo_modemmonitor.sh +++ b/scripts/modem/sxmo_modemmonitor.sh @@ -116,6 +116,13 @@ checkforfinishedcalls() { "st -f Terminus-20 -e sh -c \"echo 'Missed call from $CONTACT at $(date)' && read\"" \ none \ "Missed call - $CONTACT" + + if grep -q modem "$UNSUSPENDREASONFILE" && grep -q crust "$CACHEDIR/${FINISHEDCALLID}.laststate"; then + sleep 5 # maybe user just is too late + if [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; then + sxmo_screenlock.sh crust + fi + fi fi done } @@ -131,11 +138,15 @@ checkforincomingcalls() { [ -f "$CACHEDIR/${VOICECALLID}.monitoredcall" ] && return # prevent multiple rings touch "$CACHEDIR/${VOICECALLID}.monitoredcall" #this signals that we handled the call + cat "$LASTSTATE" > "$CACHEDIR/${VOICECALLID}.laststate" + # Determine the incoming phone number echo "sxmo_modemmonitor: Incoming Call:">&2 INCOMINGNUMBER=$(lookupnumberfromcallid "$VOICECALLID") CONTACTNAME=$(lookupcontactname "$INCOMINGNUMBER") + xset dpms force on + if [ -x "$XDG_CONFIG_HOME/sxmo/hooks/ring" ]; then echo "sxmo_modemmonitor: Invoking ring hook (async)">&2 "$XDG_CONFIG_HOME/sxmo/hooks/ring" "$CONTACTNAME" & @@ -160,6 +171,8 @@ checkfornewtexts() { )" echo "$TEXTIDS" | grep -v . && return + xset dpms force on + # Loop each textid received and read out the data into appropriate logfile for TEXTID in $TEXTIDS; do TEXTDATA="$(mmcli -m "$(modem_n)" -s "$TEXTID" -K)" @@ -188,6 +201,13 @@ checkfornewtexts() { "$XDG_CONFIG_HOME/sxmo/hooks/sms" "$CONTACTNAME" "$TEXT" fi done + + if grep -q modem "$UNSUSPENDREASONFILE" && grep -q crust "$LASTSTATE"; then + sleep 5 # maybe user just is too late + if [ "$(sxmo_screenlock.sh getCurState)" != "unlock" ]; then + sxmo_screenlock.sh crust + fi + fi } initialmodemstatus() {