hypridle icon indicating copy to clipboard operation
hypridle copied to clipboard

hypridle doesn't wait for animation to finish before suspend

Open danielepintore opened this issue 7 months ago • 24 comments

Problem Description

Hello, first of all thanks for your software. I've been using hyprlock and hypridle for a while now. But there is a problem that seems I can't fix it: After I suspend my system with systemctl suspend or I close the lid of my laptop, when I wake up the system I see for a split second a flash with the screen content. I think the problem is the fact that the animations are active on hyprlock, because when I disable them the problem seems to be fixed. Seems that the lock given from hyprlock-lock-notify-v1 it's a little early if animations are enabled.

What I've tried to fix

I've tried to change the inhibit_sleep value to 3 without any luck. I've also tried to change my hyprlock and hypridle config to the default one without any luck.

Hyprland 0.48.1 built from branch at commit 29e2e59fdbab8ed2cc23a20e3c6043d5decb5cdc (version: bump to v0.48.1). Date: Fri Mar 28 16:16:07 2025 Tag: v0.48.1, commits: 5937 built against: aquamarine 0.8.0 hyprlang 0.6.1 hyprutils 0.7.0 hyprcursor 0.1.12 hyprgraphics 0.1.3

P.S. I'm using uwsm and i have activated the hypridle service

Hyprlock config Hyprlock version v0.8.2
background {
    monitor =
    path = ~/.config/hypr/wallpapers/background.jpg
    color = rgba(25, 20, 20, 1.0)

    # all these options are taken from hyprland, see https://wiki.hyprland.org/Configuring/Variables/#blur for explanations
    blur_passes = 3
    blur_size = 8
    contrast = 0.8916
    brightness = 0.7172
    vibrancy = 0.1696
    vibrancy_darkness = 0
}

#animations {
#	enabled = false
#}

input-field {
    monitor =
    size = 300, 30
    outline_thickness = 0
    dots_size = 0.25 # Scale of input-field height, 0.2 - 0.8
    dots_spacing = 0.55 # Scale of dots' absolute size, 0.0 - 1.0
    dots_center = true
    dots_rounding = -1
    outer_color = rgba(242, 243, 244, 0)
    inner_color = rgba(242, 243, 244, 0)
    font_color = rgba(242, 243, 244, 0.75)
    fade_on_empty = false
    placeholder_text = # Text rendered in the input box when it's empty.
    hide_input = false
    check_color = rgba(204, 136, 34, 0)
    fail_color = rgba(204, 34, 34, 0) # if authentication failed, changes outer_color and fail message color
    fail_text = $FAIL <b>($ATTEMPTS)</b> # can be set to empty
    capslock_color = -1
    numlock_color = -1
    bothlock_color = -1 # when both locks are active. -1 means don't change outer color (same for above)
    invert_numlock = false # change color if numlock is off
    swap_font_color = false # see below
    position = 0, -470
    halign = center
    valign = center
}

label {
  monitor =
  text = cmd[update:1000] echo "$(date +"%A, %B %d")"
  color = rgba(242, 243, 244, 0.75)
  font_size = 20
  font_family = SF Pro Display Bold
  position = 0, 400
  halign = center
  valign = center
}

label {
  monitor = 
  text = $TIME
  color = rgba(242, 243, 244, 0.75)
  font_size = 93
  font_family = SF Pro Display Bold
  position = 0, 253
  halign = center
  valign = center
}

label {
    monitor =
    text = $USER
    color = rgba(242, 243, 244, 0.75)
    font_size = 12
    font_family = SF Pro Display Bold
    position = 0, -407
    halign = center
    valign = center
}

label {
    monitor =
    text = Enter Password
    color = rgba(242, 243, 244, 0.75)
    font_size = 10
    font_family = SF Pro Display
    position = 0, -440
    halign = center
    valign = center
}
Hypridle config hypridle v0.1.6
general {
    lock_cmd = pidof hyprlock || hyprlock											# dbus/sysd lock command (loginctl lock-session)
    before_sleep_cmd = playerctl stop; loginctl lock-session							# command ran before sleep
    after_sleep_cmd = hyprctl dispatch dpms on  # to avoid having to press a key twice to turn on the display.
}

listener {
    timeout = 360                            # in seconds
    on-timeout = loginctl lock-session										 # command to run when timeout has passed
}

listener {
    timeout = 600                            # in seconds
    on-timeout = systemctl suspend										 # command to run when timeout has passed
}

