From 3c9cbc99d73638c7c3929de86c17d188438975b0 Mon Sep 17 00:00:00 2001 From: Patrick Nicolas Date: Wed, 7 Jun 2023 10:17:42 +0200 Subject: [PATCH] Wake all sleeping threads when leaving suspend std::condition_variable::wait_for does not count time spent in sleep mode, resulting in longer than expected waits. --- include/util/prepare_for_sleep.h | 9 ++++++ include/util/sleeper_thread.hpp | 16 +++++++++-- meson.build | 1 + src/util/prepare_for_sleep.cpp | 49 ++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 include/util/prepare_for_sleep.h create mode 100644 src/util/prepare_for_sleep.cpp diff --git a/include/util/prepare_for_sleep.h b/include/util/prepare_for_sleep.h new file mode 100644 index 00000000..68db8d8e --- /dev/null +++ b/include/util/prepare_for_sleep.h @@ -0,0 +1,9 @@ +#pragma once + +#include "SafeSignal.hpp" + +namespace waybar::util { + +// Get a signal emited with value true when entering sleep, and false when exiting +SafeSignal& prepare_for_sleep(); +} // namespace waybar::util diff --git a/include/util/sleeper_thread.hpp b/include/util/sleeper_thread.hpp index e12287a0..a724b1e8 100644 --- a/include/util/sleeper_thread.hpp +++ b/include/util/sleeper_thread.hpp @@ -6,6 +6,8 @@ #include #include +#include "prepare_for_sleep.h" + namespace waybar::util { /** @@ -33,7 +35,11 @@ class SleeperThread { signal_ = false; func(); } - }} {} + }} { + connection_ = prepare_for_sleep().connect([this](bool sleep) { + if (not sleep) wake_up(); + }); + } SleeperThread& operator=(std::function func) { thread_ = std::thread([this, func] { @@ -42,6 +48,11 @@ class SleeperThread { func(); } }); + if (connection_.empty()) { + connection_ = prepare_for_sleep().connect([this](bool sleep) { + if (not sleep) wake_up(); + }); + } return *this; } @@ -61,7 +72,7 @@ class SleeperThread { return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; }); } - auto wake_up() { + void wake_up() { { std::lock_guard lck(mutex_); signal_ = true; @@ -96,6 +107,7 @@ class SleeperThread { std::mutex mutex_; bool do_run_ = true; bool signal_ = false; + sigc::connection connection_; }; } // namespace waybar::util diff --git a/meson.build b/meson.build index beee053f..0e42defd 100644 --- a/meson.build +++ b/meson.build @@ -170,6 +170,7 @@ src_files = files( 'src/client.cpp', 'src/config.cpp', 'src/group.cpp', + 'src/util/prepare_for_sleep.cpp', 'src/util/ustring_clen.cpp', 'src/util/sanitize_str.cpp', 'src/util/rewrite_string.cpp' diff --git a/src/util/prepare_for_sleep.cpp b/src/util/prepare_for_sleep.cpp new file mode 100644 index 00000000..221497e8 --- /dev/null +++ b/src/util/prepare_for_sleep.cpp @@ -0,0 +1,49 @@ +#include "util/prepare_for_sleep.h" + +#include + +namespace { +class PrepareForSleep { + private: + PrepareForSleep() { + GError *error = NULL; + login1_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (!login1_connection) { + throw std::runtime_error("Unable to connect to the SYSTEM Bus!..."); + } else { + login1_id = g_dbus_connection_signal_subscribe( + login1_connection, "org.freedesktop.login1", "org.freedesktop.login1.Manager", + "PrepareForSleep", "/org/freedesktop/login1", NULL, G_DBUS_SIGNAL_FLAGS_NONE, + prepareForSleep_cb, this, NULL); + } + } + + static void prepareForSleep_cb(GDBusConnection *system_bus, const gchar *sender_name, + const gchar *object_path, const gchar *interface_name, + const gchar *signal_name, GVariant *parameters, + gpointer user_data) { + if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(b)"))) { + gboolean sleeping; + g_variant_get(parameters, "(b)", &sleeping); + + PrepareForSleep *self = static_cast(user_data); + self->signal.emit(sleeping); + } + } + + public: + static PrepareForSleep &GetInstance() { + static PrepareForSleep instance; + return instance; + } + waybar::SafeSignal signal; + + private: + guint login1_id; + GDBusConnection *login1_connection; +}; +} // namespace + +waybar::SafeSignal &waybar::util::prepare_for_sleep() { + return PrepareForSleep::GetInstance().signal; +}