Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add D-Bus signals to notify session lock and unlock states #609

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Iamanaws
Copy link

@Iamanaws Iamanaws commented Dec 25, 2024

Send an "Unlock" D-Bus signal to notify programs listening for Unlock events.

This enables tools like hypridle to detect the Unlock event and execute the unlock_cmd.

Issues:
hyprwm/hypridle#79
hyprwm/hypridle#112

@PaideiaDilemma
Copy link
Collaborator

While i understand what you want to achieve, i think that is not the way this dbus interface is supposed to work.

From org.freedesktop.login1:

Lock()/Unlock() is sent when the session is asked to be screen-locked/unlocked. A session manager of the session should listen to this signal and act accordingly. This signal is sent out as a result of the Lock() and Unlock() methods, respectively.

So from what i understand Unlock is not supposed to signal that we just unlocked, but to request an unlock?? Not entirely clear to me how it is supposed to be used though.

@Iamanaws
Copy link
Author

Yes, I agree it’s a bit unclear, but from what I understand, Unlock() is intended to inform the Session Manager and other programs listening to D-Bus that the lock screen should be removed. It’s up to each listening process to handle this notification as they see fit.

In this case, Hyprlock directly manages the unlock process via Wayland using the ext_session_lock_v1 interface. In other scenarios, a lock screen might call Unlock() to signal the Session Manager that the unlock should proceed after successful authentication.

The key point is that Unlock() does not handle the unlocking itself—it simply notifies that it should occur or has occurred. By sending the Unlock() method after handling the unlock, Hyprlock ensures compatibility with tools and listeners on D-Bus, even if it doesn’t rely on them.

Since Hyprlock already performs the actual unlock via Wayland, calling Unlock() is purely informational and has no functional impact on the unlocking process.

@PaideiaDilemma
Copy link
Collaborator

Can't you just use smth like hyprlock && loginctl unlock-session??

@PaideiaDilemma
Copy link
Collaborator

But i agree that it would be better if hypridle's unlock_cmd just worked...
Do you know any lock screen app that sends Unlock?

@Iamanaws
Copy link
Author

Can't you just use smth like hyprlock && loginctl unlock-session??

Yes, but we should map every hyprlock call or make an alias.

But i agree that it would be better if hypridle's unlock_cmd just worked... Do you know any lock screen app that sends Unlock?

I'm looking into it, there's not much documentation or code about it out there.

I see GDM calls login1.Manager UnlockSession() method that uses Session Unlock. GDM

LockSession() asks the session with the specified ID to activate the screen lock. UnlockSession() asks the session with the specified ID to remove an active screen lock, if there is any. This is implemented by sending out the Lock() and Unlock() signals from the respective session object which session managers are supposed to listen on. org.freedesktop.login1.Manager#Methods

@Iamanaws
Copy link
Author

Iamanaws commented Dec 25, 2024

i3-lock and swaylock lack the functionality.

But I found there's a LockedHint property that is part of the Session too and could be an option.
I like it because it removes the ambiguity of Unlock() signal, but in that case, I will have to make a change to Hypridle to be listening to the LockedHint property, and will have to test how well it works.


Also, I found a comment with an interesting interpretation of the org.freedesktop.login1 documentation and how it could be properly implemented.

compliant implementation

With Gnome-Shell and GDM it would be something like:

  1. Session.Lock() -> Gnome-Shell -> GDM
  2. Session.SetLockedHint(true)
  3. .
    3.1 Session.Unlock -> Gnome-Shell
    3.2 GDM -> Manager.UnlockSession() -> Session.Unlock() -> Gnome-Shell
  4. Session.SetLockedHint(false)

Translated will be similar to this path:

  1. Session.Lock() (loginctl) -> Hypridle -> Hyprlock -> Wayland (ext_session_lock_manager_v1_lock)
  2. hyprlock -> Session.SetLockedHint(true)
  3. hyprlock -> Wayland (ext_session_lock_v1_unlock_and_destroy)
  4. hyprlock -> Session.Unlock()
  5. hyprlock -> Session.SetLockedHint(false)

Another solution would be to have a configuration option for a unlock_cmd in Hyprlock, so we can set
unlock_cmd "loginctl unlock-session" from hyprlock. as discussed on sway issue

@Iamanaws Iamanaws changed the title Add D-Bus unlock functionality Add D-Bus signals to notify session lock and unlock states Dec 26, 2024
@PaideiaDilemma
Copy link
Collaborator

LockedHint sounds like a better solution thanks!

The only thing is that we now would have 2 dbus connection objects for org.freedesktop.login1, when a user enables fingerprint authentication as well.

We should centralize that by implementing a dbus manager class. Idk if you would want to try to do that. If you don't , I think we can do it afterwards.

Also it would be good to add an option to enable/disable this. Enable per default.

@Iamanaws
Copy link
Author

I centralized the dbus connection, could you give it a look please?

src/core/DBusManager.cpp Outdated Show resolved Hide resolved
src/core/DBusManager.hpp Outdated Show resolved Hide resolved
src/core/DBusManager.cpp Outdated Show resolved Hide resolved
@PaideiaDilemma
Copy link
Collaborator

I am still a bit unsure if this is the right solution.