Thanks for any help!

danielepintore avatar May 06 '25 09:05 danielepintore

The problem seems to be that before_sleep_cmd doesn't actually execute before the user is frozen by systemd-suspend, so effectively hyperlock starts after the system has already woken up.

After some tinkering, I found that an acceptable solution for me was to hack systemd directly, delaying its suspend service by 0.6s (would be something else for you). To do that, e.g., create /etc/systemd/system/[email protected] with

[Unit]
Description=Delay Suspend by 0.6s
Before=sleep.target

[Service]
User=%i
Type=oneshot
ExecStart=/usr/bin/bash -c "sleep 0.6"

[Install]
WantedBy=sleep.target

inside and then enable/start the service via # systemctl enable --now user-suspend@<USER>.service Here <USER> is the user who'd be running the service. You may also change ExecStart if needed for your setup. Hopefully this works for you!

IiroUllin avatar Jun 11 '25 02:06 IiroUllin

Thanks, I’ll try that. Hopefully somedays this problem will be fixed

danielepintore avatar Jun 12 '25 08:06 danielepintore

I see hypridle's inhibition in systemd-inhibit --list. Is it being released early?

Vladimir-csp avatar Jul 02 '25 11:07 Vladimir-csp

Here what I've found using this config:

general {
    lock_cmd = date > ~/lock-idle.log
    before_sleep_cmd = sleep 2 && pidof hyprlock || hyprlock
    after_sleep_cmd = hyprctl dispatch dpms on
}

Running this seems that hypridle waits 2 seconds before suspending the system. But there is something strange:

Given the output of journalctl -u systemd-logind.service:

Jul 02 16:06:18 thinkpad systemd-logind[972]: The system will suspend now!
Jul 02 16:06:24 thinkpad systemd-logind[972]: Operation 'suspend' finished.

and the lock-idle.log file contains:

Wed Jul  2 04:06:27 PM CEST 2025

It seems that the lock command is being executed after the system has finished suspending, and with a noticeable delay

danielepintore avatar Jul 02 '25 14:07 danielepintore

little update: I have installed swaylock. Using it with hypridle seems to work fine. Can anyone else try this? Maybe it is a hyprlock problem. I'm using the same configuration that is in my first comment.

I'm more confused than before 😕

