mirror of
https://github.com/hyprwm/hypridle.git
synced 2025-05-12 13:10:39 +01:00
core: implement hyprlock-lock-notify-v1 functionality (#122)
--------- Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
parent
33ac8cae64
commit
15ca902b2c
12 changed files with 338 additions and 133 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -1,3 +1,7 @@
|
|||
.vscode/
|
||||
build/
|
||||
protocols/
|
||||
protocols/
|
||||
.clangd/
|
||||
.direnv/
|
||||
.cache/
|
||||
compile_commands.json
|
||||
|
|
|
@ -35,13 +35,14 @@ message(STATUS "Checking deps...")
|
|||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(hyprwayland-scanner 0.4.4 REQUIRED)
|
||||
pkg_check_modules(
|
||||
deps
|
||||
REQUIRED
|
||||
IMPORTED_TARGET
|
||||
wayland-client
|
||||
wayland-protocols
|
||||
hyprlang>=0.4.0
|
||||
hyprlang>=0.6.0
|
||||
hyprutils>=0.2.0
|
||||
sdbus-c++>=0.2.0)
|
||||
|
||||
|
@ -50,45 +51,47 @@ add_executable(hypridle ${SRCFILES})
|
|||
target_link_libraries(hypridle PRIVATE rt Threads::Threads PkgConfig::deps)
|
||||
|
||||
# protocols
|
||||
find_program(WaylandScanner NAMES wayland-scanner)
|
||||
message(STATUS "Found WaylandScanner at ${WaylandScanner}")
|
||||
execute_process(
|
||||
COMMAND pkg-config --variable=pkgdatadir wayland-protocols
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE WAYLAND_PROTOCOLS_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||
message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
|
||||
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
|
||||
message(STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}")
|
||||
|
||||
function(protocol protoPath protoName external)
|
||||
pkg_check_modules(hyprland_protocols_dep REQUIRED IMPORTED_TARGET hyprland-protocols>=0.6.0)
|
||||
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
|
||||
message(STATUS "Found hyprland-protocols at ${HYPRLAND_PROTOCOLS}")
|
||||
|
||||
function(protocolnew protoPath protoName external)
|
||||
if(external)
|
||||
execute_process(
|
||||
COMMAND ${WaylandScanner} client-header ${protoPath}
|
||||
protocols/${protoName}-protocol.h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
execute_process(
|
||||
COMMAND ${WaylandScanner} private-code ${protoPath}
|
||||
protocols/${protoName}-protocol.c
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(hypridle PRIVATE protocols/${protoName}-protocol.c)
|
||||
set(path ${protoPath})
|
||||
else()
|
||||
execute_process(
|
||||
COMMAND
|
||||
${WaylandScanner} client-header ${WAYLAND_PROTOCOLS_DIR}/${protoPath}
|
||||
protocols/${protoName}-protocol.h
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
execute_process(
|
||||
COMMAND
|
||||
${WaylandScanner} private-code ${WAYLAND_PROTOCOLS_DIR}/${protoPath}
|
||||
protocols/${protoName}-protocol.c
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(hypridle PRIVATE protocols/${protoName}-protocol.c)
|
||||
set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
|
||||
endif()
|
||||
message(STATUS "Full proto path: ${path}")
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
|
||||
COMMAND hyprwayland-scanner --client ${path}/${protoName}.xml
|
||||
${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(hypridle PRIVATE protocols/${protoName}.cpp
|
||||
protocols/${protoName}.hpp)
|
||||
endfunction()
|
||||
function(protocolWayland)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
||||
COMMAND hyprwayland-scanner --wayland-enums --client
|
||||
${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
target_sources(hypridle PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
|
||||
endfunction()
|
||||
|
||||
make_directory(${CMAKE_SOURCE_DIR}/protocols) # we don't ship any custom ones so
|
||||
# the dir won't be there
|
||||
protocol("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1"
|
||||
false)
|
||||
|
||||
protocolwayland()
|
||||
|
||||
protocolnew("staging/ext-idle-notify" "ext-idle-notify-v1" false)
|
||||
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true)
|
||||
|
||||
# Installation
|
||||
install(TARGETS hypridle)
|
||||
|
|
|
@ -36,6 +36,7 @@ will make those events ignored.
|
|||
- wayland-protocols
|
||||
- hyprlang >= 0.4.0
|
||||
- sdbus-c++
|
||||
- hyprwayland-scanner
|
||||
|
||||
## Building & Installation
|
||||
|
||||
|
|
50
flake.lock
50
flake.lock
|
@ -1,5 +1,28 @@
|
|||
{
|
||||
"nodes": {
|
||||
"hyprland-protocols": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1737556638,
|
||||
"narHash": "sha256-laKgI3mr2qz6tas/q3tuGPxMdsGhBi/w+HO+hO2f1AY=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"rev": "4c75dd5c015c8a0e5a34c6d02a018a650f57feb5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprland-protocols",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprlang": {
|
||||
"inputs": {
|
||||
"hyprutils": [
|
||||
|
@ -13,6 +36,8 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1734364628,
|
||||
"narHash": "sha256-ii8fzJfI953n/EmIxVvq64ZAwhvwuuPHWfGd61/mJG8=",
|
||||
"lastModified": 1737634606,
|
||||
"narHash": "sha256-W7W87Cv6wqZ9PHegI6rH1+ve3zJPiyevMFf0/HwdbCQ=",
|
||||
"owner": "hyprwm",
|
||||
|
@ -49,6 +74,29 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"hyprwayland-scanner": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1735493474,
|
||||
"narHash": "sha256-fktzv4NaqKm94VAkAoVqO/nqQlw+X0/tJJNAeCSfzK4=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"rev": "de913476b59ee88685fdc018e77b8f6637a2ae0b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprwayland-scanner",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1737469691,
|
||||
|
@ -67,8 +115,10 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"hyprland-protocols": "hyprland-protocols",
|
||||
"hyprlang": "hyprlang",
|
||||
"hyprutils": "hyprutils",
|
||||
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
}
|
||||
|
|
12
flake.nix
12
flake.nix
|
@ -17,6 +17,18 @@
|
|||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprland-protocols = {
|
||||
url = "github:hyprwm/hyprland-protocols";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
|
||||
hyprwayland-scanner = {
|
||||
url = "github:hyprwm/hyprwayland-scanner";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
};
|
||||
|
||||
outputs = {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
{
|
||||
lib,
|
||||
stdenv,
|
||||
cmake,
|
||||
pkg-config,
|
||||
hyprland-protocols,
|
||||
hyprlang,
|
||||
hyprutils,
|
||||
hyprwayland-scanner,
|
||||
lib,
|
||||
pkg-config,
|
||||
sdbus-cpp,
|
||||
stdenv,
|
||||
systemd,
|
||||
wayland,
|
||||
wayland-protocols,
|
||||
|
@ -19,11 +21,13 @@ stdenv.mkDerivation {
|
|||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
hyprwayland-scanner
|
||||
pkg-config
|
||||
wayland-scanner
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
hyprland-protocols
|
||||
hyprlang
|
||||
hyprutils
|
||||
sdbus-cpp
|
||||
|
|
|
@ -13,8 +13,10 @@ in {
|
|||
default = inputs.self.overlays.hypridle;
|
||||
|
||||
hypridle = lib.composeManyExtensions [
|
||||
inputs.hyprland-protocols.overlays.default
|
||||
inputs.hyprlang.overlays.default
|
||||
inputs.hyprutils.overlays.default
|
||||
inputs.hyprwayland-scanner.overlays.default
|
||||
inputs.self.overlays.sdbuscpp
|
||||
(final: prev: {
|
||||
hypridle = prev.callPackage ./default.nix {
|
||||
|
|
|
@ -23,10 +23,13 @@ void CConfigManager::init() {
|
|||
|
||||
m_config.addConfigValue("general:lock_cmd", Hyprlang::STRING{""});
|
||||
m_config.addConfigValue("general:unlock_cmd", Hyprlang::STRING{""});
|
||||
m_config.addConfigValue("general:on_lock_cmd", Hyprlang::STRING{""});
|
||||
m_config.addConfigValue("general:on_unlock_cmd", Hyprlang::STRING{""});
|
||||
m_config.addConfigValue("general:before_sleep_cmd", Hyprlang::STRING{""});
|
||||
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();
|
||||
|
||||
|
@ -77,11 +80,3 @@ Hyprlang::CParseResult CConfigManager::postParse() {
|
|||
std::vector<CConfigManager::STimeoutRule> CConfigManager::getRules() {
|
||||
return m_vRules;
|
||||
}
|
||||
|
||||
std::string CConfigManager::getOnTimeoutCommand() {
|
||||
return m_vRules.front().onTimeout;
|
||||
}
|
||||
|
||||
void* const* CConfigManager::getValuePtr(const std::string& name) {
|
||||
return m_config.getConfigValuePtr(name.c_str())->getDataStaticPtr();
|
||||
}
|
||||
|
|
|
@ -18,9 +18,12 @@ class CConfigManager {
|
|||
std::string onResume = "";
|
||||
};
|
||||
|
||||
std::string getOnTimeoutCommand();
|
||||
std::vector<STimeoutRule> getRules();
|
||||
void* const* getValuePtr(const std::string& name);
|
||||
|
||||
template <typename T>
|
||||
Hyprlang::CSimpleConfigValue<T> getValue(const std::string& name) {
|
||||
return Hyprlang::CSimpleConfigValue<T>(&m_config, name.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
Hyprlang::CConfig m_config;
|
||||
|
|
|
@ -18,36 +18,32 @@ CHypridle::CHypridle() {
|
|||
}
|
||||
}
|
||||
|
||||
void handleGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
|
||||
g_pHypridle->onGlobal(data, registry, name, interface, version);
|
||||
}
|
||||
|
||||
void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name) {
|
||||
g_pHypridle->onGlobalRemoved(data, registry, name);
|
||||
}
|
||||
|
||||
inline const wl_registry_listener registryListener = {
|
||||
.global = handleGlobal,
|
||||
.global_remove = handleGlobalRemove,
|
||||
};
|
||||
|
||||
void handleIdled(void* data, ext_idle_notification_v1* ext_idle_notification_v1) {
|
||||
g_pHypridle->onIdled((CHypridle::SIdleListener*)data);
|
||||
}
|
||||
|
||||
void handleResumed(void* data, ext_idle_notification_v1* ext_idle_notification_v1) {
|
||||
g_pHypridle->onResumed((CHypridle::SIdleListener*)data);
|
||||
}
|
||||
|
||||
inline const ext_idle_notification_v1_listener idleListener = {
|
||||
.idled = handleIdled,
|
||||
.resumed = handleResumed,
|
||||
};
|
||||
|
||||
void CHypridle::run() {
|
||||
m_sWaylandState.registry = wl_display_get_registry(m_sWaylandState.display);
|
||||
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;
|
||||
Debug::log(LOG, " | got iface: {} v{}", IFACE, version);
|
||||
|
||||
wl_registry_add_listener(m_sWaylandState.registry, ®istryListener, nullptr);
|
||||
if (IFACE == ext_idle_notifier_v1_interface.name) {
|
||||
m_sWaylandIdleState.notifier =
|
||||
makeShared<CCExtIdleNotifierV1>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &ext_idle_notifier_v1_interface, version));
|
||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||
} else if (IFACE == hyprland_lock_notifier_v1_interface.name) {
|
||||
m_sWaylandState.lockNotifier =
|
||||
makeShared<CCHyprlandLockNotifierV1>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &hyprland_lock_notifier_v1_interface, version));
|
||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||
} else if (IFACE == wl_seat_interface.name) {
|
||||
if (m_sWaylandState.seat) {
|
||||
Debug::log(WARN, "Hypridle does not support multi-seat configurations. Only binding to the first seat.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_sWaylandState.seat = makeShared<CCWlSeat>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &wl_seat_interface, version));
|
||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||
}
|
||||
});
|
||||
|
||||
m_sWaylandState.registry->setGlobalRemove([](CCWlRegistry* r, uint32_t name) { Debug::log(LOG, " | removed iface {}", name); });
|
||||
|
||||
wl_display_roundtrip(m_sWaylandState.display);
|
||||
|
||||
|
@ -62,17 +58,26 @@ void CHypridle::run() {
|
|||
Debug::log(LOG, "found {} rules", RULES.size());
|
||||
|
||||
for (size_t i = 0; i < RULES.size(); ++i) {
|
||||
auto& l = m_sWaylandIdleState.listeners[i];
|
||||
const auto& r = RULES[i];
|
||||
l.notification = ext_idle_notifier_v1_get_idle_notification(m_sWaylandIdleState.notifier, r.timeout * 1000 /* ms */, m_sWaylandState.seat);
|
||||
l.onRestore = r.onResume;
|
||||
l.onTimeout = r.onTimeout;
|
||||
auto& l = m_sWaylandIdleState.listeners[i];
|
||||
const auto& r = RULES[i];
|
||||
l.onRestore = r.onResume;
|
||||
l.onTimeout = r.onTimeout;
|
||||
|
||||
ext_idle_notification_v1_add_listener(l.notification, &idleListener, &l);
|
||||
l.notification = makeShared<CCExtIdleNotificationV1>(m_sWaylandIdleState.notifier->sendGetIdleNotification(r.timeout * 1000 /* ms */, m_sWaylandState.seat->resource()));
|
||||
l.notification->setData(&m_sWaylandIdleState.listeners[i]);
|
||||
|
||||
l.notification->setIdled([this](CCExtIdleNotificationV1* n) { onIdled((CHypridle::SIdleListener*)n->data()); });
|
||||
l.notification->setResumed([this](CCExtIdleNotificationV1* n) { onResumed((CHypridle::SIdleListener*)n->data()); });
|
||||
}
|
||||
|
||||
wl_display_roundtrip(m_sWaylandState.display);
|
||||
|
||||
if (m_sWaylandState.lockNotifier) {
|
||||
m_sWaylandState.lockNotification = makeShared<CCHyprlandLockNotificationV1>(m_sWaylandState.lockNotifier->sendGetLockNotification());
|
||||
m_sWaylandState.lockNotification->setLocked([this](CCHyprlandLockNotificationV1* n) { onLocked(); });
|
||||
m_sWaylandState.lockNotification->setUnlocked([this](CCHyprlandLockNotificationV1* n) { onUnlocked(); });
|
||||
}
|
||||
|
||||
Debug::log(LOG, "wayland done, registering dbus");
|
||||
|
||||
try {
|
||||
|
@ -82,7 +87,46 @@ void CHypridle::run() {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
if (!m_sWaylandState.lockNotifier)
|
||||
Debug::log(WARN,
|
||||
"Compositor is missing hyprland-lock-notify-v1!\n"
|
||||
"general:inhibit_sleep=3, general:on_lock_cmd and general:on_unlock_cmd will not work.");
|
||||
|
||||
static const auto INHIBIT = g_pConfigManager->getValue<Hyprlang::INT>("general:inhibit_sleep");
|
||||
static const auto SLEEPCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:before_sleep_cmd");
|
||||
static const auto LOCKCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:lock_cmd");
|
||||
|
||||
switch (*INHIBIT) {
|
||||
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 (m_sWaylandState.lockNotifier && std::string{*SLEEPCMD}.contains("hyprlock"))
|
||||
m_inhibitSleepBehavior = SLEEP_INHIBIT_LOCK_NOTIFY;
|
||||
else if (m_sWaylandState.lockNotifier && std::string{*LOCKCMD}.contains("hyprlock") && std::string{*SLEEPCMD}.contains("lock-session"))
|
||||
m_inhibitSleepBehavior = SLEEP_INHIBIT_LOCK_NOTIFY;
|
||||
else
|
||||
m_inhibitSleepBehavior = SLEEP_INHIBIT_NORMAL;
|
||||
} break;
|
||||
case 3: // wait until locked
|
||||
if (m_sWaylandState.lockNotifier)
|
||||
m_inhibitSleepBehavior = SLEEP_INHIBIT_LOCK_NOTIFY;
|
||||
break;
|
||||
default: Debug::log(ERR, "Invalid inhibit_sleep value: {}", *INHIBIT); 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_LOCK_NOTIFY: Debug::log(LOG, "Sleep inhibition enabled - inhibiting until the wayland session gets locked"); break;
|
||||
}
|
||||
|
||||
setupDBUS();
|
||||
if (m_inhibitSleepBehavior != SLEEP_INHIBIT_NONE)
|
||||
inhibitSleep();
|
||||
enterEventLoop();
|
||||
}
|
||||
|
||||
|
@ -187,28 +231,6 @@ void CHypridle::enterEventLoop() {
|
|||
Debug::log(ERR, "[core] Terminated");
|
||||
}
|
||||
|
||||
void CHypridle::onGlobal(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
|
||||
const std::string IFACE = interface;
|
||||
Debug::log(LOG, " | got iface: {} v{}", IFACE, version);
|
||||
|
||||
if (IFACE == ext_idle_notifier_v1_interface.name) {
|
||||
m_sWaylandIdleState.notifier = (ext_idle_notifier_v1*)wl_registry_bind(registry, name, &ext_idle_notifier_v1_interface, version);
|
||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||
} else if (IFACE == wl_seat_interface.name) {
|
||||
if (m_sWaylandState.seat) {
|
||||
Debug::log(WARN, "Hypridle does not support multi-seat configurations. Only binding to the first seat.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_sWaylandState.seat = (wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, version);
|
||||
Debug::log(LOG, " > Bound to {} v{}", IFACE, version);
|
||||
}
|
||||
}
|
||||
|
||||
void CHypridle::onGlobalRemoved(void* data, struct wl_registry* registry, uint32_t name) {
|
||||
;
|
||||
}
|
||||
|
||||
static void spawn(const std::string& args) {
|
||||
Debug::log(LOG, "Executing {}", args);
|
||||
|
||||
|
@ -310,17 +332,44 @@ void CHypridle::onInhibit(bool lock) {
|
|||
auto& l = m_sWaylandIdleState.listeners[i];
|
||||
const auto& r = RULES[i];
|
||||
|
||||
ext_idle_notification_v1_destroy(l.notification);
|
||||
l.notification->sendDestroy();
|
||||
|
||||
l.notification = ext_idle_notifier_v1_get_idle_notification(m_sWaylandIdleState.notifier, r.timeout * 1000 /* ms */, m_sWaylandState.seat);
|
||||
l.notification =
|
||||
makeShared<CCExtIdleNotificationV1>(m_sWaylandIdleState.notifier->sendGetIdleNotification(r.timeout * 1000 /* ms */, m_sWaylandState.seat->resource()));
|
||||
l.notification->setData(&m_sWaylandIdleState.listeners[i]);
|
||||
|
||||
ext_idle_notification_v1_add_listener(l.notification, &idleListener, &l);
|
||||
l.notification->setIdled([this](CCExtIdleNotificationV1* n) { onIdled((CHypridle::SIdleListener*)n->data()); });
|
||||
l.notification->setResumed([this](CCExtIdleNotificationV1* n) { onResumed((CHypridle::SIdleListener*)n->data()); });
|
||||
}
|
||||
}
|
||||
|
||||
Debug::log(LOG, "Inhibit locks: {}", m_iInhibitLocks);
|
||||
}
|
||||
|
||||
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 (*LOCKCMD)
|
||||
spawn(*LOCKCMD);
|
||||
|
||||
if (m_inhibitSleepBehavior == SLEEP_INHIBIT_LOCK_NOTIFY)
|
||||
uninhibitSleep();
|
||||
}
|
||||
|
||||
void CHypridle::onUnlocked() {
|
||||
Debug::log(LOG, "Wayland session got unlocked");
|
||||
m_isLocked = false;
|
||||
|
||||
if (m_inhibitSleepBehavior == SLEEP_INHIBIT_LOCK_NOTIFY)
|
||||
inhibitSleep();
|
||||
|
||||
static const auto UNLOCKCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:on_unlock_cmd");
|
||||
if (*UNLOCKCMD)
|
||||
spawn(*UNLOCKCMD);
|
||||
}
|
||||
|
||||
CHypridle::SDbusInhibitCookie CHypridle::getDbusInhibitCookie(uint32_t cookie) {
|
||||
for (auto& c : m_sDBUSState.inhibitCookies) {
|
||||
if (c.cookie == cookie)
|
||||
|
@ -358,8 +407,8 @@ bool CHypridle::unregisterDbusInhibitCookies(const std::string& ownerID) {
|
|||
|
||||
static void handleDbusLogin(sdbus::Message msg) {
|
||||
// lock & unlock
|
||||
static auto* const PLOCKCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:lock_cmd");
|
||||
static auto* const PUNLOCKCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:unlock_cmd");
|
||||
static const auto LOCKCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:lock_cmd");
|
||||
static const auto UNLOCKCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:unlock_cmd");
|
||||
|
||||
Debug::log(LOG, "Got dbus .Session");
|
||||
|
||||
|
@ -367,16 +416,16 @@ static void handleDbusLogin(sdbus::Message msg) {
|
|||
if (MEMBER == "Lock") {
|
||||
Debug::log(LOG, "Got Lock from dbus");
|
||||
|
||||
if (!std::string{*PLOCKCMD}.empty()) {
|
||||
Debug::log(LOG, "Locking with {}", *PLOCKCMD);
|
||||
spawn(*PLOCKCMD);
|
||||
if (!std::string{*LOCKCMD}.empty()) {
|
||||
Debug::log(LOG, "Locking with {}", *LOCKCMD);
|
||||
spawn(*LOCKCMD);
|
||||
}
|
||||
} else if (MEMBER == "Unlock") {
|
||||
Debug::log(LOG, "Got Unlock from dbus");
|
||||
|
||||
if (!std::string{*PUNLOCKCMD}.empty()) {
|
||||
Debug::log(LOG, "Locking with {}", *PUNLOCKCMD);
|
||||
spawn(*PUNLOCKCMD);
|
||||
if (!std::string{*UNLOCKCMD}.empty()) {
|
||||
Debug::log(LOG, "Locking with {}", *UNLOCKCMD);
|
||||
spawn(*UNLOCKCMD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -390,18 +439,21 @@ static void handleDbusSleep(sdbus::Message msg) {
|
|||
bool toSleep = true;
|
||||
msg >> toSleep;
|
||||
|
||||
static auto* const PSLEEPCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:before_sleep_cmd");
|
||||
static auto* const PAFTERSLEEPCMD = (Hyprlang::STRING const*)g_pConfigManager->getValuePtr("general:after_sleep_cmd");
|
||||
static const auto SLEEPCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:before_sleep_cmd");
|
||||
static const auto AFTERSLEEPCMD = g_pConfigManager->getValue<Hyprlang::STRING>("general:after_sleep_cmd");
|
||||
|
||||
Debug::log(LOG, "Got PrepareForSleep from dbus with sleep {}", toSleep);
|
||||
|
||||
std::string cmd = toSleep ? *PSLEEPCMD : *PAFTERSLEEPCMD;
|
||||
std::string cmd = toSleep ? *SLEEPCMD : *AFTERSLEEPCMD;
|
||||
|
||||
if (cmd.empty())
|
||||
return;
|
||||
if (!toSleep)
|
||||
g_pHypridle->handleInhibitOnDbusSleep(toSleep);
|
||||
|
||||
Debug::log(LOG, "Running: {}", cmd);
|
||||
spawn(cmd);
|
||||
if (!cmd.empty())
|
||||
spawn(cmd);
|
||||
|
||||
if (toSleep)
|
||||
g_pHypridle->handleInhibitOnDbusSleep(toSleep);
|
||||
}
|
||||
|
||||
void handleDbusBlockInhibits(const std::string& inhibits) {
|
||||
|
@ -484,8 +536,8 @@ static void handleDbusNameOwnerChanged(sdbus::Message msg) {
|
|||
}
|
||||
|
||||
void CHypridle::setupDBUS() {
|
||||
static auto const IGNORE_DBUS_INHIBIT = **(Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:ignore_dbus_inhibit");
|
||||
static auto const IGNORE_SYSTEMD_INHIBIT = **(Hyprlang::INT* const*)g_pConfigManager->getValuePtr("general:ignore_systemd_inhibit");
|
||||
static const auto IGNOREDBUSINHIBIT = g_pConfigManager->getValue<Hyprlang::INT>("general:ignore_dbus_inhibit");
|
||||
static const auto IGNORESYSTEMDINHIBIT = g_pConfigManager->getValue<Hyprlang::INT>("general:ignore_systemd_inhibit");
|
||||
|
||||
auto systemConnection = sdbus::createSystemBusConnection();
|
||||
auto proxy = sdbus::createProxy(*systemConnection, sdbus::ServiceName{"org.freedesktop.login1"}, sdbus::ObjectPath{"/org/freedesktop/login1"});
|
||||
|
@ -496,11 +548,12 @@ 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());
|
||||
|
||||
if (!IGNORE_SYSTEMD_INHIBIT) {
|
||||
if (!*IGNORESYSTEMDINHIBIT) {
|
||||
m_sDBUSState.connection->addMatch("type='signal',path='/org/freedesktop/login1',interface='org.freedesktop.DBus.Properties'", ::handleDbusBlockInhibitsPropertyChanged);
|
||||
|
||||
try {
|
||||
|
@ -509,7 +562,7 @@ void CHypridle::setupDBUS() {
|
|||
} catch (std::exception& e) { Debug::log(WARN, "Couldn't retrieve current systemd inhibits ({})", e.what()); }
|
||||
}
|
||||
|
||||
if (!IGNORE_DBUS_INHIBIT) {
|
||||
if (!*IGNOREDBUSINHIBIT) {
|
||||
// attempt to register as ScreenSaver
|
||||
std::string paths[] = {
|
||||
"/org/freedesktop/ScreenSaver",
|
||||
|
@ -542,3 +595,52 @@ void CHypridle::setupDBUS() {
|
|||
|
||||
systemConnection.reset();
|
||||
}
|
||||
|
||||
void CHypridle::handleInhibitOnDbusSleep(bool toSleep) {
|
||||
if (m_inhibitSleepBehavior == SLEEP_INHIBIT_NONE || //
|
||||
m_inhibitSleepBehavior == SLEEP_INHIBIT_LOCK_NOTIFY // Sleep inhibition handled via onLocked/onUnlocked
|
||||
)
|
||||
return;
|
||||
|
||||
if (!toSleep)
|
||||
inhibitSleep();
|
||||
else
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -2,20 +2,23 @@
|
|||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <wayland-client.h>
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "ext-idle-notify-v1-protocol.h"
|
||||
#include "wayland.hpp"
|
||||
#include "ext-idle-notify-v1.hpp"
|
||||
#include "hyprland-lock-notify-v1.hpp"
|
||||
|
||||
#include "../defines.hpp"
|
||||
|
||||
class CHypridle {
|
||||
public:
|
||||
CHypridle();
|
||||
|
||||
struct SIdleListener {
|
||||
ext_idle_notification_v1* notification = nullptr;
|
||||
std::string onTimeout = "";
|
||||
std::string onRestore = "";
|
||||
SP<CCExtIdleNotificationV1> notification = nullptr;
|
||||
std::string onTimeout = "";
|
||||
std::string onRestore = "";
|
||||
};
|
||||
|
||||
struct SDbusInhibitCookie {
|
||||
|
@ -33,27 +36,43 @@ class CHypridle {
|
|||
|
||||
void onInhibit(bool lock);
|
||||
|
||||
void onLocked();
|
||||
void onUnlocked();
|
||||
|
||||
SDbusInhibitCookie getDbusInhibitCookie(uint32_t cookie);
|
||||
void registerDbusInhibitCookie(SDbusInhibitCookie& cookie);
|
||||
bool unregisterDbusInhibitCookie(const SDbusInhibitCookie& cookie);
|
||||
bool unregisterDbusInhibitCookies(const std::string& ownerID);
|
||||
|
||||
void handleInhibitOnDbusSleep(bool toSleep);
|
||||
void inhibitSleep();
|
||||
void uninhibitSleep();
|
||||
|
||||
private:
|
||||
void setupDBUS();
|
||||
void enterEventLoop();
|
||||
|
||||
bool m_bTerminate = false;
|
||||
bool isIdled = false;
|
||||
bool m_isLocked = false;
|
||||
int64_t m_iInhibitLocks = 0;
|
||||
|
||||
enum {
|
||||
SLEEP_INHIBIT_NONE,
|
||||
SLEEP_INHIBIT_NORMAL,
|
||||
SLEEP_INHIBIT_LOCK_NOTIFY,
|
||||
} m_inhibitSleepBehavior;
|
||||
|
||||
struct {
|
||||
wl_display* display = nullptr;
|
||||
wl_registry* registry = nullptr;
|
||||
wl_seat* seat = nullptr;
|
||||
wl_display* display = nullptr;
|
||||
SP<CCWlRegistry> registry = nullptr;
|
||||
SP<CCWlSeat> seat = nullptr;
|
||||
SP<CCHyprlandLockNotifierV1> lockNotifier = nullptr;
|
||||
SP<CCHyprlandLockNotificationV1> lockNotification = nullptr;
|
||||
} m_sWaylandState;
|
||||
|
||||
struct {
|
||||
ext_idle_notifier_v1* notifier = nullptr;
|
||||
SP<CCExtIdleNotifierV1> notifier = nullptr;
|
||||
|
||||
std::vector<SIdleListener> listeners;
|
||||
} m_sWaylandIdleState;
|
||||
|
@ -61,8 +80,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 {
|
||||
|
|
8
src/defines.hpp
Normal file
8
src/defines.hpp
Normal file
|
@ -0,0 +1,8 @@
|
|||
#include "wayland.hpp"
|
||||
#include "ext-idle-notify-v1.hpp"
|
||||
#include "hyprland-lock-notify-v1.hpp"
|
||||
|
||||
#include <hyprutils/memory/WeakPtr.hpp>
|
||||
using namespace Hyprutils::Memory;
|
||||
#define SP CSharedPointer
|
||||
#define WP CWeakPointer
|
Loading…
Reference in a new issue