Skip to content

Commit

Permalink
core: add an option to inhibit sleep until the locked event
Browse files Browse the repository at this point in the history
  • Loading branch information
PaideiaDilemma committed Jan 17, 2025
1 parent 6cd8f36 commit edb9779
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/config/ConfigManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void CConfigManager::init() {
m_config.addConfigValue("general:after_sleep_cmd", Hyprlang::STRING{""});
m_config.addConfigValue("general:ignore_dbus_inhibit", Hyprlang::INT{0});
m_config.addConfigValue("general:ignore_systemd_inhibit", Hyprlang::INT{0});
m_config.addConfigValue("general:inhibit_sleep", Hyprlang::INT{2});

m_config.commence();

Expand Down
107 changes: 95 additions & 12 deletions src/core/Hypridle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,39 @@ void CHypridle::run() {
exit(1);
}

static auto* const PINHIBIT = (Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:inhibit_sleep");
static auto* const PSLEEPCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:before_sleep_cmd");
static auto* const PLOCKCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:lock_cmd");

switch (**PINHIBIT) {
case 0: // disabled
m_inhibitSleepBehavior = SLEEP_INHIBIT_NONE;
break;
case 1: // enabled
m_inhibitSleepBehavior = SLEEP_INHIBIT_NORMAL;
break;
case 2: { // auto (enable, but wait until locked if before_sleep_cmd contains hyprlock, or loginctl lock-session and lock_cmd contains hyprlock.)
if (std::string{*PSLEEPCMD}.contains("hyprlock"))
m_inhibitSleepBehavior = SLEEP_INHIBIT_WAIT_FOR_LOCKED;
else if (std::string{*PLOCKCMD}.contains("hyprlock") && std::string{*PSLEEPCMD}.contains("lock-session"))
m_inhibitSleepBehavior = SLEEP_INHIBIT_WAIT_FOR_LOCKED;
else
m_inhibitSleepBehavior = SLEEP_INHIBIT_NORMAL;
} break;
case 3: // wait until locked
m_inhibitSleepBehavior = SLEEP_INHIBIT_WAIT_FOR_LOCKED;
break;
default: Debug::log(ERR, "Invalid inhibit_sleep value: {}", **PINHIBIT); break;
}

switch (m_inhibitSleepBehavior) {
case SLEEP_INHIBIT_NONE: Debug::log(LOG, "Sleep inhibition disabled"); break;
case SLEEP_INHIBIT_NORMAL: Debug::log(LOG, "Sleep inhibition enabled"); break;
case SLEEP_INHIBIT_WAIT_FOR_LOCKED: Debug::log(LOG, "Sleep inhibition enabled - inhibiting until the wayland session gets locked"); break;
}

setupDBUS();
handleInhibitSleep(false);
enterEventLoop();
}

Expand Down Expand Up @@ -268,6 +300,7 @@ static void spawn(const std::string& args) {
close(socket[0]);
write(socket[1], &grandchild, sizeof(grandchild));
close(socket[1]);
waitpid(grandchild, NULL, 0);
// exit child
_exit(0);
}
Expand Down Expand Up @@ -346,23 +379,22 @@ void CHypridle::onInhibit(bool lock) {
}

void CHypridle::onLocked() {
Debug::log(LOG, "Locked");
Debug::log(LOG, "Wayland session got locked");
m_isLocked = true;

if (const auto* const PLOCKCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:on_lock_cmd"); !PLOCKCMD->empty()) {
Debug::log(LOG, "Running {}", *PLOCKCMD);
if (m_inhibitSleepBehavior == SLEEP_INHIBIT_WAIT_FOR_LOCKED)
uninhibitSleep();

if (const auto* const PLOCKCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:on_lock_cmd"); PLOCKCMD && strlen(*PLOCKCMD) > 0)
spawn(*PLOCKCMD);
}
}

void CHypridle::onUnlocked() {
Debug::log(LOG, "Unlocked");
Debug::log(LOG, "Wayland session got unlocked");
m_isLocked = false;

if (const auto* const PUNLOCKCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:on_unlock_cmd"); !PUNLOCKCMD->empty()) {
Debug::log(LOG, "Running {}", *PUNLOCKCMD);
if (const auto* const PUNLOCKCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:on_unlock_cmd"); PUNLOCKCMD && strlen(*PUNLOCKCMD) > 0)
spawn(*PUNLOCKCMD);
}
}

CHypridle::SDbusInhibitCookie CHypridle::getDbusInhibitCookie(uint32_t cookie) {
Expand Down Expand Up @@ -441,11 +473,14 @@ static void handleDbusSleep(sdbus::Message msg) {

std::string cmd = toSleep ? *PSLEEPCMD : *PAFTERSLEEPCMD;

if (cmd.empty())
return;
if (!toSleep)
g_pHypridle->handleInhibitSleep(toSleep);

if (!cmd.empty())
spawn(cmd);

Debug::log(LOG, "Running: {}", cmd);
spawn(cmd);
if (toSleep)
g_pHypridle->handleInhibitSleep(toSleep);
}

void handleDbusBlockInhibits(const std::string& inhibits) {
Expand Down Expand Up @@ -540,6 +575,7 @@ void CHypridle::setupDBUS() {

m_sDBUSState.connection->addMatch("type='signal',path='" + path + "',interface='org.freedesktop.login1.Session'", ::handleDbusLogin);
m_sDBUSState.connection->addMatch("type='signal',path='/org/freedesktop/login1',interface='org.freedesktop.login1.Manager'", ::handleDbusSleep);
m_sDBUSState.login = sdbus::createProxy(*m_sDBUSState.connection, sdbus::ServiceName{"org.freedesktop.login1"}, sdbus::ObjectPath{"/org/freedesktop/login1"});
} catch (std::exception& e) { Debug::log(WARN, "Couldn't connect to logind service ({})", e.what()); }

Debug::log(LOG, "Using dbus path {}", path.c_str());
Expand Down Expand Up @@ -586,3 +622,50 @@ void CHypridle::setupDBUS() {

systemConnection.reset();
}

void CHypridle::handleInhibitSleep(bool toSleep) {
if (m_inhibitSleepBehavior == SLEEP_INHIBIT_NONE)
return;

if (!toSleep)
inhibitSleep();
else if (m_inhibitSleepBehavior != SLEEP_INHIBIT_WAIT_FOR_LOCKED)
uninhibitSleep();
}

void CHypridle::inhibitSleep() {
auto method = m_sDBUSState.login->createMethodCall(sdbus::InterfaceName{"org.freedesktop.login1.Manager"}, sdbus::MethodName{"Inhibit"});
method << "sleep";
method << "hypridle";
method << "Hypridle wants to delay sleep until it's before_sleep handling is done.";
method << "delay";

try {
auto reply = m_sDBUSState.login->callMethod(method);

if (!reply || !reply.isValid()) {
Debug::log(ERR, "Failed to inhibit sleep");
return;
}

if (reply.isEmpty()) {
Debug::log(ERR, "Failed to inhibit sleep, empty reply");
return;
}

reply >> m_sDBUSState.sleepInhibitFd;
Debug::log(TRACE, "Inhibited sleep with fd {}", m_sDBUSState.sleepInhibitFd.get());
} catch (const std::exception& e) { Debug::log(ERR, "Failed to inhibit sleep ({})", e.what()); }

Debug::log(LOG, "Inhibited sleep!");
}

void CHypridle::uninhibitSleep() {
if (!m_sDBUSState.sleepInhibitFd.isValid()) {
Debug::log(ERR, "No sleep inhibitor fd to release");
return;
}

Debug::log(LOG, "Releasing the sleep inhibitor!");
close(m_sDBUSState.sleepInhibitFd.release());
}
16 changes: 14 additions & 2 deletions src/core/Hypridle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,20 @@ class CHypridle {
void onIdled(SIdleListener*);
void onResumed(SIdleListener*);

void onInhibit(bool lock);

void onLocked();
void onUnlocked();

void onInhibit(bool lock);

SDbusInhibitCookie getDbusInhibitCookie(uint32_t cookie);
void registerDbusInhibitCookie(SDbusInhibitCookie& cookie);
bool unregisterDbusInhibitCookie(const SDbusInhibitCookie& cookie);
bool unregisterDbusInhibitCookies(const std::string& ownerID);

void handleInhibitSleep(bool toSleep);
void inhibitSleep();
void uninhibitSleep();

private:
void setupDBUS();
void enterEventLoop();
Expand All @@ -51,6 +55,12 @@ class CHypridle {
bool m_isLocked = false;
int64_t m_iInhibitLocks = 0;

enum {
SLEEP_INHIBIT_NONE,
SLEEP_INHIBIT_NORMAL,
SLEEP_INHIBIT_WAIT_FOR_LOCKED,
} m_inhibitSleepBehavior;

struct {
wl_display* display = nullptr;
wl_registry* registry = nullptr;
Expand All @@ -68,8 +78,10 @@ class CHypridle {
struct {
std::unique_ptr<sdbus::IConnection> connection;
std::unique_ptr<sdbus::IConnection> screenSaverServiceConnection;
std::unique_ptr<sdbus::IProxy> login;
std::vector<std::unique_ptr<sdbus::IObject>> screenSaverObjects;
std::vector<SDbusInhibitCookie> inhibitCookies;
sdbus::UnixFd sleepInhibitFd;
} m_sDBUSState;

struct {
Expand Down

0 comments on commit edb9779

Please sign in to comment.