general { lock_cmd = pidof hyprlock || hyprlock # dbus/sysd lock command (loginctl lock-session) before_sleep_cmd = playerctl stop; loginctl lock-session # command ran before sleep after_sleep_cmd = hyprctl dispatch dpms on # to avoid having to press a key twice to turn on the display. }

listener { timeout = 360 # in seconds on-timeout = loginctl lock-session # command to run when timeout has passed }

listener { timeout = 600 # in seconds on-timeout = systemctl suspend # command to run when timeout has passed }

danielepintore avatar Jul 02 '25 14:07 danielepintore

@Vladimir-csp yes, something like that. It seems that hypridle fires off its before_sleep_cmd but doesn't wait until it finishes and gives the reigns back to systemd. The latter immediately freezes user space processes, so pretty much everything that in before_sleep_cmd then only runs after the suspend is over...

IiroUllin avatar Jul 02 '25 14:07 IiroUllin

@danielepintore It's possible that swaylock is very quick and manages to lock the system before its frozen. But I think the main issue is that before_sleep_cmd is kind of misleading as it is right now: it really only starts executing right before suspension, however, there is no mechanism in place to wait until it finishes. My solution was just to add a bit of delay to systemd-suspend itself, but it's not particularly elegant, as that delay must be hand-tuned. The proper solution would be to have hypridle wait until its before_sleep_cmd finishes running and only then release its lock, but I remember reading in some other thread that it's not going to happen. (Regrettably, but also understandably so, as it's not trivial or even possible in the most general circumstances.)

IiroUllin avatar Jul 02 '25 14:07 IiroUllin

yes, you are right, using sleep 3 && swaylock as the lock command results in the same behavior

danielepintore avatar Jul 02 '25 19:07 danielepintore

But I think the main issue is that before_sleep_cmd is kind of misleading as it is right now: it really only starts executing right before suspension, however, there is no mechanism in place to wait until it finishes.

This^! However, hyprland-lock-notify-v1 and hypridles inhibit_sleep option is intended to be the mechanism that guaranties the system fully locks before going to sleep.

The feature not working can have 2 different causes.

  1. Your system doesn't let hypridle inhibit when it needs to, there is a bug in hypridles sleep inhibition, or you don't have inhibit_sleep set to auto (and it is enabled with "wait until locked") or 3, or your logind configuration doesn't allow hyprlidle to inhibit sleep. Identifying this is can be done when examining hypridle logs. So I encourage you to post your hypridle logs here.
  2. Hypridle successfully inhibits sleep and releases it at the right time, but hyprlock doesn't manage to actually draw a frame that covers the screen with it's own content. On the one hand this is a problem with fade-in. You will need --no-fade-in, because the fade in is something that the Hyprland doesn't know about and the hyprland-lock-notify protocol is intended to work for all session-lock clients. On the other hand, hyprlock before https://github.com/hyprwm/hyprlock/pull/726 (so 0.8.2) has some edge cases in the background widget that may lead to the first frame being leaky. That goes together with https://github.com/hyprwm/Hyprland/pull/10865 which will guaranty that workspaces wont be rendered any more when hypridle recieves lock from hyprland-lock-notifiy.

Generally about the hyprland-lock-notify protocol: The notification for locked only gets sent, when all monitors of your session get covered with one lock-screen frame. (See this code)

If you are willing to test the stuff I have been working on to fix this problem, do this:

  1. Use hyprlock git.
  2. Compile and run this pr https://github.com/hyprwm/Hyprland/pull/10865 (Or wait until it's merged)
  3. Use --no-fade-in when locking before sleep. I suggest a config like this (this way, --no-fade-in is only used when locking before sleep):
    general {
        lock_cmd = hyprlock
        before_sleep_cmd = hyprlock --no-fade-in
        after_sleep_cmd = hyprctl dispatch dpms on
    }
    
  4. Make sure that hypridle logs Sleep inhibition enabled - inhibiting until the wayland session gets locked when it start's up.
  5. Before locking, check systemd-inhibit --list to verifiy hypridle successfully inhibits sleep.

When everything works as intended, you do systemctl suspend (keep in mind! something like rtcwake or other utilities do not respect systemd's sleep inhibit!) Since hypridle has inhibited sleep, sleep will not hit immediately. hypridle recieves "PrepareForSleep" from systemd dbus and launches your before_sleep_cmd. Hypridle does not release the sleep inhibitor after it launched before_sleep_cmd. Sleep is still inhibited. Meanwhile hyprlock starts up and locks the session. When hyprlock commited a lock-surface for each output (aka. it covered all monitors), the compositor (Hyprland) will notify Hypridle that the session was locked and thus hypridle will release the inhibitor and the system can go to sleep. This is how it is supposed to work.

PointerDilemma avatar Jul 03 '25 07:07 PointerDilemma

After some time tinkering I've finally found and implemented a proper fix. This requires changes in hyprlock and hypridle.

At the moment hypridle inhibits the system from suspend, launches the lock_cmd and other commands that should run before the sleep, then releases the inhibit lock. The problem with this approach is that sometimes, due to the speed of the computer or due to the configuration of hyprlock this can cause the system to go to sleep before the lock application has finished to launch.

This can be easily reproduced by slowing the animation on hyprlock:

animations {
		enabled = true
		animation = fade, 1, 15, linear
}

In order to fix this problem we need a way to know when the lock has finished drawing the transition (the animation), wait and then release the suspend lock. This is feasible since when we acquire the delay type of inhibit, logind will wait a maximum of 5 seconds and the force the suspend anyway.

I'm not a C++ programmer but I managed to implement a janky proof of concept.

hypridle.patch
diff --git a/src/core/Hypridle.cpp b/src/core/Hypridle.cpp
index 13537c7..13fb586 100644
--- a/src/core/Hypridle.cpp
+++ b/src/core/Hypridle.cpp
@@ -6,6 +6,7 @@
 #include <sys/wait.h>
 #include <sys/poll.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <algorithm>
@@ -324,13 +325,26 @@ void CHypridle::onInhibit(bool lock) {
     Debug::log(LOG, "Inhibit locks: {}", m_iInhibitLocks);
 }
 
+void CHypridle::waitForLockfileRemoval(const char* lockfile, std::chrono::milliseconds interval) {
+    struct stat st;
+    while (::stat(lockfile, &st) == 0) {
+        std::this_thread::sleep_for(interval);
+    }
+}
+
 void CHypridle::onLocked() {
     Debug::log(LOG, "Wayland session got locked");
     m_isLocked = true;
 
-    static const auto LOCKCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:on_lock_cmd");
-    if (!std::string{*LOCKCMD}.empty())
-        spawn(*LOCKCMD);
+    static const auto ONLOCKCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:on_lock_cmd");
+    static const auto LOCKCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:lock_cmd");
+
+    if (!std::string{*ONLOCKCMD}.empty())
+        spawn(*ONLOCKCMD);
+
+    if (std::string{*LOCKCMD}.contains("hyprlock"))
+        waitForLockfileRemoval("/tmp/hyprlock.lock"); // we have max 5 seconds to delete the lock or logind will continue anyway
+                                                      // the 5 seconds is the time that logind waits for delay inhibit
 
     if (m_inhibitSleepBehavior == SLEEP_INHIBIT_LOCK_NOTIFY)
         uninhibitSleep();
diff --git a/src/core/Hypridle.hpp b/src/core/Hypridle.hpp
index 395b07c..3410c82 100644
--- a/src/core/Hypridle.hpp
+++ b/src/core/Hypridle.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <chrono>
 #include <memory>
 #include <vector>
 #include <sdbus-c++/sdbus-c++.h>
@@ -53,6 +54,7 @@ class CHypridle {
   private:
     void    setupDBUS();
     void    enterEventLoop();
+    void    waitForLockfileRemoval(const char* lockfile, std::chrono::milliseconds interval = std::chrono::milliseconds(100));
 
     bool    m_bTerminate    = false;
     bool    isIdled         = false;
hyprlock.patch
diff --git a/src/core/hyprlock.cpp b/src/core/hyprlock.cpp
index 0b5fa69..f8478d5 100644
--- a/src/core/hyprlock.cpp
+++ b/src/core/hyprlock.cpp
@@ -6,6 +6,7 @@
 #include "../auth/Auth.hpp"
 #include "../auth/Fingerprint.hpp"
 #include "Egl.hpp"
+#include "src/helpers/MiscFunctions.hpp"
 #include <chrono>
 #include <hyprutils/memory/UniquePtr.hpp>
 #include <sys/wait.h>
@@ -239,6 +240,7 @@ void CHyprlock::addDmabufListener() {
 }
 
 void CHyprlock::run() {
+    spawnAsync("touch /tmp/hyprlock.lock");
     m_sWaylandState.registry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(m_sWaylandState.display));
     m_sWaylandState.registry->setGlobal([this](CCWlRegistry* r, uint32_t name, const char* interface, uint32_t version) {
         const std::string IFACE = interface;
diff --git a/src/renderer/Renderer.cpp b/src/renderer/Renderer.cpp
index 41bdb0a..7716045 100644
--- a/src/renderer/Renderer.cpp
+++ b/src/renderer/Renderer.cpp
@@ -12,6 +12,7 @@
 #include <GLES3/gl3ext.h>
 #include <GLES2/gl2ext.h>
 #include <algorithm>
+#include "src/helpers/MiscFunctions.hpp"
 #include "widgets/PasswordInputField.hpp"
 #include "widgets/Background.hpp"
 #include "widgets/Label.hpp"
@@ -610,7 +611,12 @@ void CRenderer::startFadeIn() {
     Debug::log(LOG, "Starting fade in");
     *opacity = 1.f;
 
-    opacity->setCallbackOnEnd([this](auto) { opacity->setConfig(g_pConfigManager->m_AnimationTree.getConfig("fadeOut")); }, true);
+    opacity->setCallbackOnEnd(
+        [this](auto) {
+            opacity->setConfig(g_pConfigManager->m_AnimationTree.getConfig("fadeOut"));
+            spawnAsync("rm /tmp/hyprlock.lock");
+        },
+        true);
 }
 
 void CRenderer::startFadeOut(bool unlock) {

Then you need to apply these patches to hypridle and hyprlock. These patches allow to hyprlock to generate a lockfile in the startup and delete it when the transition is over. hypridle waits for the lockfile and then inhibits the suspend. I think this can done in a more polished way avoiding the lockfile and maybe sending some kind of signal, but I'm not a c++ programmer and I don't know how to do it. But this simple approach will fix this bug.

danielepintore avatar Jul 03 '25 07:07 danielepintore

Bro, did you even read my comment??

PointerDilemma avatar Jul 03 '25 08:07 PointerDilemma

@PaideiaDilemma For me the problem is with the fade in animation, if it takes too long to finish it will cause this problem. I'll wait until #10865 gets merged and give it a try. But I think from a ux standpoint that the user should see the screen to lock with the transition that it's selected, then suspend the system.

danielepintore avatar Jul 03 '25 08:07 danielepintore

We discussed and thought about how to solve the locking race when suspending quite a bit and opted for a solution that works with all session-lock clients. That sadly means you need to use --no-fade-in in your before_sleep_cmd.

PointerDilemma avatar Jul 03 '25 08:07 PointerDilemma

Thanks, indeed using hyprlock with --no-fade-in in before_sleep_cmd works fine. I think since this is the expected approach that we should add a little info section about this in the wiki. For the moment, I'll keep this issue open for anyone else having this problem.

danielepintore avatar Jul 03 '25 08:07 danielepintore

Yes @danielepintore, that would be top!

Also there are those potential problems i mentioned above. So better keep it open.

PointerDilemma avatar Jul 03 '25 12:07 PointerDilemma

I also thought about adding an environment variable that overrides fade in for hyprlock. Something like HYPRLOCK_NO_FADE_IN. That could be set by hypridle for the before_sleep_cmd and thus hyprlock would automatically disable fade-in in case it is launched in an before_sleep_cmd context.

However, so far I didn't bother to implement that, because I think most people redirect to lock_cmd anyways. Meaning they call loginctl lock-session in their before_sleep_cmd and not call the lockscreen application directly. (Just adds a useless dbus roundtrip and breaks this idea with HYPRLOCK_NO_FADE_IN in the environment)

PointerDilemma avatar Jul 03 '25 12:07 PointerDilemma

@PaideiaDilemma I ran some experiments of the kind that you suggested. Didn't get the pr you mentioned though, so am using 0.1.6-5 version of hypridle which came with recent arch update. Let me know if that is essential: it might take some extra time to get to that...

Relevant parts of my config:

hypridle.config

    general {
      lock_cmd = pidof hyprlock || hyprlock
      before_sleep_cmd = $SCRIPTS/before-sleep-cmd.sh
      after_sleep_cmd = $SCRIPTS/after-sleep-cmd.sh
    }
before-sleep-cmd.sh

echo "Before 1->$(date +%T)"

hyprlock --no-fade-in
#loginctl lock-session

echo "Before 2->$(date +%T)"
after-sleep-cmd.sh

echo "After 1->$(date +%T)"

hyprctl dispatch dpms on  

echo "After 2->$(date +%T)"

The hypridle does hold an inhibit lock as manifested in the log (not shown, as it is way earlier) and is also confirmed by calling system-inhibit. However, the lock is released too early and systemd freezes it way before hyprlock manages to do anything at all. In fact, after system wakes from suspended state, I can even sneak in a few keystrokes into the terminal (which still has focus) before hyprlock engages...

log with a few comments

Jul 04 09:55:01 nebula hypridle[20777]: [LOG] Got PrepareForSleep from dbus with sleep true
Jul 04 09:55:01 nebula hypridle[20777]: [LOG] Executing ~/.config/hypr/scripts/before-sleep-cmd.sh
Jul 04 09:55:01 nebula hypridle[20777]: [LOG] Process Created with pid 22351
Jul 04 09:55:01 nebula hypridle[20777]: [LOG] Releasing the sleep inhibitor!
Jul 04 09:55:01 nebula hypridle[22351]: Before 1->09:55:01

This is way too fast: the lock is released immediately after the before_sleep_cmd is called. At this moment systemd freezes the userspace and all the following events happen already after waking from the sleep.


Jul 04 09:55:13 nebula hypridle[20777]: [LOG] Got PrepareForSleep from dbus with sleep false
Jul 04 09:55:14 nebula hypridle[20777]: [LOG] Inhibited sleep with fd 10
Jul 04 09:55:14 nebula hypridle[20777]: [LOG] Executing ~/.config/hypr/scripts/after-sleep-cmd.sh
Jul 04 09:55:14 nebula hypridle[20777]: [LOG] Process Created with pid 22673
Jul 04 09:55:14 nebula hypridle[22673]: After 1->09:55:14
Jul 04 09:55:14 nebula hypridle[22675]: Couldn't commit output {}
Jul 04 09:55:14 nebula hypridle[22673]: After 2->09:55:14

You can see, there's a split second before the system gets locked, and the terminal window from which I started systemctl suspend still has focus. I can even manage to sneak some keystrokes in...


Jul 04 09:55:14 nebula hypridle[20777]: [LOG] Wayland session got locked
Jul 04 09:55:14 nebula hypridle[20777]: [LOG] Executing
Jul 04 09:55:14 nebula hypridle[20777]: [LOG] Process Created with pid 22708
Jul 04 09:55:16 nebula hypridle[22354]: Hyprlock version v0.8.2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wl_seat v9
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to wl_seat v9
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wl_data_device_manager v3
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wl_compositor v6
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to wl_compositor v6
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wl_subcompositor v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wl_shm v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to wl_shm v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_viewporter v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to wp_viewporter v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_tearing_control_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_fractional_scale_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to wp_fractional_scale_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zxdg_output_manager_v1 v3
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_cursor_shape_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to wp_cursor_shape_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_idle_inhibit_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_relative_pointer_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zxdg_decoration_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_alpha_modifier_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_gamma_control_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: ext_foreign_toplevel_list_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_pointer_gestures_v1 v3
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_foreign_toplevel_manager_v1 v3
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_keyboard_shortcuts_inhibit_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_text_input_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_text_input_manager_v3 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_pointer_constraints_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_output_power_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: xdg_activation_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: ext_idle_notifier_v1 v2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: hyprland_lock_notifier_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: ext_session_lock_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to ext_session_lock_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_input_method_manager_v2 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_virtual_keyboard_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_virtual_pointer_manager_v1 v2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_output_manager_v1 v4
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: org_kde_kwin_server_decoration_manager v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: hyprland_focus_grab_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_tablet_manager_v2 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_layer_shell_v1 v5
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_presentation v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: xdg_wm_base v6
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_data_control_manager_v1 v2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_primary_selection_device_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: xwayland_shell_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwlr_screencopy_manager_v1 v3
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to zwlr_screencopy_manager_v1 v3
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: hyprland_toplevel_export_manager_v1 v2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: hyprland_toplevel_mapping_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: hyprland_global_shortcuts_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: xdg_wm_dialog_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_single_pixel_buffer_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_security_context_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: hyprland_ctm_control_manager_v1 v2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: hyprland_surface_manager_v1 v2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_content_type_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: xdg_toplevel_tag_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: xdg_system_bell_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_color_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_drm_lease_device_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wp_linux_drm_syncobj_manager_v1 v1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wl_drm v2
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: zwp_linux_dmabuf_v1 v5
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to zwp_linux_dmabuf_v1 v5
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]   | got iface: wl_output v4
Jul 04 09:55:16 nebula hypridle[22354]: [LOG]    > Bound to wl_output v4
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Exposed seat name: Hyprland
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] [core] dmabufFeedbackMainDevice
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] output eDP-1 name eDP-1
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] output 58 description BOE 0x0BC7  (eDP-1)
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] output 58 make BOE model 0x0BC7
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] output 58 done
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Running on Hyprland
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Locking session
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Starting fade in
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] fprint: using device path /net/reactivated/Fprint/Device/0
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Got fractional scale: 160.0%
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] configure with serial 10279
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Configuring surface for logical [Vector2D: x: 1600, y: 1000] and pixel [Vector2D: x: 2560, y: 1600]
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] onLockLocked called
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] fprint: claimed device
Jul 04 09:55:16 nebula hypridle[22354]: [ERR] Invalid key down event (stray release event?)
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] fprint: started verifying
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] fprint: finger selected: right-index-finger
Jul 04 09:55:16 nebula hypridle[22354]: [ERR] Invalid key down event (stray release event?)
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] fprint: handling status verif
Jul 04 09:55:16 nebula hypridle[20777]: [LOG] Wayland session got unlocked
Jul 04 09:55:16 nebula hypridle[20777]: [LOG] Executing
Jul 04 09:55:16 nebula hypridle[20777]: [LOG] Process Created with pid 22729
Jul 04 09:55:16 nebula hypridle[22354]: y-match
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] fprint: stopped verification
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Unlocking session
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Unlocked, exiting!
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] fprint: released device
Jul 04 09:55:16 nebula hypridle[22354]: [LOG] Reached the end, exiting
Jul 04 09:55:16 nebula hypridle[22351]: Before 2->09:55:16

