spiegel-keyman/linux/ibus-keyman/src/KeymanSystemServiceClient.cpp
Eberhard Beilharz 80ae8e6289
chore(linux): improve compatibility with Gentoo Linux 🍒
Gentoo doesn't use systemd. `libelogind` or `basu` implement some aspects
of systemd, so we use that on Gentoo (or rather when `libsystemd` is not
available but `libelogind` or `basu` is).

Patch from https://forums.gentoo.org/viewtopic.php?p=8850566.
See also https://community.software.sil.org/t/keyman-for-gentoo-linux/9615.

Cherry-pick-of: #12889
2025-01-29 09:18:22 +01:00

111 lines
3 KiB
C++

#include "config.h"
#include <cassert>
#if DBUS_IMPLEMENTATION == SYSTEMD
#include <systemd/sd-bus.h>
#else
#include <basu/sd-bus.h>
#endif
#include "KeymanSystemServiceClient.h"
#define KEYMAN_BUS_NAME "com.keyman.SystemService1"
#define KEYMAN_INTERFACE_NAME "com.keyman.SystemService1.System"
#define KEYMAN_OBJECT_PATH "/com/keyman/SystemService1/System"
extern gboolean testing;
class KeymanSystemServiceClient {
private:
sd_bus_error *error = NULL;
sd_bus_message *msg = NULL;
sd_bus *bus = NULL;
public:
KeymanSystemServiceClient();
~KeymanSystemServiceClient();
void SetCapsLockIndicator(guint32 capsLock);
gint32 GetCapsLockIndicator();
};
KeymanSystemServiceClient::KeymanSystemServiceClient() {
int result;
if (testing) {
result = sd_bus_open_user(&bus);
} else {
result = sd_bus_default_system(&bus);
}
if (result < 0) {
g_error("%s: Can't get connection: %s", __FUNCTION__, strerror(-result));
}
}
KeymanSystemServiceClient::~KeymanSystemServiceClient() {
if (error) { sd_bus_error_free(error); }
if (msg) { sd_bus_message_unref(msg); }
if (bus) { sd_bus_unref(bus); }
}
void KeymanSystemServiceClient::SetCapsLockIndicator(guint32 capsLock) {
// If Set/GetCapsLockIndicator is called more than once and previously
// failed, we will leak `error`.
assert(error == NULL);
if (!bus) {
// we already reported the error, so just return
return;
}
if (capsLock > 1) {
g_error("%s: Invalid value '%d' for parameter capsLock", __FUNCTION__, capsLock);
return;
}
int result = sd_bus_call_method(bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH,
KEYMAN_INTERFACE_NAME, "SetCapsLockIndicator", error, &msg, "b", capsLock);
if (result < 0) {
g_error("%s: Failed to call method SetCapsLockIndicator: %s. %s. %s.",
__FUNCTION__, strerror(-result), error ? error->name : "-", error ? error->message : "-");
return;
}
}
gint32 KeymanSystemServiceClient::GetCapsLockIndicator() {
// If Set/GetCapsLockIndicator is called more than once and previously
// failed, we will leak `error`.
assert(error == NULL);
if (!bus) {
// we already reported the error, so just return
return -1;
}
int result = sd_bus_call_method(bus, KEYMAN_BUS_NAME, KEYMAN_OBJECT_PATH,
KEYMAN_INTERFACE_NAME, "GetCapsLockIndicator", error, &msg, "");
if (result < 0) {
g_error("%s: Failed to call method GetCapsLockIndicator: %s. %s. %s.",
__FUNCTION__, strerror(-result), error ? error->name : "-", error ? error->message : "-");
return -1;
}
guint32 capsLock = 0;
result = sd_bus_message_read(msg, "b", &capsLock);
if (result < 0) {
g_error("%s: Failed to parse response message: %s",
__FUNCTION__, strerror(-result));
return -1;
}
return capsLock;
}
void set_capslock_indicator(
guint32 capsLock
) {
KeymanSystemServiceClient client;
client.SetCapsLockIndicator(capsLock);
}
gint32 get_capslock_indicator() {
KeymanSystemServiceClient client;
return client.GetCapsLockIndicator();
}