Use Unix sockets instead of GlobalShortcuts portal
This commit is contained in:
parent
0e7776e2ca
commit
0f258561e5
4
Makefile
4
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
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <unordered_map>
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
16
inc/ipc.h
Normal file
16
inc/ipc.h
Normal file
@ -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();
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
||||
|
@ -1,2 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
extern const char* const shader_text_frag;
|
||||
extern const char* const shader_text_vert;
|
||||
|
@ -1,40 +0,0 @@
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
typedef sdbus::Struct<std::string, std::map<std::string, sdbus::Variant>> dbus_shortcut_t;
|
||||
typedef void(*shortcut_callback_t)(void*);
|
||||
// typedef std::function<void()> 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<dbus_shortcut_t> 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<sdbus::IProxy> m_xdgProxy;
|
||||
|
||||
std::vector<dbus_shortcut_t> m_Shortcuts;
|
||||
std::map<std::string, ShortcutCallback> m_Callbacks;
|
||||
};
|
@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <chrono>
|
||||
|
||||
@ -35,6 +37,7 @@ public:
|
||||
StopWatch();
|
||||
TimeDuration GetTime();
|
||||
void Start();
|
||||
void PauseResume();
|
||||
void Pause();
|
||||
void Resume();
|
||||
void Clear();
|
||||
|
173
src/ipc.cpp
Normal file
173
src/ipc.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
#include <sys/socket.h>
|
||||
#include <filesystem>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
|
||||
#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
|
||||
|
97
src/main.cpp
97
src/main.cpp
@ -7,7 +7,8 @@
|
||||
#include <glm/common.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <thread>
|
||||
#include <argparser.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1,354 +0,0 @@
|
||||
#include <cstdlib>
|
||||
#include <sdbus-c++/IProxy.h>
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <utility>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#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<std::mt19937::result_type> 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<std::string, sdbus::Variant> 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<std::string, sdbus::Variant> 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<std::string, sdbus::Variant> res_map)
|
||||
{
|
||||
if (result_code == 0) {
|
||||
this->m_SessionPath = res_map.at("session_handle").get<std::string>();
|
||||
} 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<sdbus::IProxy> 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<std::string, sdbus::Variant> res_map)
|
||||
{
|
||||
if (result_code == 0) {
|
||||
this->m_SessionPath = res_map.at("session_handle").get<sdbus::ObjectPath>();
|
||||
} 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<dbus_shortcut_t> 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<dbus_shortcut_t> GlobalShortcuts::listBinds()
|
||||
{
|
||||
std::vector<dbus_shortcut_t> binds;
|
||||
bool requestInProgress = false;
|
||||
|
||||
std::map<std::string, sdbus::Variant> 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<std::string, sdbus::Variant> res_map)
|
||||
{
|
||||
if (result_code == 0) {
|
||||
binds = res_map.at("shortcuts").get<std::vector<dbus_shortcut_t>>();
|
||||
// for (dbus_shortcut_t bind: binds) {
|
||||
// std::cout << "id: " << bind.get<0>();
|
||||
// std::cout << ", desc: " << bind.get<1>().at("description").get<std::string>();
|
||||
// std::cout << ", trigger: " << bind.get<1>().at("trigger_description").get<std::string>();
|
||||
// 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<sdbus::IProxy> 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<std::string, sdbus::Variant> res_map)
|
||||
{
|
||||
if (result_code == 0) {
|
||||
binds = res_map.at("shortcuts").get<std::vector<dbus_shortcut_t>>();
|
||||
} 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<std::string, sdbus::Variant> 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<std::string, sdbus::Variant> res_map){
|
||||
(void) res_map;
|
||||
if (result_code == 0) {
|
||||
// auto binds = res_map.at("shortcuts").get<std::vector<dbus_shortcut_t>>();
|
||||
// for (auto bind: binds) {
|
||||
// std::cout << "id: " << bind.get<0>();
|
||||
// std::cout << ", desc: " << bind.get<1>().at("description").get<std::string>();
|
||||
// std::cout << ", trigger: " << bind.get<1>().at("trigger_description").get<std::string>();
|
||||
// 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<sdbus::IProxy> 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<std::string, sdbus::Variant> 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<std::string, sdbus::Variant> 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);
|
||||
//}
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user