It is a bit weird that this "Before 2->" echo only fired off in the very end. this means that before_sleep_cmd actually finished executing way after after_sleep_cmd. This doesn't happen if instead of invoking hyprlock directly I use loginctl lock-session; then hyprlock is called by hypridle through lock_cmd and before_sleep_cmd immediately finishes...

IiroUllin avatar Jul 03 '25 14:07 IiroUllin

@PaideiaDilemma -- posted some logs (see above)

Your system doesn't let hypridle inhibit when it needs to, there is a bug in hypridles sleep inhibition, or you don't have inhibit_sleep set to auto (and it is enabled with "wait until locked") or 3, or your logind configuration doesn't allow hyprlidle to inhibit sleep.

Could be something like that. I am not 100% certain at the moment that the sleep inhibition is fully working. Changing inhibit_sleep to 0 vs 3 results in different log messages (as expected) but there is no functional difference between these modes...

Also: I am not sure about the timestamps of the hypridle logs anymore. I've added systemd-suspend delay of 5s, so now I can clearly see that the hyprlock engages before the system suspends, however, I still see hyprlock's log messages appearing way after they should have... It's all very confusing 🤔

IiroUllin avatar Jul 04 '25 17:07 IiroUllin

@IiroUllin I told you to post your hypridle logs, but the part i would be interested in is missing...

PointerDilemma avatar Jul 10 '25 07:07 PointerDilemma

However, the lock is released too early and systemd freezes it way before hyprlock manages to do anything at all. In fact, after system wakes from suspended state, I can even sneak in a few keystrokes into the terminal (which still has focus) before hyprlock engages...

I think hypridle is woriking as expected here. It doesn't have any method to know when hyprlock has finished locking. Problably you system takes some time to suspend and it doesn't get to run it before the suspend event.

We discussed and thought about how to solve the locking race when suspending quite a bit and opted for a solution that works with all session-lock clients.

From what I've understood they decided to not implement that kind of feature since it would work only with hypridle and would require some special cases only for it since there isn't a standard way to know when the lock application has finished locking.

The trick of using --no-fade-in may not work on any system if they are slow?? On what hardware are you running?

Edit: if you are curious you can try my patch, that should make hypridle and hyprlock behave correctly. I personally think that a benefit of using the hypr-ecosystem can be this, so why not implement this special case just for hyprlock?

danielepintore avatar Jul 10 '25 08:07 danielepintore

The trick of using --no-fade-in may not work on any system if they are slow?? On what hardware are you running?

I already answered that multiple times. HYPRLAND WAITS FOR A RENDERED LOCKSURFACE ON EACH OUTPUT BEFORE IT SENDS LOCKED.

