From 0f258561e5435d24e0eb75fc6d8e4ae306f4f4e8 Mon Sep 17 00:00:00 2001 From: Cameron Reed Date: Mon, 22 Jul 2024 14:37:46 -0600 Subject: [PATCH] Use Unix sockets instead of GlobalShortcuts portal --- Makefile | 4 +- inc/character_utils.h | 2 + inc/config.h | 2 + inc/ipc.h | 16 ++ inc/shader_utils.h | 2 + inc/shadersrc.h | 2 + inc/shortcuts.h | 40 ----- inc/timer.h | 3 + src/ipc.cpp | 173 +++++++++++++++++++++ src/main.cpp | 97 +++++------- src/shortcuts.cpp | 354 ------------------------------------------ src/timer.cpp | 11 ++ 12 files changed, 256 insertions(+), 450 deletions(-) create mode 100644 inc/ipc.h delete mode 100644 inc/shortcuts.h create mode 100644 src/ipc.cpp delete mode 100644 src/shortcuts.cpp diff --git a/Makefile b/Makefile index 89cba3d..7290807 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ SRC_DIRS := src INC_DIRS := inc -LIBS := glew glfw3 freetype2 sdbus-c++ +LIBS := glew glfw3 freetype2 # Outputs @@ -37,7 +37,7 @@ CXXFLAGS := -std=c++17 $(OPT) -Wall -Wextra -Wpedantic # Linker flags LDFLAGS := $(foreach lib, $(LIBS), $(shell pkg-config --libs-only-L $(lib))) -LDLIBS := $(foreach lib, $(LIBS), $(shell pkg-config --libs-only-l $(lib))) +LDLIBS := $(foreach lib, $(LIBS), $(shell pkg-config --libs-only-l $(lib))) -largParser # Dependency files generated by the compiler diff --git a/inc/character_utils.h b/inc/character_utils.h index 2d29f0d..cc9d2c4 100644 --- a/inc/character_utils.h +++ b/inc/character_utils.h @@ -1,3 +1,5 @@ +#pragma once + #include #include #include diff --git a/inc/config.h b/inc/config.h index 56d3247..3abb93f 100644 --- a/inc/config.h +++ b/inc/config.h @@ -1,3 +1,5 @@ +#pragma once + #include #include #include diff --git a/inc/ipc.h b/inc/ipc.h new file mode 100644 index 0000000..6202329 --- /dev/null +++ b/inc/ipc.h @@ -0,0 +1,16 @@ +#pragma once + +#include "timer.h" + + +namespace IPC { + +void listen_timer(bool* running, Timer* timer, StopWatch* stopwatch); +void addTime(int64_t minutes); +void clearTimer(); +void startStopwatch(); +void pauseResumeStopwatch(); +void clearStopwatch(); +void stop(); +} + diff --git a/inc/shader_utils.h b/inc/shader_utils.h index f106acd..cad6c72 100644 --- a/inc/shader_utils.h +++ b/inc/shader_utils.h @@ -1,3 +1,5 @@ +#pragma once + #include diff --git a/inc/shadersrc.h b/inc/shadersrc.h index ef20e5c..0cd7122 100644 --- a/inc/shadersrc.h +++ b/inc/shadersrc.h @@ -1,2 +1,4 @@ +#pragma once + extern const char* const shader_text_frag; extern const char* const shader_text_vert; diff --git a/inc/shortcuts.h b/inc/shortcuts.h deleted file mode 100644 index cb8fa8e..0000000 --- a/inc/shortcuts.h +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include -#include -#include - - -typedef sdbus::Struct> dbus_shortcut_t; -typedef void(*shortcut_callback_t)(void*); -// typedef std::function shortcut_callback_t; - -struct ShortcutCallback { - void* userData; - shortcut_callback_t callback; -}; - -class GlobalShortcuts { -public: - GlobalShortcuts() = delete; - GlobalShortcuts(const char* const tokenPrefix); - void addShortcut(const std::string& id, const std::string& description, const std::string& trigger, shortcut_callback_t callback, void* userData); - int createSession(); - int bindKeys(); - bool alreadyBound(); - std::vector listBinds(); - void listen(); - -private: - std::string AddNumToToken(); - -private: - sdbus::ObjectPath m_SessionPath; - std::string m_TokenPrefix; - std::string m_ConnName; - std::string m_Sender; - std::unique_ptr m_xdgProxy; - - std::vector m_Shortcuts; - std::map m_Callbacks; -}; diff --git a/inc/timer.h b/inc/timer.h index c484dc8..c088b95 100644 --- a/inc/timer.h +++ b/inc/timer.h @@ -1,3 +1,5 @@ +#pragma once + #include #include @@ -35,6 +37,7 @@ public: StopWatch(); TimeDuration GetTime(); void Start(); + void PauseResume(); void Pause(); void Resume(); void Clear(); diff --git a/src/ipc.cpp b/src/ipc.cpp new file mode 100644 index 0000000..ffa80e0 --- /dev/null +++ b/src/ipc.cpp @@ -0,0 +1,173 @@ +#include +#include +#include +#include +#include + +#include "timer.h" +#include "ipc.h" + + +enum COMMAND { + ADD_TIME = 1, + CLEAR_TIMER = 2, + START_STOPWATCH = 3, + PAUSE_RESUME_STOPWATCH = 4, + CLEAR_STOPWATCH = 5, + STOP = 6, +}; + + +namespace IPC { + +std::filesystem::path getSockDir() +{ + std::filesystem::path sock_dir = getenv("XDG_RUNTIME_DIR"); + if (sock_dir.empty()) { + sock_dir = "/tmp"; + } + + sock_dir /= "timer_overlay"; + + std::filesystem::create_directories(sock_dir); + + return sock_dir; +} + + +void listen_timer(bool* running, Timer* timer, StopWatch* stopwatch) +{ + std::filesystem::path sock_path = getSockDir() / "timer.sock"; + unlink(sock_path.c_str()); + + int sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock == -1) { +// std::cout << "Failed to create socket" << std::endl; + return; + } + + sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock_path.c_str(), sizeof(addr.sun_path) - 1); + + if (bind(sock, (sockaddr*) &addr, sizeof(addr)) == -1) { +// std::cout << "Failed to bind" << std::endl; + close(sock); + return; + } + + char buf[100]; + while (*running) { + ssize_t len = recv(sock, buf, 100, 0); +// std::cout << "New packet" << std::endl; + if (len < 1) { +// std::cout << "Bad packet" << std::endl; + continue; + } + + switch (buf[0]) { + case ADD_TIME: +// std::cout << "Add time packet: " << *(int64_t*) &buf[1] << " minutes" << std::endl; + if (len != 9) break; + timer->AddMinutes(*(int64_t*) &buf[1]); + break; + case CLEAR_TIMER: +// std::cout << "Clear timer packet" << std::endl; + timer->Clear(); + break; + case START_STOPWATCH: +// std::cout << "Start stopwatch packet" << std::endl; + stopwatch->Start(); + break; + case PAUSE_RESUME_STOPWATCH: +// std::cout << "Pause/Resume stopwatch packet" << std::endl; + stopwatch->PauseResume(); + break; + case CLEAR_STOPWATCH: +// std::cout << "Clear stopwatch packet" << std::endl; + stopwatch->Clear(); + break; + case STOP: +// std::cout << "Stop packet" << std::endl; + *running = false; + break; + default: +// std::cout << "Unknown packet" << std::endl; + break; + } + } + + close(sock); + unlink(sock_path.c_str()); +} + +void sendPacket(char* buf, size_t size) +{ + std::filesystem::path sock_path = getSockDir() / "timer.sock"; + + int sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock == -1) { + return; + } + + sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock_path.c_str(), sizeof(addr.sun_path) - 1); + + if (connect(sock, (sockaddr*) &addr, sizeof(addr)) == -1) { + close(sock); + return; + } + + send(sock, buf, size, 0); + + close(sock); +} + +void addTime(int64_t minutes) +{ +// std::cout << "Sending add time packet" << std::endl; + char buf[9] = { ADD_TIME }; + memcpy(&buf[1], &minutes, sizeof(minutes)); + sendPacket(buf, 9); +} + +void clearTimer() +{ +// std::cout << "Sending clear timer packet" << std::endl; + char buf[1] = { CLEAR_TIMER }; + sendPacket(buf, 1); +} + +void startStopwatch() +{ +// std::cout << "Sending start stopwatch packet" << std::endl; + char buf[1] = { START_STOPWATCH }; + sendPacket(buf, 1); +} + +void pauseResumeStopwatch() +{ +// std::cout << "Sending pause/resume stopwatch packet" << std::endl; + char buf[1] = { PAUSE_RESUME_STOPWATCH }; + sendPacket(buf, 1); +} + +void clearStopwatch() +{ +// std::cout << "Sending clear stopwatch packet" << std::endl; + char buf[1] = { CLEAR_STOPWATCH }; + sendPacket(buf, 1); +} + +void stop() +{ +// std::cout << "Sending stop packet" << std::endl; + char buf[1] = { STOP }; + sendPacket(buf, 1); +} + +} // namespace IPC + diff --git a/src/main.cpp b/src/main.cpp index 59d8c8a..6013807 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,8 @@ #include #include #include -#include +#include +#include #include #include @@ -16,17 +17,48 @@ #include "shader_utils.h" #include "shadersrc.h" #include "character_utils.h" -#include "shortcuts.h" -#include "timer.h" #include "config.h" +#include "timer.h" +#include "ipc.h" +int daemon(); + void error_callback(int error, const char* description) { std::cerr << "Error " << error << ": " << description << std::endl; } -int main() +int main(int argc, char* argv[]) +{ + Arguments::Bool start_daemon("daemon"); + Arguments::Int add_time("add", 0); + Arguments::Bool clear_timer("clear-timer"); + Arguments::Bool start_stopwatch("start-stopwatch"); + Arguments::Bool pause("pause"); + Arguments::Bool clear_stopwatch("clear-stopwatch"); + Arguments::Bool stop("stop"); + + Arguments::parse(argc, argv); + + if (start_daemon.found) { + return daemon(); + } else if (add_time.found) { + IPC::addTime(add_time.value); + } else if (clear_timer.found) { + IPC::clearTimer(); + } else if (start_stopwatch.found) { + IPC::startStopwatch(); + } else if (pause.found) { + IPC::pauseResumeStopwatch(); + } else if (clear_stopwatch.found) { + IPC::clearStopwatch(); + } else if (stop.found) { + IPC::stop(); + } +} + +int daemon() { Config cfg = readConfig(getConfigPath("timer_overlay")); @@ -106,60 +138,14 @@ int main() glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); + bool running = true; Timer timer; StopWatch stopwatch; - GlobalShortcuts shortcuts("timer_overlay"); - - if (shortcuts.createSession() != 0) { - std::cout << "Failed to create shortcuts session" << std::endl; - glfwTerminate(); - } - - shortcuts.addShortcut("time1", "Adds 1 minute to the timer", "ALT+F5", [](void* timer_ptr) { - ((Timer*)timer_ptr)->AddMinutes(1); - }, &timer); - shortcuts.addShortcut("time5", "Adds 5 minutes to the timer", "ALT+F6", [](void* timer_ptr) { - ((Timer*)timer_ptr)->AddMinutes(5); - }, &timer); - shortcuts.addShortcut("time15", "Adds 15 minutes to the timer", "ALT+F7", [](void* timer_ptr) { - ((Timer*)timer_ptr)->AddMinutes(15); - }, &timer); - shortcuts.addShortcut("time60", "Adds 1 hour to the timer", "ALT+F8", [](void* timer_ptr) { - ((Timer*)timer_ptr)->AddMinutes(60); - }, &timer); - shortcuts.addShortcut("timeclear", "Clears the timer", "ALT+F9", [](void* timer_ptr) { - ((Timer*)timer_ptr)->Clear(); - }, &timer); - - shortcuts.addShortcut("swstart", "Starts the stopwatch", "CTRL+F5", [](void* stopwatch_ptr) { - ((StopWatch*)stopwatch_ptr)->Start(); - }, &stopwatch); - shortcuts.addShortcut("swclear", "Clears the stopwatch", "CTRL+F6", [](void* stopwatch_ptr) { - ((StopWatch*)stopwatch_ptr)->Clear(); - }, &stopwatch); - shortcuts.addShortcut("swpause", "Pauses the stopwatch", "CTRL+F7", [](void* stopwatch_ptr) { - ((StopWatch*)stopwatch_ptr)->Pause(); - }, &stopwatch); - shortcuts.addShortcut("swresume", "Resumes the stopwatch", "CTRL+F8", [](void* stopwatch_ptr) { - ((StopWatch*)stopwatch_ptr)->Resume(); - }, &stopwatch); - - if (!shortcuts.alreadyBound()) { - std::cout << "Requsting to bind keys" << std::endl; - if (shortcuts.bindKeys() != 0) { - std::cerr << "Failed to bind keys" << std::endl; - return -1; - } - } - - shortcuts.listen(); + std::thread ipc_thread(IPC::listen_timer, &running, &timer, &stopwatch); + int64_t last_frame_seconds = LONG_MAX; - while (!glfwWindowShouldClose(window)) { - if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { - glfwSetWindowShouldClose(window, GLFW_TRUE); - } - + while (running) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); @@ -189,5 +175,8 @@ int main() glfwPollEvents(); } + ipc_thread.join(); glfwTerminate(); + return 0; } + diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp deleted file mode 100644 index 07de9eb..0000000 --- a/src/shortcuts.cpp +++ /dev/null @@ -1,354 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "shortcuts.h" - - -const char* xdgName = "org.freedesktop.portal.Desktop"; -const char* xdgPath = "/org/freedesktop/portal/desktop"; -const char* shortcutsInterface = "org.freedesktop.portal.GlobalShortcuts"; -const char* requstInterface = "org.freedesktop.portal.Request"; - - - - -GlobalShortcuts::GlobalShortcuts(const char* const tokenPrefix) - : m_TokenPrefix(tokenPrefix), m_Shortcuts() { }; - - -std::string GlobalShortcuts::AddNumToToken() -{ - std::random_device dev; - std::mt19937 rng(dev()); - std::uniform_int_distribution dist(1000,9999); - - return m_TokenPrefix + std::to_string(dist(rng)); -} - -void GlobalShortcuts::addShortcut(const std::string& id, const std::string& description, const std::string& trigger, shortcut_callback_t callback, void* userData) -{ - std::map smap; - smap["description"] = sdbus::Variant(description); - smap["preferred_trigger"] = sdbus::Variant(trigger); - - m_Shortcuts.emplace_back(id, smap); - - m_Callbacks[id] = ShortcutCallback{ userData, callback }; -} - -int GlobalShortcuts::createSession() -{ - bool requestInProgress = false; - int result = 1; - - auto conn = sdbus::createSessionBusConnection(); - m_ConnName = conn->getUniqueName(); - m_Sender = m_ConnName.substr(1); - - - m_xdgProxy = sdbus::createProxy(std::move(conn), xdgName, xdgPath); - - std::map create_session_args; - std::string token = AddNumToToken(); - create_session_args["handle_token"] = sdbus::Variant(token); - create_session_args["session_handle_token"] = sdbus::Variant(m_TokenPrefix); - - for (size_t i = 1; i < m_Sender.length(); i++) { - if (m_Sender[i] == '.') { - m_Sender[i] = '_'; - } - } - std::string expectedRequestPath = "/org/freedesktop/portal/desktop/request/" + m_Sender + "/" + token; - - auto requestProxy = sdbus::createProxy(m_xdgProxy->getConnection(), xdgName, expectedRequestPath); - requestProxy->uponSignal("Response").onInterface(requstInterface) - .call([this, &requestInProgress, &result](uint32_t result_code, std::map res_map) - { - if (result_code == 0) { - this->m_SessionPath = res_map.at("session_handle").get(); - } else { - std::cerr << "Failed to create GlobalShortcuts session" << std::endl; - } - result = result_code; - requestInProgress = false; - }); - requestProxy->finishRegistration(); - - - sdbus::ObjectPath requestPath; - requestInProgress = true; - m_xdgProxy->callMethod("CreateSession").onInterface(shortcutsInterface) - .withArguments(create_session_args).storeResultsTo(requestPath); - - std::unique_ptr requestProxy2; - if (requestPath != expectedRequestPath) { - requestProxy->unregister(); - requestProxy2 = sdbus::createProxy(m_xdgProxy->getConnection(), xdgName, requestPath); - requestProxy2->uponSignal("Response").onInterface(requstInterface) - .call([this, &requestInProgress, &result](uint32_t result_code, std::map res_map) - { - if (result_code == 0) { - this->m_SessionPath = res_map.at("session_handle").get(); - } else { - std::cerr << "Failed to create GlobalShortcuts session" << std::endl; - } - result = result_code; - requestInProgress = false; - }); - requestProxy2->finishRegistration(); - } - - while (requestInProgress) { - usleep(500); - } - - return result; -} - -bool GlobalShortcuts::alreadyBound() -{ - std::vector binds = listBinds(); - if (binds.size() != m_Shortcuts.size()) { - return false; - } - - for (dbus_shortcut_t shortcut: m_Shortcuts) { - const std::string shortcut_id = shortcut.get<0>(); - bool match = false; - for (dbus_shortcut_t bind: binds) { - const std::string bind_id = bind.get<0>(); - if (shortcut_id == bind_id) { - match = true; - break; - } - } - - if (!match) { - return false; - } - } - - return true; -} - -std::vector GlobalShortcuts::listBinds() -{ - std::vector binds; - bool requestInProgress = false; - - std::map list_shortcuts_args; - const std::string token = AddNumToToken(); - list_shortcuts_args["handle_token"] = sdbus::Variant(token); - - sdbus::ObjectPath expectedRequestPath = "/org/freedesktop/portal/desktop/request/" + m_Sender + "/" + token; - - auto requestProxy = sdbus::createProxy(m_xdgProxy->getConnection(), xdgName, expectedRequestPath); - requestProxy->uponSignal("Response").onInterface(requstInterface) - .call([&requestInProgress, &binds](uint32_t result_code, std::map res_map) - { - if (result_code == 0) { - binds = res_map.at("shortcuts").get>(); - // for (dbus_shortcut_t bind: binds) { - // std::cout << "id: " << bind.get<0>(); - // std::cout << ", desc: " << bind.get<1>().at("description").get(); - // std::cout << ", trigger: " << bind.get<1>().at("trigger_description").get(); - // std::cout << std::endl << std::endl; - // } - } else { - std::cerr << "Failed to list shortcuts" << std::endl; - } - requestInProgress = false; - }); - requestProxy->finishRegistration(); - - - sdbus::ObjectPath requestPath; - requestInProgress = true; - m_xdgProxy->callMethod("ListShortcuts").onInterface(shortcutsInterface) - .withArguments(m_SessionPath, list_shortcuts_args).storeResultsTo(requestPath); - - std::unique_ptr requestProxy2; - if (requestPath != expectedRequestPath) { - requestProxy->unregister(); - requestProxy2 = sdbus::createProxy(m_xdgProxy->getConnection(), xdgName, requestPath); - requestProxy2->uponSignal("Response").onInterface(requstInterface) - .call([&requestInProgress, &binds](uint32_t result_code, std::map res_map) - { - if (result_code == 0) { - binds = res_map.at("shortcuts").get>(); - } else { - std::cerr << "Failed to list shortcuts" << std::endl; - } - requestInProgress = false; - }); - requestProxy2->finishRegistration(); - } - - - while (requestInProgress) { - usleep(500); - } - - return binds; -} - -int GlobalShortcuts::bindKeys() -{ - bool requestInProgress = false; - int result = 1; - - // std::cout << "session: " << this->sessionPath.c_str() << std::endl; - - std::map bind_shortcuts_args; - const std::string token = AddNumToToken(); - bind_shortcuts_args["handle_token"] = sdbus::Variant(token); - - sdbus::ObjectPath expectedRequestPath = "/org/freedesktop/portal/desktop/request/" + m_Sender + "/" + token; - - auto requestProxy = sdbus::createProxy(m_xdgProxy->getConnection(), xdgName, expectedRequestPath); - requestProxy->uponSignal("Response").onInterface(requstInterface) - .call([&requestInProgress, &result](uint32_t result_code, std::map res_map){ - (void) res_map; - if (result_code == 0) { - // auto binds = res_map.at("shortcuts").get>(); - // for (auto bind: binds) { - // std::cout << "id: " << bind.get<0>(); - // std::cout << ", desc: " << bind.get<1>().at("description").get(); - // std::cout << ", trigger: " << bind.get<1>().at("trigger_description").get(); - // std::cout << std::endl; - // } - } else { - std::cerr << "Failed to bind shortcuts" << std::endl; - } - result = result_code; - requestInProgress = false; - }); - requestProxy->finishRegistration(); - - sdbus::ObjectPath requestPath; - requestInProgress = true; - m_xdgProxy->callMethod("BindShortcuts").onInterface(shortcutsInterface) - .withArguments(m_SessionPath, m_Shortcuts, "", bind_shortcuts_args).storeResultsTo(requestPath); - - std::unique_ptr requestProxy2; - if (requestPath != expectedRequestPath) { - requestProxy->unregister(); - requestProxy2 = sdbus::createProxy(m_xdgProxy->getConnection(), xdgName, requestPath); - requestProxy2->uponSignal("Response").onInterface(requstInterface) - .call([&requestInProgress, &result](uint32_t result_code, std::map res_map){ - (void) res_map; - if (result_code == 0) { - std::cerr << "Failed to bind shortcuts" << std::endl; - } - result = result_code; - requestInProgress = false; - }); - requestProxy2->finishRegistration(); - } - - while (requestInProgress) { - usleep(500); - } - - return result; -} - -void GlobalShortcuts::listen() -{ - m_xdgProxy->uponSignal("Activated").onInterface(shortcutsInterface) - .call([this](sdbus::ObjectPath session_handle, const std::string& shortcut_id, uint64_t timestamp, std::map options) - { - (void) options; - (void) session_handle; - (void) timestamp; - - // std::cout << "Shortcut activated!" << std::endl; - // std::cout << "session: " << session_handle << ", id: " << shortcut_id << ", time: " << timestamp << std::endl << std::endl; - ShortcutCallback cb = this->m_Callbacks[shortcut_id]; - cb.callback(cb.userData); - }); - m_xdgProxy->finishRegistration(); -} - - -// Very basic example - -//int main() -//{ -// GlobalShortcuts shortcuts; -// -// if (shortcuts.createSession() != 0) { -// std::cout << "Failed to create shortcuts session" << std::endl; -// return -1; -// } -// -// shortcuts.addShortcut("test1", "Prints things", "CTRL+SHIFT+a"); -// shortcuts.addShortcut("test2", "Prints things, but like, different", "CTRL+SHIFT+b"); -// -// if (shortcuts.listBinds().size() == 0) { -// std::cout << "Requsting to bind keys" << std::endl; -// shortcuts.bindKeys(); -// } -// -// shortcuts.listen(); -// -// while (true) {}; -//} -// - -// Code for working with libdbus directly. There isn't a lot of information around on how to use it -// And it is pretty difficult to use - -//void connect() -//{ -// DBusConnection* dbus_conn = nullptr; -// DBusError dbus_error; -// -// dbus_error_init(&dbus_error); -// -// dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, &dbus_error); -// std::cout << "Connected to DBUS as \"" << dbus_bus_get_unique_name(dbus_conn) << "\"." << std::endl; -// -// // Request connection to GlobalShortcuts portal -// DBusMessage* conn_request_msg = dbus_message_new_method_call("org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", "org.freedesktop.portal.GlobalShortcuts", "CreateSession"); -// DBusMessage* reply = dbus_connection_send_with_reply_and_block(dbus_conn, conn_request_msg, DBUS_TIMEOUT_USE_DEFAULT, &dbus_error); -// -// const char* conn_request_path = nullptr; -// dbus_message_get_args(reply, &dbus_error, DBUS_TYPE_OBJECT_PATH, conn_request_path, DBUS_TYPE_INVALID); -// -// dbus_message_unref(reply); -// dbus_message_unref(conn_request_msg); -// -// std::string rule = "type='signal',path='"; -// rule = rule + conn_request_path + '\''; -// dbus_bus_add_match(dbus_conn, rule.c_str(), &dbus_error); -// while (true) { -// dbus_connection_read_write(dbus_conn, DBUS_TIMEOUT_USE_DEFAULT); -// DBusMessage* msg_in = dbus_connection_pop_message(dbus_conn); -// if (msg_in == nullptr) { -// continue; -// } -// -// if (dbus_message_is_signal(msg_in, "org.freedesktop.portal.Request", "Response")) { -// uint32_t result; -// -// dbus_message_get_args(msg_in, &dbus_error, DBUS_TYPE_UINT32, &result, DBUS_TYPE_ARRAY, , DBUS_TYPE_INVALID); -// -// std::cout << "Global shortcut session creation result: " << result << std::endl; -// } -// -// dbus_message_unref(msg_in); -// } -// -// dbus_connection_unref(dbus_conn); -//} diff --git a/src/timer.cpp b/src/timer.cpp index 7d58f03..d145e98 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -90,6 +90,17 @@ void StopWatch::Start() } } +void StopWatch::PauseResume() +{ + if (paused) { + start_time = std::chrono::system_clock::now() - paused_duration; + paused = false; + } else { + paused_duration = std::chrono::system_clock::now() - start_time; + paused = true; + } +} + void StopWatch::Pause() { if (!paused) {