// gKeyMapper - talk to gkeymapper-daemon over the session bus. #ifndef GKEYMAPPER_DAEMONCLIENT_H #define GKEYMAPPER_DAEMONCLIENT_H #include #include #include namespace gkeymapper { // What the footer needs to know about the daemon. struct DaemonStatus { bool reachable = false; std::string version; std::string device; std::string configPath; }; // 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; using KeyFn = std::function; 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; StatusFn onStatus_; KeyFn onKey_; }; } // namespace gkeymapper #endif // GKEYMAPPER_DAEMONCLIENT_H