And using --no-fade-in is not a trick. It's is an inherent problem. The lockscreen is responsible for covering your screen. If it would screenshot your workspace and then render the workspace, it would be the lockscreens fault for showing your screen. Like for example when you use hyprlock with background:path=screenshot, but leave background:blur_passes=0.

Edit: if you are curious you can try my https://github.com/hyprwm/hypridle/issues/146#issuecomment-3031273599, that should make hypridle and hyprlock behave correctly. I personally think that a benefit of using thy hypr-ecosystem can be this, so why not implement this special case just for hyprlock?

My goal is to get it working for all lockscreen clients. Lots of people use swaylock for example. If you think this is a wrong approach, just because you can't get it to work on your system, please open a separate issue or a pr and suggest your changes there.

I would rather fix the problems that are present with this solutions. Maybe implement something that automatically disables fade in when we are currently inhibiting sleep.

@IiroUllin you wan't to open a new issue? cause op's and yours are not the same.

PointerDilemma avatar Jul 10 '25 08:07 PointerDilemma

I also think that a solution that works form all lockscreen client would be better. Uhh so it seems the issue that @IiroUllin has is hyprland not waiting for that lock.. I didn't understood that before, sorry..

danielepintore avatar Jul 10 '25 08:07 danielepintore

Sure, just started a new issue and posted my hypridle log there...