For me it is unclear if it is appropriate to call this method as a session-lock client.
I think it would be more appropriate for the compositor that implements the server side of session-lock to set the locked hint. But hyprland currently doesn't do dbus stuff and i think that is fine. Now if some compositor would implement it, I guess we would not break it, we would just set the hint twice right?.

What i also did not consider initially is that unlock_cmd actually has a proper functionality already, but is easy to be misunderstood. You could for example do

unlock_cmd = pkill -USR1 hyprlock

to have loginctl unlock-session unlock the session properly.
this would not make any sense any more, if unlock_cmd would be triggered by hyprlock!

However signaling lock/unlock is also related to the start before suspend problem that we also have. If we can properly signal lock and unlock, we can solve that by waiting for locked in before_sleep_cmd.

What do you think about just implementing an internal way of signaling lock/unlock to hypridle and use that for two additional triggers in hypridle and to wait for locked when launching hyprlock via before_sleep_cmd.

@Iamanaws
Copy link
Author

Iamanaws commented Jan 8, 2025

For me it is unclear if it is appropriate to call this method as a session-lock client. I think it would be more appropriate for the compositor that implements the server side of session-lock to set the locked hint. But hyprland currently doesn't do dbus stuff and i think that is fine. Now if some compositor would implement it, I guess we would not break it, we would just set the hint twice right?.

Yeah, also though about the compositor handling it at first, but it seems like a simpler solution to just do it here. And yes, I think there should be no problem if it is set twice.

What i also did not consider initially is that unlock_cmd actually has a proper functionality already, but is easy to be misunderstood. You could for example do

unlock_cmd = pkill -USR1 hyprlock

to have loginctl unlock-session unlock the session properly. this would not make any sense any more, if unlock_cmd would be triggered by hyprlock!

That's a bit confusing. unlock_cmd would never be called because no one (hyprlock/hyprland) tells hypridle that it unlocked / not send dbus signal. But yeah, when it does it will be redundant.


What do you think about just implementing an internal way of signaling lock/unlock to hypridle and use that for two additional triggers in hypridle and to wait for locked when launching hyprlock via before_sleep_cmd.

I like the idea of an internal unlock signal. However, I still see value in keeping the D-Bus signals for broader compatibility, but not a big problem.
I think we can maintain Hypridle’s current behavior (listening for unlock signals) while also triggering unlock_cmd upon receiving an internal signal. That signal could originate from Hyprlock, or even better, from Hyprland. This approach would also support other lock screens that don’t use D-Bus. If keeping the D-Bus listener on Hypridle becomes redundant, we can remove it later.

I'm not sure if there's already, and if there is how, a channel used by Hyprland and Hypridle or hypr apps in general to communicate between them, could you point me to? I think there is, just not very familiar with.

@PaideiaDilemma
Copy link
Collaborator

That signal could originate from Hyprlock, or even better, from Hyprland. This approach would also support other lock screens that don’t use D-Bus.

I think that is a really good idea! Have Hyprland signal to hypridle whether we are locked or not.

I'm not sure if there's already, and if there is how, a channel used by Hyprland and Hypridle or hypr apps in general to communicate between them, could you point me to? I think there is, just not very familiar with.

Well the existing channel is wayland. I don't think there is anything else that we could use for that purpose. We would need an internal protocol for that. It could work exactly like the idle-notify protocol. As a wayland client we can request to be notified and then we will receive a locked and unlock from the compositor.
I will ask vaxry what he thinks about that.

@PaideiaDilemma
Copy link
Collaborator

@vaxerski

What do you think about this idea?

We are trying to solve the "lock before suspend problem" as well as giving hyprIDLE the ability to launch commands when we unlock.

swaylock has -R, --ready-fd to script your way out of the suspend problem.
Instead of adding something like that (See #637), we could solve this problem on the compositor level, by adding a hypothetical "hyprland-session-lock-notify" protocol that would work very similar to "ext-idle-notfiy-v1".
Then in hypridle we would be able to receive lock and unlock notifications allowing it to

  1. inihibit sleep via dbus until we are actually locked.
  2. launch a command on unlock.

Copy link
Member

@vaxerski vaxerski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also in dire need of a clang-format


class DBusManager {
public:
static DBusManager& getInstance();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's not how we do singletons in hyprland.

inline std::unique_ptr<CDBusManager> g_pDBusManager;

public:
static DBusManager& getInstance();

std::shared_ptr<sdbus::IConnection> getConnection();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SP?

#include <string>
#include <sdbus-c++/sdbus-c++.h>

class DBusManager {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CDBusManager

const auto fingerprintAuth = g_pAuth->getImpl(AUTH_IMPL_FINGERPRINT);
const auto dbusConn = (fingerprintAuth) ? ((CFingerprint*)fingerprintAuth.get())->getConnection() : nullptr;
if (fingerprintAuth){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no {}

@PaideiaDilemma
Copy link
Collaborator

@Iamanaws vaxry misunderstood me and reviewed the pr instead of the comment, but he has nothing against such a protocol. I will make one in hyprland-protocols and start a hyprland implementation : )

@PaideiaDilemma
Copy link
Collaborator

@Iamanaws I created hyprwm/hyprland-protocols#12 and hyprwm/Hyprland#9092

You wanna do the hypridle impl, or should i?

@Iamanaws
Copy link
Author

@PaideiaDilemma go for it, you're half the way

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants