meta: restructure project for a modular architechture for more interfaces

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I16f88f649bddad572e0d44cee7e0edec6a6a6964
This commit is contained in:
raf 2026-04-13 11:23:40 +03:00
commit 087f28d726
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
22 changed files with 2494 additions and 0 deletions

View file

@ -0,0 +1,8 @@
#ifndef DBUS_CINNAMON_SCREENSAVER_H
#define DBUS_CINNAMON_SCREENSAVER_H
#include "inhibit-interface.h"
InhibitInterface *dbus_cinnamon_screensaver_create(void);
#endif

40
include/dbus-common.h Normal file
View file

@ -0,0 +1,40 @@
#ifndef DBUS_COMMON_H
#define DBUS_COMMON_H
#include "inhibit-interface.h"
#include <stdarg.h>
#include <systemd/sd-bus.h>
typedef enum {
DBUS_MODE_NONE,
DBUS_MODE_IMPLEMENT, // we own the D-Bus name
DBUS_MODE_MONITOR // we monitor via BecomeMonitor
} DBusMode;
typedef struct {
sd_bus *bus;
DBusMode mode;
char *bus_name;
char *object_path;
char *interface_name;
sd_bus_slot *slot;
InhibitInterface *parent;
} DBusService;
int dbus_service_init(DBusService *svc, const char *bus_name,
const char *object_path, const char *interface_name);
void dbus_service_cleanup(DBusService *svc);
int dbus_service_detect_mode(DBusService *svc);
int dbus_service_claim_name(DBusService *svc);
int dbus_service_become_monitor(DBusService *svc, const char **match_rules,
int num_rules);
int dbus_service_poll(DBusService *svc);
int dbus_parse_inhibit_request(sd_bus_message *m, char **app_name,
char **reason);
int dbus_send_signal(DBusService *svc, const char *signal_name,
const char *signature, ...);
#endif

View file

@ -0,0 +1,8 @@
#ifndef DBUS_POWERMANAGER_H
#define DBUS_POWERMANAGER_H
#include "inhibit-interface.h"
InhibitInterface *dbus_freedesktop_powermanager_create(void);
#endif

View file

@ -0,0 +1,9 @@
#ifndef DBUS_SCREENSAVER_H
#define DBUS_SCREENSAVER_H
#include "dbus-common.h"
#include "inhibit-interface.h"
InhibitInterface *dbus_freedesktop_screensaver_create(void);
#endif

View file

@ -0,0 +1,8 @@
#ifndef DBUS_GNOME_SCREENSAVER_H
#define DBUS_GNOME_SCREENSAVER_H
#include "inhibit-interface.h"
InhibitInterface *dbus_gnome_screensaver_create(void);
#endif

View file

@ -0,0 +1,8 @@
#ifndef DBUS_GNOME_SESSION_H
#define DBUS_GNOME_SESSION_H
#include "inhibit-interface.h"
InhibitInterface *dbus_gnome_session_create(void);
#endif

View file

@ -0,0 +1,8 @@
#ifndef DBUS_MATE_SCREENSAVER_H
#define DBUS_MATE_SCREENSAVER_H
#include "inhibit-interface.h"
InhibitInterface *dbus_mate_screensaver_create(void);
#endif

View file

@ -0,0 +1,8 @@
#ifndef DBUS_SYSTEMD_LOGIN1_H
#define DBUS_SYSTEMD_LOGIN1_H
#include "inhibit-interface.h"
InhibitInterface *dbus_systemd_login1_create(void);
#endif

103
include/inhibit-interface.h Normal file
View file

@ -0,0 +1,103 @@
#ifndef INHIBIT_INTERFACE_H
#define INHIBIT_INTERFACE_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INTERFACES 16
#define MAX_INHIBITS_PER_INTERFACE 64
#define INHIBIT_ID_LEN 64
typedef enum {
INHIBIT_TYPE_SCREENSAVER = 1 << 0,
INHIBIT_TYPE_SUSPEND = 1 << 1,
INHIBIT_TYPE_IDLE = 1 << 2,
INHIBIT_TYPE_ALL =
INHIBIT_TYPE_SCREENSAVER | INHIBIT_TYPE_SUSPEND | INHIBIT_TYPE_IDLE
} InhibitType;
typedef enum {
INHIBIT_FLAG_NONE = 0,
INHIBIT_FLAG_FORWARDED = 1 << 0,
INHIBIT_FLAG_LOOP_DETECTED = 1 << 1
} InhibitFlags;
typedef struct {
char id[INHIBIT_ID_LEN];
InhibitType type;
char app_name[256];
char reason[1024];
InhibitFlags flags;
uint64_t cookie;
void *interface_data;
} InhibitEntry;
typedef struct {
InhibitEntry entry;
int interface_idx;
char forwarded_to[MAX_INTERFACES][INHIBIT_ID_LEN];
int num_forwarded;
} TrackedInhibit;
typedef struct InhibitInterface InhibitInterface;
typedef void (*InhibitEventCallback)(InhibitInterface *source,
const InhibitEntry *entry, int is_inhibit);
struct InhibitInterface {
const char *name;
int enabled;
int (*init)(InhibitInterface *iface);
void (*cleanup)(InhibitInterface *iface);
int (*inhibit)(InhibitInterface *iface, InhibitType type,
const char *app_name, const char *reason,
InhibitEntry *out_entry);
int (*uninhibit)(InhibitInterface *iface, const InhibitEntry *entry);
int (*poll)(InhibitInterface *iface);
void (*set_callback)(InhibitInterface *iface, InhibitEventCallback cb);
void *private_data;
};
typedef struct {
InhibitInterface *interfaces[MAX_INTERFACES];
int num_interfaces;
TrackedInhibit inhibits[MAX_INTERFACES * MAX_INHIBITS_PER_INTERFACE];
int num_inhibits;
InhibitEventCallback event_callback;
} InhibitManager;
int inhibit_manager_init(InhibitManager *mgr);
void inhibit_manager_cleanup(InhibitManager *mgr);
int inhibit_manager_register(InhibitManager *mgr, InhibitInterface *iface);
void inhibit_manager_set_callback(InhibitManager *mgr, InhibitEventCallback cb);
int inhibit_manager_forward_inhibit(InhibitManager *mgr,
InhibitInterface *source,
const InhibitEntry *entry);
int inhibit_manager_forward_uninhibit(InhibitManager *mgr,
InhibitInterface *source,
const InhibitEntry *entry);
TrackedInhibit *inhibit_manager_find(InhibitManager *mgr,
InhibitInterface *source, const char *id);
int inhibit_manager_add_tracked(InhibitManager *mgr, InhibitInterface *source,
const InhibitEntry *entry);
void inhibit_manager_remove_tracked(InhibitManager *mgr,
InhibitInterface *source, const char *id);
void inhibit_manager_poll_all(InhibitManager *mgr);
const char *inhibit_type_to_string(InhibitType type);
InhibitType inhibit_type_from_string(const char *str);
#endif

View file

@ -0,0 +1,8 @@
#ifndef KERNEL_WAKELOCK_H
#define KERNEL_WAKELOCK_H
#include "inhibit-interface.h"
InhibitInterface *kernel_wakelock_create(void);
#endif

18
include/shell-command.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef SHELL_COMMAND_H
#define SHELL_COMMAND_H
#include "inhibit-interface.h"
typedef struct {
char *screensaver_inhibit;
char *screensaver_uninhibit;
char *suspend_inhibit;
char *suspend_uninhibit;
char *any_inhibit;
char *any_uninhibit;
} ShellCommandConfig;
InhibitInterface *shell_command_create(const ShellCommandConfig *config);
void shell_command_config_free(ShellCommandConfig *config);
#endif

8
include/xidlehook.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef XIDLEHOOK_H
#define XIDLEHOOK_H
#include "inhibit-interface.h"
InhibitInterface *xidlehook_create(const char *socket_path);
#endif

View file

@ -0,0 +1,192 @@
#include "dbus-cinnamon-screensaver.h"
#include "dbus-common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <systemd/sd-bus.h>
typedef struct {
DBusService service;
InhibitEventCallback callback;
uint32_t next_cookie;
} CinnamonSSData;
static int cinnamon_method_inhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
CinnamonSSData* data = userdata;
char *app_name = NULL, *reason = NULL;
if (dbus_parse_inhibit_request(m, &app_name, &reason) < 0) {
return sd_bus_reply_method_return(m, "u", 0);
}
uint32_t cookie = data->next_cookie++;
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "cinnamon_%u", cookie);
strncpy(entry.app_name, app_name ? app_name : "unknown", sizeof(entry.app_name) - 1);
strncpy(entry.reason, reason ? reason : "", sizeof(entry.reason) - 1);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 1);
}
free(app_name);
free(reason);
return sd_bus_reply_method_return(m, "u", cookie);
}
static int cinnamon_method_uninhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
CinnamonSSData* data = userdata;
uint32_t cookie = 0;
int r = sd_bus_message_read(m, "u", &cookie);
if (r < 0) {
return sd_bus_reply_method_return(m, "");
}
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "cinnamon_%u", cookie);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 0);
}
return sd_bus_reply_method_return(m, "");
}
static int cinnamon_method_simulate_activity(sd_bus_message* m, void* userdata,
sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "");
}
static int cinnamon_method_get_active(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "b", 1);
}
static const sd_bus_vtable cinnamon_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Inhibit", "ss", "u", cinnamon_method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnInhibit", "u", "", cinnamon_method_uninhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SimulateUserActivity", "", "", cinnamon_method_simulate_activity,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetActive", "", "b", cinnamon_method_get_active, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END};
static int cinnamon_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
CinnamonSSData* data = iface->private_data;
int r = dbus_service_init(&data->service, "org.cinnamon.ScreenSaver", "/org/cinnamon/ScreenSaver",
"org.cinnamon.ScreenSaver");
if (r < 0)
return -1;
r = sd_bus_open(&data->service.bus);
if (r < 0) {
fprintf(stderr, "Failed to open bus for cinnamon-screensaver: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
data->service.parent = iface;
r = dbus_service_detect_mode(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
if (data->service.mode == DBUS_MODE_IMPLEMENT) {
r = dbus_service_claim_name(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
r = sd_bus_add_object_vtable(data->service.bus, &data->service.slot, data->service.object_path,
data->service.interface_name, cinnamon_vtable, data);
if (r < 0) {
fprintf(stderr, "Failed to add cinnamon vtable: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
} else {
const char* rules[] = {"interface='org.cinnamon.ScreenSaver'"};
r = dbus_service_become_monitor(&data->service, rules, 1);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
}
return 0;
}
static void cinnamon_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
CinnamonSSData* data = iface->private_data;
dbus_service_cleanup(&data->service);
}
static int cinnamon_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) iface;
(void) type;
(void) app_name;
(void) reason;
(void) out_entry;
return 0;
}
static int cinnamon_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) iface;
(void) entry;
return 0;
}
static int cinnamon_poll(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
CinnamonSSData* data = iface->private_data;
return dbus_service_poll(&data->service);
}
static void cinnamon_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
if (!iface || !iface->private_data)
return;
CinnamonSSData* data = iface->private_data;
data->callback = cb;
}
InhibitInterface* dbus_cinnamon_screensaver_create(void) {
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
CinnamonSSData* data = calloc(1, sizeof(CinnamonSSData));
if (!data) {
free(iface);
return NULL;
}
iface->name = "cinnamon-screensaver";
iface->init = cinnamon_init;
iface->cleanup = cinnamon_cleanup;
iface->inhibit = cinnamon_inhibit;
iface->uninhibit = cinnamon_uninhibit;
iface->poll = cinnamon_poll;
iface->set_callback = cinnamon_set_callback;
iface->private_data = data;
return iface;
}

View file

@ -0,0 +1,192 @@
#include "dbus-freedesktop-powermanager.h"
#include "dbus-common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <systemd/sd-bus.h>
typedef struct {
DBusService service;
InhibitEventCallback callback;
uint32_t next_cookie;
int has_inhibit;
} FDPMData;
static int pm_method_inhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
FDPMData* data = userdata;
char *app_name = NULL, *reason = NULL;
if (dbus_parse_inhibit_request(m, &app_name, &reason) < 0) {
return sd_bus_reply_method_return(m, "u", 0);
}
uint32_t cookie = data->next_cookie++;
InhibitEntry entry = {.type = INHIBIT_TYPE_SUSPEND, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "fdpm_%u", cookie);
strncpy(entry.app_name, app_name ? app_name : "unknown", sizeof(entry.app_name) - 1);
strncpy(entry.reason, reason ? reason : "", sizeof(entry.reason) - 1);
int had_inhibit = data->has_inhibit;
data->has_inhibit = 1;
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 1);
}
if (!had_inhibit && data->service.bus) {
dbus_send_signal(&data->service, "HasInhibitChanged", "b", 1);
}
free(app_name);
free(reason);
return sd_bus_reply_method_return(m, "u", cookie);
}
static int pm_method_uninhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
FDPMData* data = userdata;
uint32_t cookie = 0;
int r = sd_bus_message_read(m, "u", &cookie);
if (r < 0) {
return sd_bus_reply_method_return(m, "");
}
InhibitEntry entry = {.type = INHIBIT_TYPE_SUSPEND, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "fdpm_%u", cookie);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 0);
}
return sd_bus_reply_method_return(m, "");
}
static int pm_method_has_inhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
FDPMData* data = userdata;
return sd_bus_reply_method_return(m, "b", data->has_inhibit);
}
static const sd_bus_vtable powermanager_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Inhibit", "ss", "u", pm_method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnInhibit", "u", "", pm_method_uninhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("HasInhibit", "", "b", pm_method_has_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("HasInhibitChanged", "b", 0),
SD_BUS_VTABLE_END};
static int fdpm_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
FDPMData* data = iface->private_data;
int r = dbus_service_init(&data->service, "org.freedesktop.PowerManagement",
"/org/freedesktop/PowerManagement", "org.freedesktop.PowerManagement");
if (r < 0)
return -1;
r = sd_bus_open(&data->service.bus);
if (r < 0) {
fprintf(stderr, "Failed to open bus for powermanager: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
data->service.parent = iface;
r = dbus_service_detect_mode(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
if (data->service.mode == DBUS_MODE_IMPLEMENT) {
r = dbus_service_claim_name(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
r = sd_bus_add_object_vtable(data->service.bus, &data->service.slot, data->service.object_path,
data->service.interface_name, powermanager_vtable, data);
if (r < 0) {
fprintf(stderr, "Failed to add powermanager vtable: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
} else {
const char* rules[] = {"interface='org.freedesktop.PowerManagement'"};
r = dbus_service_become_monitor(&data->service, rules, 1);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
}
return 0;
}
static void fdpm_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
FDPMData* data = iface->private_data;
dbus_service_cleanup(&data->service);
}
static int fdpm_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) iface;
(void) type;
(void) app_name;
(void) reason;
(void) out_entry;
return 0;
}
static int fdpm_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) iface;
(void) entry;
return 0;
}
static int fdpm_poll(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
FDPMData* data = iface->private_data;
return dbus_service_poll(&data->service);
}
static void fdpm_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
if (!iface || !iface->private_data)
return;
FDPMData* data = iface->private_data;
data->callback = cb;
}
InhibitInterface* dbus_freedesktop_powermanager_create(void) {
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
FDPMData* data = calloc(1, sizeof(FDPMData));
if (!data) {
free(iface);
return NULL;
}
iface->name = "freedesktop-powermanager";
iface->init = fdpm_init;
iface->cleanup = fdpm_cleanup;
iface->inhibit = fdpm_inhibit;
iface->uninhibit = fdpm_uninhibit;
iface->poll = fdpm_poll;
iface->set_callback = fdpm_set_callback;
iface->private_data = data;
return iface;
}

View file

@ -0,0 +1,198 @@
#include "dbus-freedesktop-screensaver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <systemd/sd-bus.h>
typedef struct {
DBusService service;
InhibitEventCallback callback;
uint32_t next_cookie;
} FDSSData;
static int method_inhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
FDSSData* data = userdata;
char *app_name = NULL, *reason = NULL;
if (dbus_parse_inhibit_request(m, &app_name, &reason) < 0) {
return sd_bus_reply_method_return(m, "u", 0);
}
uint32_t cookie = data->next_cookie++;
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "fdss_%u", cookie);
strncpy(entry.app_name, app_name ? app_name : "unknown", sizeof(entry.app_name) - 1);
strncpy(entry.reason, reason ? reason : "", sizeof(entry.reason) - 1);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 1);
}
free(app_name);
free(reason);
return sd_bus_reply_method_return(m, "u", cookie);
}
static int method_uninhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
FDSSData* data = userdata;
uint32_t cookie = 0;
int r = sd_bus_message_read(m, "u", &cookie);
if (r < 0) {
return sd_bus_reply_method_return(m, "");
}
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "fdss_%u", cookie);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 0);
}
return sd_bus_reply_method_return(m, "");
}
static int method_simulate_user_activity(sd_bus_message* m, void* userdata,
sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "");
}
static int method_get_active(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "b", 1);
}
static int method_get_session_idle(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "b", 0);
}
static const sd_bus_vtable screensaver_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Inhibit", "ss", "u", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnInhibit", "u", "", method_uninhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SimulateUserActivity", "", "", method_simulate_user_activity,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetActive", "", "b", method_get_active, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionIdle", "", "b", method_get_session_idle, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END};
static int fdss_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
FDSSData* data = iface->private_data;
int r = dbus_service_init(&data->service, "org.freedesktop.ScreenSaver",
"/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver");
if (r < 0)
return -1;
r = sd_bus_open(&data->service.bus);
if (r < 0) {
fprintf(stderr, "Failed to open bus for freedesktop-screensaver: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
data->service.parent = iface;
r = dbus_service_detect_mode(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
if (data->service.mode == DBUS_MODE_IMPLEMENT) {
r = dbus_service_claim_name(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
r = sd_bus_add_object_vtable(data->service.bus, &data->service.slot, data->service.object_path,
data->service.interface_name, screensaver_vtable, data);
if (r < 0) {
fprintf(stderr, "Failed to add vtable: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
} else {
const char* rules[] = {"interface='org.freedesktop.ScreenSaver'"};
r = dbus_service_become_monitor(&data->service, rules, 1);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
}
return 0;
}
static void fdss_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
FDSSData* data = iface->private_data;
dbus_service_cleanup(&data->service);
}
static int fdss_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) iface;
(void) type;
(void) app_name;
(void) reason;
(void) out_entry;
return 0;
}
static int fdss_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) iface;
(void) entry;
return 0;
}
static int fdss_poll(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
FDSSData* data = iface->private_data;
return dbus_service_poll(&data->service);
}
static void fdss_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
if (!iface || !iface->private_data)
return;
FDSSData* data = iface->private_data;
data->callback = cb;
}
InhibitInterface* dbus_freedesktop_screensaver_create(void) {
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
FDSSData* data = calloc(1, sizeof(FDSSData));
if (!data) {
free(iface);
return NULL;
}
iface->name = "freedesktop-screensaver";
iface->init = fdss_init;
iface->cleanup = fdss_cleanup;
iface->inhibit = fdss_inhibit;
iface->uninhibit = fdss_uninhibit;
iface->poll = fdss_poll;
iface->set_callback = fdss_set_callback;
iface->private_data = data;
return iface;
}

View file

@ -0,0 +1,201 @@
#include "dbus-gnome-screensaver.h"
#include "dbus-common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <systemd/sd-bus.h>
typedef struct {
DBusService service;
InhibitEventCallback callback;
uint32_t next_cookie;
} GnomeSSData;
static int gnome_ss_method_inhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
GnomeSSData* data = userdata;
char *app_name = NULL, *reason = NULL;
if (dbus_parse_inhibit_request(m, &app_name, &reason) < 0) {
return sd_bus_reply_method_return(m, "u", 0);
}
uint32_t cookie = data->next_cookie++;
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "gnome_ss_%u", cookie);
strncpy(entry.app_name, app_name ? app_name : "unknown", sizeof(entry.app_name) - 1);
strncpy(entry.reason, reason ? reason : "", sizeof(entry.reason) - 1);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 1);
}
free(app_name);
free(reason);
return sd_bus_reply_method_return(m, "u", cookie);
}
static int gnome_ss_method_uninhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
GnomeSSData* data = userdata;
uint32_t cookie = 0;
int r = sd_bus_message_read(m, "u", &cookie);
if (r < 0) {
return sd_bus_reply_method_return(m, "");
}
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "gnome_ss_%u", cookie);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 0);
}
return sd_bus_reply_method_return(m, "");
}
static int gnome_ss_method_simulate_activity(sd_bus_message* m, void* userdata,
sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "");
}
static int gnome_ss_method_get_active(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "b", 1);
}
static int gnome_ss_method_get_session_idle(sd_bus_message* m, void* userdata,
sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "b", 0);
}
static const sd_bus_vtable gnome_ss_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Inhibit", "ss", "u", gnome_ss_method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnInhibit", "u", "", gnome_ss_method_uninhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SimulateUserActivity", "", "", gnome_ss_method_simulate_activity,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetActive", "", "b", gnome_ss_method_get_active, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionIdle", "", "b", gnome_ss_method_get_session_idle,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END};
static int gnome_ss_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
GnomeSSData* data = iface->private_data;
int r = dbus_service_init(&data->service, "org.gnome.ScreenSaver", "/org/gnome/ScreenSaver",
"org.gnome.ScreenSaver");
if (r < 0)
return -1;
r = sd_bus_open(&data->service.bus);
if (r < 0) {
fprintf(stderr, "Failed to open bus for gnome-screensaver: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
data->service.parent = iface;
r = dbus_service_detect_mode(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
if (data->service.mode == DBUS_MODE_IMPLEMENT) {
r = dbus_service_claim_name(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
r = sd_bus_add_object_vtable(data->service.bus, &data->service.slot, data->service.object_path,
data->service.interface_name, gnome_ss_vtable, data);
if (r < 0) {
fprintf(stderr, "Failed to add gnome-screensaver vtable: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
} else {
const char* rules[] = {"interface='org.gnome.ScreenSaver'"};
r = dbus_service_become_monitor(&data->service, rules, 1);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
}
return 0;
}
static void gnome_ss_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
GnomeSSData* data = iface->private_data;
dbus_service_cleanup(&data->service);
}
static int gnome_ss_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) iface;
(void) type;
(void) app_name;
(void) reason;
(void) out_entry;
return 0;
}
static int gnome_ss_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) iface;
(void) entry;
return 0;
}
static int gnome_ss_poll(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
GnomeSSData* data = iface->private_data;
return dbus_service_poll(&data->service);
}
static void gnome_ss_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
if (!iface || !iface->private_data)
return;
GnomeSSData* data = iface->private_data;
data->callback = cb;
}
InhibitInterface* dbus_gnome_screensaver_create(void) {
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
GnomeSSData* data = calloc(1, sizeof(GnomeSSData));
if (!data) {
free(iface);
return NULL;
}
iface->name = "gnome-screensaver";
iface->init = gnome_ss_init;
iface->cleanup = gnome_ss_cleanup;
iface->inhibit = gnome_ss_inhibit;
iface->uninhibit = gnome_ss_uninhibit;
iface->poll = gnome_ss_poll;
iface->set_callback = gnome_ss_set_callback;
iface->private_data = data;
return iface;
}

195
src/dbus-gnome-session.c Normal file
View file

@ -0,0 +1,195 @@
#include "dbus-gnome-session.h"
#include "dbus-common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <systemd/sd-bus.h>
#define GNOME_INHIBIT_IDLE 0x01
#define GNOME_INHIBIT_SUSPEND 0x04
#define GNOME_INHIBIT_LOGOUT 0x02
#define GNOME_INHIBIT_SWITCH_USERS 0x08
typedef struct {
DBusService service;
InhibitEventCallback callback;
uint32_t next_cookie;
} GnomeSessionData;
static int gnome_method_inhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
GnomeSessionData* data = userdata;
char * app_id = NULL, *reason = NULL;
uint32_t flags = 0, toplevel_xid = 0;
int r = sd_bus_message_read(m, "susu", &app_id, &toplevel_xid, &reason, &flags);
if (r < 0) {
return sd_bus_reply_method_return(m, "u", 0);
}
uint32_t cookie = data->next_cookie++;
InhibitType type = INHIBIT_TYPE_IDLE;
if (flags & GNOME_INHIBIT_SUSPEND) {
type = INHIBIT_TYPE_SUSPEND;
} else if (flags & GNOME_INHIBIT_IDLE) {
type = INHIBIT_TYPE_IDLE;
}
InhibitEntry entry = {.type = type, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "gnome_sess_%u", cookie);
strncpy(entry.app_name, app_id ? app_id : "unknown", sizeof(entry.app_name) - 1);
strncpy(entry.reason, reason ? reason : "", sizeof(entry.reason) - 1);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 1);
}
return sd_bus_reply_method_return(m, "u", cookie);
}
static int gnome_method_uninhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
GnomeSessionData* data = userdata;
uint32_t cookie = 0;
int r = sd_bus_message_read(m, "u", &cookie);
if (r < 0) {
return sd_bus_reply_method_return(m, "");
}
InhibitEntry entry = {.type = INHIBIT_TYPE_IDLE, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "gnome_sess_%u", cookie);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 0);
}
return sd_bus_reply_method_return(m, "");
}
static int gnome_method_is_inhibited(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "b", 0);
}
static const sd_bus_vtable gnome_session_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Inhibit", "susu", "u", gnome_method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Uninhibit", "u", "", gnome_method_uninhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("IsInhibited", "u", "b", gnome_method_is_inhibited, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END};
static int gnome_session_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
GnomeSessionData* data = iface->private_data;
int r = dbus_service_init(&data->service, "org.gnome.SessionManager", "/org/gnome/SessionManager",
"org.gnome.SessionManager");
if (r < 0)
return -1;
r = sd_bus_open(&data->service.bus);
if (r < 0) {
fprintf(stderr, "Failed to open bus for gnome-session: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
data->service.parent = iface;
r = dbus_service_detect_mode(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
if (data->service.mode == DBUS_MODE_IMPLEMENT) {
r = dbus_service_claim_name(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
r = sd_bus_add_object_vtable(data->service.bus, &data->service.slot, data->service.object_path,
data->service.interface_name, gnome_session_vtable, data);
if (r < 0) {
fprintf(stderr, "Failed to add gnome-session vtable: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
} else {
const char* rules[] = {"interface='org.gnome.SessionManager'"};
r = dbus_service_become_monitor(&data->service, rules, 1);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
}
return 0;
}
static void gnome_session_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
GnomeSessionData* data = iface->private_data;
dbus_service_cleanup(&data->service);
}
static int gnome_session_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) iface;
(void) type;
(void) app_name;
(void) reason;
(void) out_entry;
return 0;
}
static int gnome_session_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) iface;
(void) entry;
return 0;
}
static int gnome_session_poll(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
GnomeSessionData* data = iface->private_data;
return dbus_service_poll(&data->service);
}
static void gnome_session_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
if (!iface || !iface->private_data)
return;
GnomeSessionData* data = iface->private_data;
data->callback = cb;
}
InhibitInterface* dbus_gnome_session_create(void) {
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
GnomeSessionData* data = calloc(1, sizeof(GnomeSessionData));
if (!data) {
free(iface);
return NULL;
}
iface->name = "gnome-session";
iface->init = gnome_session_init;
iface->cleanup = gnome_session_cleanup;
iface->inhibit = gnome_session_inhibit;
iface->uninhibit = gnome_session_uninhibit;
iface->poll = gnome_session_poll;
iface->set_callback = gnome_session_set_callback;
iface->private_data = data;
return iface;
}

192
src/dbus-mate-screensaver.c Normal file
View file

@ -0,0 +1,192 @@
#include "dbus-mate-screensaver.h"
#include "dbus-common.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <systemd/sd-bus.h>
typedef struct {
DBusService service;
InhibitEventCallback callback;
uint32_t next_cookie;
} MateSSData;
static int mate_method_inhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
MateSSData* data = userdata;
char *app_name = NULL, *reason = NULL;
if (dbus_parse_inhibit_request(m, &app_name, &reason) < 0) {
return sd_bus_reply_method_return(m, "u", 0);
}
uint32_t cookie = data->next_cookie++;
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "mate_%u", cookie);
strncpy(entry.app_name, app_name ? app_name : "unknown", sizeof(entry.app_name) - 1);
strncpy(entry.reason, reason ? reason : "", sizeof(entry.reason) - 1);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 1);
}
free(app_name);
free(reason);
return sd_bus_reply_method_return(m, "u", cookie);
}
static int mate_method_uninhibit(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) ret_error;
MateSSData* data = userdata;
uint32_t cookie = 0;
int r = sd_bus_message_read(m, "u", &cookie);
if (r < 0) {
return sd_bus_reply_method_return(m, "");
}
InhibitEntry entry = {.type = INHIBIT_TYPE_SCREENSAVER, .cookie = cookie};
snprintf(entry.id, sizeof(entry.id), "mate_%u", cookie);
if (data->callback) {
data->callback((InhibitInterface*) data->service.parent, &entry, 0);
}
return sd_bus_reply_method_return(m, "");
}
static int mate_method_simulate_activity(sd_bus_message* m, void* userdata,
sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "");
}
static int mate_method_get_active(sd_bus_message* m, void* userdata, sd_bus_error* ret_error) {
(void) userdata;
(void) ret_error;
return sd_bus_reply_method_return(m, "b", 1);
}
static const sd_bus_vtable mate_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_METHOD("Inhibit", "ss", "u", mate_method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnInhibit", "u", "", mate_method_uninhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SimulateUserActivity", "", "", mate_method_simulate_activity,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetActive", "", "b", mate_method_get_active, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END};
static int mate_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
MateSSData* data = iface->private_data;
int r = dbus_service_init(&data->service, "org.mate.ScreenSaver", "/org/mate/ScreenSaver",
"org.mate.ScreenSaver");
if (r < 0)
return -1;
r = sd_bus_open(&data->service.bus);
if (r < 0) {
fprintf(stderr, "Failed to open bus for mate-screensaver: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
data->service.parent = iface;
r = dbus_service_detect_mode(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
if (data->service.mode == DBUS_MODE_IMPLEMENT) {
r = dbus_service_claim_name(&data->service);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
r = sd_bus_add_object_vtable(data->service.bus, &data->service.slot, data->service.object_path,
data->service.interface_name, mate_vtable, data);
if (r < 0) {
fprintf(stderr, "Failed to add mate vtable: %s\n", strerror(-r));
dbus_service_cleanup(&data->service);
return -1;
}
} else {
const char* rules[] = {"interface='org.mate.ScreenSaver'"};
r = dbus_service_become_monitor(&data->service, rules, 1);
if (r < 0) {
dbus_service_cleanup(&data->service);
return -1;
}
}
return 0;
}
static void mate_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
MateSSData* data = iface->private_data;
dbus_service_cleanup(&data->service);
}
static int mate_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) iface;
(void) type;
(void) app_name;
(void) reason;
(void) out_entry;
return 0;
}
static int mate_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) iface;
(void) entry;
return 0;
}
static int mate_poll(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
MateSSData* data = iface->private_data;
return dbus_service_poll(&data->service);
}
static void mate_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
if (!iface || !iface->private_data)
return;
MateSSData* data = iface->private_data;
data->callback = cb;
}
InhibitInterface* dbus_mate_screensaver_create(void) {
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
MateSSData* data = calloc(1, sizeof(MateSSData));
if (!data) {
free(iface);
return NULL;
}
iface->name = "mate-screensaver";
iface->init = mate_init;
iface->cleanup = mate_cleanup;
iface->inhibit = mate_inhibit;
iface->uninhibit = mate_uninhibit;
iface->poll = mate_poll;
iface->set_callback = mate_set_callback;
iface->private_data = data;
return iface;
}

128
src/kernel-wakelock.c Normal file
View file

@ -0,0 +1,128 @@
#include "kernel-wakelock.h"
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define WAKE_LOCK_PATH "/sys/power/wake_lock"
#define WAKE_UNLOCK_PATH "/sys/power/wake_unlock"
typedef struct {
uint32_t next_id;
} KernelWakelockData;
static int kernel_wakelock_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
int fd = open(WAKE_LOCK_PATH, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Kernel wakelock not available (no %s): %s\n", WAKE_LOCK_PATH, strerror(errno));
return -1;
}
close(fd);
return 0;
}
static void kernel_wakelock_cleanup(InhibitInterface* iface) { (void) iface; }
static int kernel_wakelock_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) type;
(void) app_name;
(void) reason;
if (!iface || !iface->private_data || !out_entry)
return -1;
KernelWakelockData* data = iface->private_data;
int fd = open(WAKE_LOCK_PATH, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open wake_lock: %s\n", strerror(errno));
return -1;
}
uint32_t id = data->next_id++;
char lock_name[64];
snprintf(lock_name, sizeof(lock_name), "sin_%u", id);
ssize_t written = write(fd, lock_name, strlen(lock_name));
close(fd);
if (written < 0) {
fprintf(stderr, "Failed to write wake_lock: %s\n", strerror(errno));
return -1;
}
snprintf(out_entry->id, sizeof(out_entry->id), "kernel_%u", id);
out_entry->cookie = id;
out_entry->type = INHIBIT_TYPE_SUSPEND;
strncpy(out_entry->app_name, app_name ? app_name : "unknown", sizeof(out_entry->app_name) - 1);
strncpy(out_entry->reason, reason ? reason : "", sizeof(out_entry->reason) - 1);
return 0;
}
static int kernel_wakelock_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) iface;
if (!entry)
return -1;
int fd = open(WAKE_UNLOCK_PATH, O_WRONLY);
if (fd < 0) {
fprintf(stderr, "Failed to open wake_unlock: %s\n", strerror(errno));
return -1;
}
char lock_name[64];
snprintf(lock_name, sizeof(lock_name), "sin_%" PRIu64, entry->cookie);
ssize_t written = write(fd, lock_name, strlen(lock_name));
close(fd);
if (written < 0) {
fprintf(stderr, "Failed to write wake_unlock: %s\n", strerror(errno));
return -1;
}
return 0;
}
static int kernel_wakelock_poll(InhibitInterface* iface) {
(void) iface;
return 0;
}
static void kernel_wakelock_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
(void) iface;
(void) cb;
}
InhibitInterface* kernel_wakelock_create(void) {
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
KernelWakelockData* data = calloc(1, sizeof(KernelWakelockData));
if (!data) {
free(iface);
return NULL;
}
iface->name = "kernel-wakelock";
iface->init = kernel_wakelock_init;
iface->cleanup = kernel_wakelock_cleanup;
iface->inhibit = kernel_wakelock_inhibit;
iface->uninhibit = kernel_wakelock_uninhibit;
iface->poll = kernel_wakelock_poll;
iface->set_callback = kernel_wakelock_set_callback;
iface->private_data = data;
return iface;
}

637
src/main.c Normal file
View file

@ -0,0 +1,637 @@
#define _GNU_SOURCE
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <poll.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "dbus-cinnamon-screensaver.h"
#include "dbus-freedesktop-powermanager.h"
#include "dbus-freedesktop-screensaver.h"
#include "dbus-gnome-screensaver.h"
#include "dbus-gnome-session.h"
#include "dbus-mate-screensaver.h"
#include "dbus-systemd-login1.h"
#include "inhibit-interface.h"
#include "kernel-wakelock.h"
#include "shell-command.h"
#include "xidlehook.h"
#define VERSION "2.0.0"
#define EXIT_OK 0
#define EXIT_ARGS 1
#define EXIT_INIT 2
#define EXIT_RUNTIME 3
#define MAX_PATTERNS 128
#define MAX_PATTERN_LEN 4096U
#define MIN_POLL_INTERVAL 0.1
#define MAX_POLL_INTERVAL 3600.0
#define DEFAULT_POLL_INTERVAL 2.0
#define CMDLINE_INITIAL_SIZE 4096U
#define CMDLINE_MAX_SIZE (1024U * 1024U)
static volatile sig_atomic_t running = 1;
static volatile sig_atomic_t cleanup_requested = 0;
static int quiet = 0;
static int daemonize = 0;
static InhibitManager g_manager;
static ShellCommandConfig g_shell_config;
static void handle_sig(int sig) {
(void) sig;
running = 0;
cleanup_requested = 1;
}
static void on_inhibit_event(InhibitInterface* source, const InhibitEntry* entry, int is_inhibit) {
if (!quiet) {
fprintf(stderr, "[%s] %s: %s (%s) - %s\n", source ? source->name : "process-watcher",
is_inhibit ? "INHIBIT" : "RELEASE", entry->app_name,
inhibit_type_to_string(entry->type), entry->reason);
}
if (is_inhibit) {
inhibit_manager_forward_inhibit(&g_manager, source, entry);
} else {
inhibit_manager_forward_uninhibit(&g_manager, source, entry);
}
}
static char* read_cmdline(pid_t pid) {
char path[64];
int n = snprintf(path, sizeof(path), "/proc/%d/cmdline", (int) pid);
if (n < 0 || (size_t) n >= sizeof(path)) {
return NULL;
}
int fd = open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0)
return NULL;
size_t cap = CMDLINE_INITIAL_SIZE;
char* buf = malloc(cap);
if (!buf) {
close(fd);
return NULL;
}
size_t len = 0;
for (;;) {
if (len >= CMDLINE_MAX_SIZE) {
free(buf);
close(fd);
return NULL;
}
ssize_t r = read(fd, buf + len, cap - len);
if (r < 0) {
if (errno == EINTR)
continue;
free(buf);
close(fd);
return NULL;
}
if (r == 0)
break;
len += (size_t) r;
if (len >= cap) {
size_t new_cap = cap * 2U;
if (new_cap > CMDLINE_MAX_SIZE)
new_cap = CMDLINE_MAX_SIZE;
if (new_cap <= cap) {
break;
}
char* nb = realloc(buf, new_cap);
if (!nb) {
free(buf);
close(fd);
return NULL;
}
buf = nb;
cap = new_cap;
}
}
close(fd);
if (len == 0) {
free(buf);
return NULL;
}
for (size_t j = 0; j < len; ++j) {
if (buf[j] == '\0')
buf[j] = ' ';
}
if (len >= cap) {
char* nb = realloc(buf, len + 1);
if (!nb) {
free(buf);
return NULL;
}
buf = nb;
}
buf[len] = '\0';
return buf;
}
static int any_process_running(char** patterns, int npats) {
if (!patterns || npats <= 0)
return 0;
DIR* d = opendir("/proc");
if (!d) {
fprintf(stderr, "opendir /proc failed: %s\n", strerror(errno));
return 0;
}
struct dirent* ent;
int found = 0;
while ((ent = readdir(d)) != NULL && !found) {
const char* name = ent->d_name;
if (!isdigit((unsigned char) name[0]))
continue;
int all_digits = 1;
for (const char* p = name; *p; ++p) {
if (!isdigit((unsigned char) *p)) {
all_digits = 0;
break;
}
}
if (!all_digits)
continue;
char* endptr;
long pid_long = strtol(name, &endptr, 10);
if (*endptr != '\0' || pid_long <= 0 || pid_long > INT_MAX)
continue;
pid_t pid = (pid_t) pid_long;
char* cmd = read_cmdline(pid);
if (!cmd)
continue;
for (int i = 0; i < npats; ++i) {
if (strstr(cmd, patterns[i]) != NULL) {
found = 1;
break;
}
}
free(cmd);
}
closedir(d);
return found;
}
static void usage(FILE* f, const char* prog) {
fprintf(f,
"Usage: %s [OPTIONS] -n <pattern> [-n <pattern> ...]\n"
"\n"
"Unified inhibitor daemon - bridges multiple inhibit interfaces\n"
"\n"
"Options:\n"
" -n, --name PATTERN Process cmdline substring to watch "
"(repeatable)\n"
" --what WHAT What to inhibit: idle, sleep, etc. "
"(default: idle)\n"
" --poll SECONDS Poll interval (%.1f-%.1f, default: %.1f)\n"
" -d, --daemon Run as daemon (fork to background)\n"
" -q, --quiet Suppress informational output\n"
" --ia, --inhibit-action CMD Command to run on any inhibit\n"
" --uia, --uninhibit-action CMD Command to run on any uninhibit\n"
" --sia, --screensaver-inhibit-action CMD Command for "
"screensaver inhibit\n"
" --suia, --screensaver-uninhibit-action CMD Command for "
"screensaver uninhibit\n"
" -h, --help Show this help\n"
" -v, --version Show version\n",
prog, MIN_POLL_INTERVAL, MAX_POLL_INTERVAL, DEFAULT_POLL_INTERVAL);
}
static int validate_string_param(const char* param, const char* name, size_t max_len) {
if (!param || param[0] == '\0') {
fprintf(stderr, "Error: %s cannot be empty\n", name);
return 0;
}
size_t len = strlen(param);
if (len > max_len) {
fprintf(stderr, "Error: %s too long (max %zu characters)\n", name, max_len);
return 0;
}
return 1;
}
static void* safe_realloc(void* ptr, size_t new_size) {
void* new_ptr = realloc(ptr, new_size);
if (!new_ptr && new_size > 0) {
return NULL;
}
return new_ptr;
}
static int do_daemonize(void) {
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "fork failed: %s\n", strerror(errno));
return -1;
}
if (pid > 0) {
exit(EXIT_OK);
}
if (setsid() < 0) {
fprintf(stderr, "setsid failed: %s\n", strerror(errno));
return -1;
}
signal(SIGHUP, SIG_IGN);
pid = fork();
if (pid < 0) {
fprintf(stderr, "second fork failed: %s\n", strerror(errno));
return -1;
}
if (pid > 0) {
exit(EXIT_OK);
}
if (chdir("/") < 0) {
fprintf(stderr, "chdir failed: %s\n", strerror(errno));
return -1;
}
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
int fd = open("/dev/null", O_RDWR);
if (fd >= 0) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) {
close(fd);
}
}
return 0;
}
int main(int argc, char** argv) {
double poll_interval = DEFAULT_POLL_INTERVAL;
char** patterns = NULL;
int npats = 0;
int exit_code = EXIT_OK;
int have_patterns = 0;
memset(&g_shell_config, 0, sizeof(g_shell_config));
for (int i = 1; i < argc; ++i) {
if ((strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--name") == 0)) {
if (i + 1 >= argc) {
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
usage(stderr, argv[0]);
free(patterns);
return EXIT_ARGS;
}
i++;
if (npats >= MAX_PATTERNS) {
fprintf(stderr, "Error: Too many patterns (max %d)\n", MAX_PATTERNS);
free(patterns);
return EXIT_ARGS;
}
if (!validate_string_param(argv[i], "pattern", MAX_PATTERN_LEN)) {
free(patterns);
return EXIT_ARGS;
}
char** new_patterns = safe_realloc(patterns, (size_t) (npats + 1) * sizeof(char*));
if (!new_patterns) {
fprintf(stderr, "Error: Memory allocation failed\n");
return EXIT_INIT;
}
patterns = new_patterns;
patterns[npats++] = argv[i];
have_patterns = 1;
} else if (strncmp(argv[i], "--poll=", 7U) == 0) {
char* endptr;
errno = 0;
poll_interval = strtod(argv[i] + 7, &endptr);
if (errno != 0 || *endptr != '\0' || endptr == argv[i] + 7) {
fprintf(stderr, "Error: Invalid --poll value: %s\n", argv[i] + 7);
free(patterns);
return EXIT_ARGS;
}
if (poll_interval < MIN_POLL_INTERVAL || poll_interval > MAX_POLL_INTERVAL) {
fprintf(stderr, "Error: --poll must be between %.1f and %.1f seconds\n", MIN_POLL_INTERVAL,
MAX_POLL_INTERVAL);
free(patterns);
return EXIT_ARGS;
}
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
usage(stdout, argv[0]);
free(patterns);
return EXIT_OK;
} else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
printf("sin %s (unified inhibitor daemon)\n", VERSION);
free(patterns);
return EXIT_OK;
} else if (strcmp(argv[i], "--quiet") == 0 || strcmp(argv[i], "-q") == 0) {
quiet = 1;
} else if (strcmp(argv[i], "--daemon") == 0 || strcmp(argv[i], "-d") == 0) {
daemonize = 1;
} else if (strcmp(argv[i], "--ia") == 0 || strcmp(argv[i], "--inhibit-action") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
free(patterns);
return EXIT_ARGS;
}
i++;
g_shell_config.any_inhibit = argv[i];
} else if (strcmp(argv[i], "--uia") == 0 || strcmp(argv[i], "--uninhibit-action") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
free(patterns);
return EXIT_ARGS;
}
i++;
g_shell_config.any_uninhibit = argv[i];
} else if (strcmp(argv[i], "--sia") == 0 ||
strcmp(argv[i], "--screensaver-inhibit-action") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
free(patterns);
return EXIT_ARGS;
}
i++;
g_shell_config.screensaver_inhibit = argv[i];
} else if (strcmp(argv[i], "--suia") == 0 ||
strcmp(argv[i], "--screensaver-uninhibit-action") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "Error: %s requires an argument\n", argv[i]);
free(patterns);
return EXIT_ARGS;
}
i++;
g_shell_config.screensaver_uninhibit = argv[i];
} else if (argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] != '\0') {
if (npats >= MAX_PATTERNS) {
fprintf(stderr, "Error: Too many patterns (max %d)\n", MAX_PATTERNS);
free(patterns);
return EXIT_ARGS;
}
if (!validate_string_param(argv[i] + 2, "pattern", MAX_PATTERN_LEN)) {
free(patterns);
return EXIT_ARGS;
}
char** new_patterns = safe_realloc(patterns, (size_t) (npats + 1) * sizeof(char*));
if (!new_patterns) {
fprintf(stderr, "Error: Memory allocation failed\n");
return EXIT_INIT;
}
patterns = new_patterns;
patterns[npats++] = argv[i] + 2;
have_patterns = 1;
} else {
fprintf(stderr, "Error: Unknown argument: %s\n", argv[i]);
usage(stderr, argv[0]);
free(patterns);
return EXIT_ARGS;
}
}
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handle_sig;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sa, NULL) < 0) {
fprintf(stderr, "Warning: Failed to set SIGINT handler: %s\n", strerror(errno));
}
if (sigaction(SIGTERM, &sa, NULL) < 0) {
fprintf(stderr, "Warning: Failed to set SIGTERM handler: %s\n", strerror(errno));
}
if (daemonize) {
if (do_daemonize() < 0) {
free(patterns);
return EXIT_INIT;
}
}
if (inhibit_manager_init(&g_manager) < 0) {
fprintf(stderr, "Failed to initialize inhibit manager\n");
free(patterns);
return EXIT_INIT;
}
inhibit_manager_set_callback(&g_manager, on_inhibit_event);
InhibitInterface* iface;
iface = dbus_freedesktop_screensaver_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = dbus_freedesktop_powermanager_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = dbus_gnome_session_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = dbus_gnome_screensaver_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = dbus_cinnamon_screensaver_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = dbus_mate_screensaver_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = dbus_systemd_login1_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = xidlehook_create("/tmp/xidlehook.sock");
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
iface = kernel_wakelock_create();
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
if (g_shell_config.any_inhibit || g_shell_config.any_uninhibit ||
g_shell_config.screensaver_inhibit || g_shell_config.screensaver_uninhibit) {
iface = shell_command_create(&g_shell_config);
if (iface) {
if (inhibit_manager_register(&g_manager, iface) == 0) {
if (!quiet)
fprintf(stderr, "Registered: %s\n", iface->name);
} else {
free(iface->private_data);
free(iface);
}
}
}
if (!quiet) {
fprintf(stderr, "Unified inhibitor daemon started (%d interfaces)\n", g_manager.num_interfaces);
if (have_patterns) {
fprintf(stderr, "Watching %d process pattern(s)\n", npats);
}
}
int process_inhibited = 0;
while (running) {
inhibit_manager_poll_all(&g_manager);
if (have_patterns) {
int found = any_process_running(patterns, npats);
if (found && !process_inhibited) {
if (!quiet)
fprintf(stderr, "Target process found - creating inhibit\n");
InhibitEntry entry = {.type = INHIBIT_TYPE_IDLE, .cookie = 0};
snprintf(entry.id, sizeof(entry.id), "process_watcher");
strncpy(entry.app_name, "sin-process-watcher", sizeof(entry.app_name) - 1);
strncpy(entry.reason, "Process matching pattern is running", sizeof(entry.reason) - 1);
on_inhibit_event(NULL, &entry, 1);
process_inhibited = 1;
} else if (!found && process_inhibited) {
if (!quiet)
fprintf(stderr, "Target process exited - releasing inhibit\n");
InhibitEntry entry = {.type = INHIBIT_TYPE_IDLE, .cookie = 0};
snprintf(entry.id, sizeof(entry.id), "process_watcher");
on_inhibit_event(NULL, &entry, 0);
process_inhibited = 0;
}
}
struct timespec ts;
ts.tv_sec = (time_t) poll_interval;
ts.tv_nsec = (long) ((poll_interval - (time_t) poll_interval) * 1e9);
while (nanosleep(&ts, &ts) < 0) {
if (errno != EINTR || !running)
break;
}
}
if (cleanup_requested && !quiet) {
fprintf(stderr, "Shutting down gracefully...\n");
}
inhibit_manager_cleanup(&g_manager);
free(patterns);
return exit_code;
}

179
src/shell-command.c Normal file
View file

@ -0,0 +1,179 @@
#include "shell-command.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
typedef struct {
ShellCommandConfig config;
uint32_t next_id;
} ShellCommandData;
static int execute_command(const char* cmd) {
if (!cmd || !cmd[0])
return 0;
pid_t pid = fork();
if (pid < 0) {
fprintf(stderr, "Failed to fork: %s\n", strerror(errno));
return -1;
}
if (pid == 0) {
execl("/bin/sh", "sh", "-c", cmd, NULL);
_exit(127);
}
int status;
if (waitpid(pid, &status, 0) < 0) {
fprintf(stderr, "Failed to wait for child: %s\n", strerror(errno));
return -1;
}
return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
}
static int shell_cmd_init(InhibitInterface* iface) {
(void) iface;
return 0;
}
static void shell_cmd_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
ShellCommandData* data = iface->private_data;
free(data->config.screensaver_inhibit);
free(data->config.screensaver_uninhibit);
free(data->config.suspend_inhibit);
free(data->config.suspend_uninhibit);
free(data->config.any_inhibit);
free(data->config.any_uninhibit);
}
static int shell_cmd_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) app_name;
(void) reason;
if (!iface || !iface->private_data || !out_entry)
return -1;
ShellCommandData* data = iface->private_data;
const char* cmd = NULL;
if (type & INHIBIT_TYPE_SCREENSAVER && data->config.screensaver_inhibit) {
cmd = data->config.screensaver_inhibit;
} else if (type & INHIBIT_TYPE_SUSPEND && data->config.suspend_inhibit) {
cmd = data->config.suspend_inhibit;
} else if (data->config.any_inhibit) {
cmd = data->config.any_inhibit;
}
if (cmd) {
execute_command(cmd);
}
uint32_t id = data->next_id++;
snprintf(out_entry->id, sizeof(out_entry->id), "shell_%u", id);
out_entry->cookie = id;
out_entry->type = type;
strncpy(out_entry->app_name, app_name ? app_name : "unknown", sizeof(out_entry->app_name) - 1);
strncpy(out_entry->reason, reason ? reason : "", sizeof(out_entry->reason) - 1);
return 0;
}
static int shell_cmd_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) entry;
if (!iface || !iface->private_data)
return -1;
ShellCommandData* data = iface->private_data;
const char* cmd = NULL;
if (entry->type & INHIBIT_TYPE_SCREENSAVER && data->config.screensaver_uninhibit) {
cmd = data->config.screensaver_uninhibit;
} else if (entry->type & INHIBIT_TYPE_SUSPEND && data->config.suspend_uninhibit) {
cmd = data->config.suspend_uninhibit;
} else if (data->config.any_uninhibit) {
cmd = data->config.any_uninhibit;
}
if (cmd) {
execute_command(cmd);
}
return 0;
}
static int shell_cmd_poll(InhibitInterface* iface) {
(void) iface;
return 0;
}
static void shell_cmd_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
(void) iface;
(void) cb;
}
InhibitInterface* shell_command_create(const ShellCommandConfig* config) {
if (!config)
return NULL;
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
ShellCommandData* data = calloc(1, sizeof(ShellCommandData));
if (!data) {
free(iface);
return NULL;
}
if (config->screensaver_inhibit) {
data->config.screensaver_inhibit = strdup(config->screensaver_inhibit);
}
if (config->screensaver_uninhibit) {
data->config.screensaver_uninhibit = strdup(config->screensaver_uninhibit);
}
if (config->suspend_inhibit) {
data->config.suspend_inhibit = strdup(config->suspend_inhibit);
}
if (config->suspend_uninhibit) {
data->config.suspend_uninhibit = strdup(config->suspend_uninhibit);
}
if (config->any_inhibit) {
data->config.any_inhibit = strdup(config->any_inhibit);
}
if (config->any_uninhibit) {
data->config.any_uninhibit = strdup(config->any_uninhibit);
}
iface->name = "shell-command";
iface->init = shell_cmd_init;
iface->cleanup = shell_cmd_cleanup;
iface->inhibit = shell_cmd_inhibit;
iface->uninhibit = shell_cmd_uninhibit;
iface->poll = shell_cmd_poll;
iface->set_callback = shell_cmd_set_callback;
iface->private_data = data;
return iface;
}
void shell_command_config_free(ShellCommandConfig* config) {
if (!config)
return;
free(config->screensaver_inhibit);
free(config->screensaver_uninhibit);
free(config->suspend_inhibit);
free(config->suspend_uninhibit);
free(config->any_inhibit);
free(config->any_uninhibit);
memset(config, 0, sizeof(*config));
}