IiroUllin avatar Jul 10 '25 19:07 IiroUllin

Edit: there were many comments above, sorry i didn't dare to read them. All my below experience is from reading hyprland-wiki and github readme of hypridle and hyprlock.

@PaideiaDilemma , i am using hyprlock, hypridle and also have installed hyprland-protocol package under archlinux. I haven't tested heavily but when i triggered systemctl-suspend consecutively, system suspends before waiting for blur to get applied ( unless this is an edge case bug ). Or is something wrong on my side ?

In the below video, first attempt was perfect, but then it broke on all subsequent attempts.

https://github.com/user-attachments/assets/e5419800-5a94-4d02-8caa-0b40af1a868f

I will post my hypridle and hyprlock configs -->

Details

Hypridle -->

general {
    lock_cmd = hyprlock # avoid starting multiple hyprlock instances.
    unlock_cmd = killall hyprlock
    before_sleep_cmd = loginctl lock-session    # lock before suspend.
    after_sleep_cmd = hyprctl dispatch dpms on  # to avoid having to press a key twice to turn on the display.
}

listener {
    timeout = 120                                # 2min.
    on-timeout = brightnessctl -s set 10         # set monitor backlight to minimum, avoid 0 on OLED monitor.
    on-resume = brightnessctl -r                 # monitor backlight restore.
}

