Files
gKeyMapper/src/daemonclient.h
2026-10-18 18:26:06 +02:00

84 lines
2.9 KiB
C++

// gKeyMapper - talk to gkeymapper-daemon over the session bus.
#ifndef GKEYMAPPER_DAEMONCLIENT_H
#define GKEYMAPPER_DAEMONCLIENT_H
#include <gio/gio.h>
#include <functional>
#include <string>
namespace gkeymapper {
// What the footer needs to know about the daemon.
struct DaemonStatus {
bool reachable = false;
bool configOk = true; // false after a ConfigReloaded(false); see fetch_status
std::string version;
std::string device;
std::string configPath;
};
// The daemon as the GUI shows it: the last status reply plus what the signals
// added since (the last G key that fired). The footer shows a one-line summary of
// it, the options window the full picture.
struct DaemonView {
bool reachable = false;
bool configOk = true;
std::string version;
std::string device;
std::string configPath;
std::string lastKey;
};
// Control-plane client for the daemon. Every call is asynchronous and its
// result arrives on the GTK main loop, so the UI never blocks on the daemon
// (a call is answered at most one daemon loop iteration late). Keypresses never
// travel through here.
class DaemonClient {
public:
using StatusFn = std::function<void(const DaemonStatus&)>;
using KeyFn = std::function<void(int index, const std::string& action)>;
DaemonClient() = default;
~DaemonClient();
DaemonClient(const DaemonClient&) = delete;
DaemonClient& operator=(const DaemonClient&) = delete;
void init(StatusFn onStatus, KeyFn onKey);
// Best effort: asks the daemon to re-read the mappings file. Its file watch
// would pick the save up by itself, this only makes it immediate.
void reload();
private:
static void on_bus_ready(GObject* source, GAsyncResult* result, gpointer userData);
static void on_daemon_signal(GDBusConnection* connection, const gchar* sender,
const gchar* objectPath, const gchar* interfaceName,
const gchar* signalName, GVariant* parameters,
gpointer userData);
static void on_name_owner_changed(GDBusConnection* connection, const gchar* sender,
const gchar* objectPath, const gchar* interfaceName,
const gchar* signalName, GVariant* parameters,
gpointer userData);
static void on_status_reply(GObject* source, GAsyncResult* result, gpointer userData);
static void on_reload_reply(GObject* source, GAsyncResult* result, gpointer userData);
void watch_signals();
void fetch_status();
void report_unreachable();
void publish(const DaemonStatus& status);
GDBusConnection* connection_ = nullptr;
guint signal_subscription_ = 0;
guint name_subscription_ = 0;
bool started_ = false;
bool configOk_ = true;
StatusFn onStatus_;
KeyFn onKey_;
};
} // namespace gkeymapper
#endif // GKEYMAPPER_DAEMONCLIENT_H