146
src/xidlehook.c Normal file
View file

@ -0,0 +1,146 @@
#include "xidlehook.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
typedef struct {
char* socket_path;
int sock_fd;
uint32_t next_id;
} XidlehookData;
static int xidlehook_init(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return -1;
XidlehookData* data = iface->private_data;
data->sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (data->sock_fd < 0) {
fprintf(stderr, "Failed to create xidlehook socket: %s\n", strerror(errno));
return -1;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, data->socket_path, sizeof(addr.sun_path) - 1);
if (connect(data->sock_fd, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
fprintf(stderr, "Failed to connect to xidlehook socket at %s: %s\n", data->socket_path,
strerror(errno));
close(data->sock_fd);
data->sock_fd = -1;
return -1;
}
return 0;
}
static void xidlehook_cleanup(InhibitInterface* iface) {
if (!iface || !iface->private_data)
return;
XidlehookData* data = iface->private_data;
if (data->sock_fd >= 0) {
close(data->sock_fd);
data->sock_fd = -1;
}
}
static int xidlehook_inhibit(InhibitInterface* iface, InhibitType type, const char* app_name,
const char* reason, InhibitEntry* out_entry) {
(void) type;
(void) app_name;
(void) reason;
if (!iface || !iface->private_data || !out_entry)
return -1;
XidlehookData* data = iface->private_data;
if (data->sock_fd < 0)
return -1;
const char* cmd = "disable\n";
if (write(data->sock_fd, cmd, strlen(cmd)) < 0) {
fprintf(stderr, "Failed to send disable to xidlehook: %s\n", strerror(errno));
return -1;
}
uint32_t id = data->next_id++;
snprintf(out_entry->id, sizeof(out_entry->id), "xidlehook_%u", id);
out_entry->cookie = id;
out_entry->type = INHIBIT_TYPE_SCREENSAVER;
strncpy(out_entry->app_name, app_name ? app_name : "unknown", sizeof(out_entry->app_name) - 1);
strncpy(out_entry->reason, reason ? reason : "", sizeof(out_entry->reason) - 1);
return 0;
}
static int xidlehook_uninhibit(InhibitInterface* iface, const InhibitEntry* entry) {
(void) entry;
if (!iface || !iface->private_data)
return -1;
XidlehookData* data = iface->private_data;
if (data->sock_fd < 0)
return -1;
const char* cmd = "enable\n";
if (write(data->sock_fd, cmd, strlen(cmd)) < 0) {
fprintf(stderr, "Failed to send enable to xidlehook: %s\n", strerror(errno));
return -1;
}
return 0;
}
static int xidlehook_poll(InhibitInterface* iface) {
(void) iface;
return 0;
}
static void xidlehook_set_callback(InhibitInterface* iface, InhibitEventCallback cb) {
(void) iface;
(void) cb;
}
InhibitInterface* xidlehook_create(const char* socket_path) {
if (!socket_path)
return NULL;
InhibitInterface* iface = calloc(1, sizeof(InhibitInterface));
if (!iface)
return NULL;
XidlehookData* data = calloc(1, sizeof(XidlehookData));
if (!data) {
free(iface);
return NULL;
}
data->socket_path = strdup(socket_path);
if (!data->socket_path) {
free(data);
free(iface);
return NULL;
}
data->sock_fd = -1;
iface->name = "xidlehook";
iface->init = xidlehook_init;
iface->cleanup = xidlehook_cleanup;
iface->inhibit = xidlehook_inhibit;
iface->uninhibit = xidlehook_uninhibit;
iface->poll = xidlehook_poll;
iface->set_callback = xidlehook_set_callback;
iface->private_data = data;
return iface;
}