# turn off keyboard backlight, comment out this section if you dont have a keyboard backlight.
#listener { 
#    timeout = 150                                          # 2.5min.
#    on-timeout = brightnessctl -sd rgb:kbd_backlight set 0 # turn off keyboard backlight.
#    on-resume = brightnessctl -rd rgb:kbd_backlight        # turn on keyboard backlight.
#}

listener {
    timeout = 240                                 # 4min
    on-timeout = loginctl lock-session            # lock screen when timeout has passed
}

listener {
    timeout = 330                                                     # 5.5min
    on-timeout = hyprctl dispatch dpms off                            # screen off when timeout has passed
    on-resume = hyprctl dispatch dpms on && brightnessctl -r          # screen on when activity is detected after timeout has fired.
}

listener {
    timeout = 480                                # 8min
    on-timeout = systemctl suspend                # suspend pc
}

Hyprlock -->

# sample hyprlock.conf
# for more configuration options, refer https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock
#
# rendered text in all widgets supports pango markup (e.g. <b> or <i> tags)
# ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#general-remarks
#
# shortcuts to clear password buffer: ESC, Ctrl+U, Ctrl+Backspace
#
# you can get started by copying this config to ~/.config/hypr/hyprlock.conf
#

$font = Monospace


# uncomment to enable fingerprint authentication
# auth {
#     fingerprint {
#         enabled = true
#         ready_message = Scan fingerprint to unlock
#         present_message = Scanning...
#         retry_delay = 250 # in milliseconds
#     }
# }

animations {
    enabled = true
    bezier = linear, 1, 1, 0, 0
    animation = fadeIn, 1, 5, linear
    animation = fadeOut, 1, 5, linear
    animation = inputFieldDots, 1, 2, linear
}

background {
    monitor =
    path = screenshot
    blur_passes = 3
}

input-field {
    monitor =
    size = 20%, 5%
    outline_thickness = 3
    inner_color = rgba(0, 0, 0, 0.0) # no fill

    outer_color = rgba(33ccffee) rgba(00ff99ee) 45deg
    check_color = rgba(00ff99ee) rgba(ff6633ee) 120deg
    fail_color = rgba(ff6633ee) rgba(ff0066ee) 40deg

    font_color = rgb(143, 143, 143)
    fade_on_empty = false
    rounding = 15

    font_family = $font
    placeholder_text = Input password...
    fail_text = $PAMFAIL

    # uncomment to use a letter instead of a dot to indicate the typed password
    # dots_text_format = *
    # dots_size = 0.4
    dots_spacing = 0.3

    # uncomment to use an input indicator that does not show the password length (similar to swaylock's input indicator)
    # hide_input = true

    position = 0, -20
    halign = center
    valign = center
}

# TIME
label {
    monitor =
    text = $TIME # ref. https://wiki.hyprland.org/Hypr-Ecosystem/hyprlock/#variable-substitution
    font_size = 90
    font_family = $font

    position = -30, 0
    halign = right
    valign = top
}

# DATE
label {
    monitor =
    text = cmd[update:60000] date +"%A, %d %B %Y" # update every 60 seconds
    font_size = 25
    font_family = $font

    position = -30, -150
    halign = right
    valign = top
}

label {
    monitor =
    text = $LAYOUT[en,ru]
    font_size = 24
    onclick = hyprctl switchxkblayout all next

    position = 250, -20
    halign = center
    valign = center
}

KAGEYAM4 avatar Oct 02 '25 13:10 KAGEYAM4