Added signal support and wait-for-activity bool.

This commit is contained in:
guttermonk
2025-10-17 18:11:50 -05:00
parent d45ce841e3
commit c831a352f2
3 changed files with 167 additions and 17 deletions
+10
View File
@@ -10,21 +10,31 @@ namespace waybar::modules {
class IdleInhibitor : public ALabel { class IdleInhibitor : public ALabel {
sigc::connection timeout_; sigc::connection timeout_;
sigc::connection activity_timeout_;
sigc::connection motion_connection_;
sigc::connection key_connection_;
public: public:
IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&); IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~IdleInhibitor(); virtual ~IdleInhibitor();
auto update() -> void override; auto update() -> void override;
auto refresh(int) -> void override;
static std::list<waybar::AModule*> modules; static std::list<waybar::AModule*> modules;
static bool status; static bool status;
private: private:
bool handleToggle(GdkEventButton* const& e) override; bool handleToggle(GdkEventButton* const& e) override;
bool handleMotion(GdkEventMotion* const& e);
bool handleKey(GdkEventKey* const& e);
void toggleStatus(); void toggleStatus();
void resetActivityTimeout();
void setupActivityMonitoring();
void teardownActivityMonitoring();
const Bar& bar_; const Bar& bar_;
struct zwp_idle_inhibitor_v1* idle_inhibitor_; struct zwp_idle_inhibitor_v1* idle_inhibitor_;
int pid_; int pid_;
bool wait_for_activity_;
}; };
} // namespace waybar::modules } // namespace waybar::modules
+42 -2
View File
@@ -76,6 +76,17 @@ screensaver, also known as "presentation mode".
typeof: double ++ typeof: double ++
The number of minutes the inhibition should last. The number of minutes the inhibition should last.
*wait-for-activity*: ++
typeof: bool ++
default: *false* ++
When enabled, the idle inhibitor remains active as long as there is keyboard or mouse activity on the bar. If there is no activity for the duration specified in *timeout*, the inhibitor will automatically toggle off. This option requires *timeout* to be set.
*signal*: ++
typeof: integer ++
The signal number used to toggle the idle inhibitor externally. ++
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*. ++
Use `pkill -SIGRTMIN+N waybar` to toggle the idle inhibitor from scripts or keybindings.
*tooltip*: ++ *tooltip*: ++
typeof: bool ++ typeof: bool ++
default: true ++ default: true ++
@@ -115,17 +126,46 @@ screensaver, also known as "presentation mode".
# EXAMPLES # EXAMPLES
Basic usage with timeout:
``` ```
"idle_inhibitor": { "idle_inhibitor": {
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"activated": "", "activated": "",
"deactivated": "" "deactivated": ""
}, },
"timeout": 30.5 "timeout": 30.5
} }
``` ```
With external control via signals (can be toggled with `pkill -SIGRTMIN+8 waybar`):
```
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
},
"signal": 8
}
```
With wait-for-activity feature:
```
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
},
"timeout": 5.0,
"wait-for-activity": true
}
```
# STYLE # STYLE
- *#idle_inhibitor* - *#idle_inhibitor*
+101 -1
View File
@@ -11,11 +11,17 @@ waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar&
: ALabel(config, "idle_inhibitor", id, "{status}", 0, false, true), : ALabel(config, "idle_inhibitor", id, "{status}", 0, false, true),
bar_(bar), bar_(bar),
idle_inhibitor_(nullptr), idle_inhibitor_(nullptr),
pid_(-1) { pid_(-1),
wait_for_activity_(false) {
if (waybar::Client::inst()->idle_inhibit_manager == nullptr) { if (waybar::Client::inst()->idle_inhibit_manager == nullptr) {
throw std::runtime_error("idle-inhibit not available"); throw std::runtime_error("idle-inhibit not available");
} }
// Read the wait-for-activity config option
if (config_["wait-for-activity"].isBool()) {
wait_for_activity_ = config_["wait-for-activity"].asBool();
}
if (waybar::modules::IdleInhibitor::modules.empty() && config_["start-activated"].isBool() && if (waybar::modules::IdleInhibitor::modules.empty() && config_["start-activated"].isBool() &&
config_["start-activated"].asBool() != status) { config_["start-activated"].asBool() != status) {
toggleStatus(); toggleStatus();
@@ -32,6 +38,8 @@ waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar&
} }
waybar::modules::IdleInhibitor::~IdleInhibitor() { waybar::modules::IdleInhibitor::~IdleInhibitor() {
teardownActivityMonitoring();
if (idle_inhibitor_ != nullptr) { if (idle_inhibitor_ != nullptr) {
zwp_idle_inhibitor_v1_destroy(idle_inhibitor_); zwp_idle_inhibitor_v1_destroy(idle_inhibitor_);
idle_inhibitor_ = nullptr; idle_inhibitor_ = nullptr;
@@ -77,6 +85,17 @@ auto waybar::modules::IdleInhibitor::update() -> void {
ALabel::update(); ALabel::update();
} }
auto waybar::modules::IdleInhibitor::refresh(int sig) -> void {
if (config_["signal"].isInt() && sig == SIGRTMIN + config_["signal"].asInt()) {
toggleStatus();
// Make all other idle inhibitor modules update
for (auto const& module : waybar::modules::IdleInhibitor::modules) {
module->update();
}
}
}
void waybar::modules::IdleInhibitor::toggleStatus() { void waybar::modules::IdleInhibitor::toggleStatus() {
status = !status; status = !status;
@@ -89,6 +108,12 @@ void waybar::modules::IdleInhibitor::toggleStatus() {
auto timeoutMins = config_["timeout"].asDouble(); auto timeoutMins = config_["timeout"].asDouble();
int timeoutSecs = timeoutMins * 60; int timeoutSecs = timeoutMins * 60;
// If wait-for-activity is enabled, set up activity monitoring
if (wait_for_activity_) {
setupActivityMonitoring();
resetActivityTimeout();
} else {
// Original behavior: simple timeout
timeout_ = Glib::signal_timeout().connect_seconds( timeout_ = Glib::signal_timeout().connect_seconds(
[]() { []() {
/* intentionally not tied to a module instance lifetime /* intentionally not tied to a module instance lifetime
@@ -104,6 +129,10 @@ void waybar::modules::IdleInhibitor::toggleStatus() {
}, },
timeoutSecs); timeoutSecs);
} }
} else {
// When deactivated, tear down activity monitoring
teardownActivityMonitoring();
}
} }
bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) { bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) {
@@ -121,3 +150,74 @@ bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) {
ALabel::handleToggle(e); ALabel::handleToggle(e);
return true; return true;
} }
bool waybar::modules::IdleInhibitor::handleMotion(GdkEventMotion* const& e) {
if (wait_for_activity_ && status) {
resetActivityTimeout();
}
return false;
}
bool waybar::modules::IdleInhibitor::handleKey(GdkEventKey* const& e) {
if (wait_for_activity_ && status) {
resetActivityTimeout();
}
return false;
}
void waybar::modules::IdleInhibitor::resetActivityTimeout() {
if (!config_["timeout"].isNumeric()) {
return;
}
if (activity_timeout_.connected()) {
activity_timeout_.disconnect();
}
auto timeoutMins = config_["timeout"].asDouble();
int timeoutSecs = timeoutMins * 60;
activity_timeout_ = Glib::signal_timeout().connect_seconds(
[]() {
spdlog::info("deactivating idle_inhibitor due to inactivity");
status = false;
for (auto const& module : waybar::modules::IdleInhibitor::modules) {
module->update();
}
return false;
},
timeoutSecs);
}
void waybar::modules::IdleInhibitor::setupActivityMonitoring() {
// Don't set up if already connected
if (motion_connection_.connected() || key_connection_.connected()) {
return;
}
// Enable motion and key event monitoring on the bar window
auto window = bar_.window.get_window();
if (window) {
window->set_events(window->get_events() | Gdk::POINTER_MOTION_MASK | Gdk::KEY_PRESS_MASK);
}
// Connect to the bar window's event signals
motion_connection_ = bar_.window.signal_motion_notify_event().connect(
sigc::mem_fun(*this, &IdleInhibitor::handleMotion));
key_connection_ = bar_.window.signal_key_press_event().connect(
sigc::mem_fun(*this, &IdleInhibitor::handleKey));
}
void waybar::modules::IdleInhibitor::teardownActivityMonitoring() {
if (activity_timeout_.connected()) {
activity_timeout_.disconnect();
}
if (motion_connection_.connected()) {
motion_connection_.disconnect();
}
if (key_connection_.connected()) {
key_connection_.disconnect();
}
}