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:
parent
c89f4b5d02
commit
087f28d726
22 changed files with 2494 additions and 0 deletions
8
include/dbus-cinnamon-screensaver.h
Normal file
8
include/dbus-cinnamon-screensaver.h
Normal 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
40
include/dbus-common.h
Normal 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
|
||||
8
include/dbus-freedesktop-powermanager.h
Normal file
8
include/dbus-freedesktop-powermanager.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef DBUS_POWERMANAGER_H
|
||||
#define DBUS_POWERMANAGER_H
|
||||
|
||||
#include "inhibit-interface.h"
|
||||
|
||||
InhibitInterface *dbus_freedesktop_powermanager_create(void);
|
||||
|
||||
#endif
|
||||
9
include/dbus-freedesktop-screensaver.h
Normal file
9
include/dbus-freedesktop-screensaver.h
Normal 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
|
||||
8
include/dbus-gnome-screensaver.h
Normal file
8
include/dbus-gnome-screensaver.h
Normal 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
|
||||
8
include/dbus-gnome-session.h
Normal file
8
include/dbus-gnome-session.h
Normal 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
|
||||
8
include/dbus-mate-screensaver.h
Normal file
8
include/dbus-mate-screensaver.h
Normal 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
|
||||
8
include/dbus-systemd-login1.h
Normal file
8
include/dbus-systemd-login1.h
Normal 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
103
include/inhibit-interface.h
Normal 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
|
||||
8
include/kernel-wakelock.h
Normal file
8
include/kernel-wakelock.h
Normal 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
18
include/shell-command.h
Normal 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
8
include/xidlehook.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef XIDLEHOOK_H
|
||||
#define XIDLEHOOK_H
|
||||
|
||||
#include "inhibit-interface.h"
|
||||
|
||||
InhibitInterface *xidlehook_create(const char *socket_path);
|
||||
|
||||
#endif
|
||||
192
src/dbus-cinnamon-screensaver.c
Normal file
192
src/dbus-cinnamon-screensaver.c
Normal 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;
|
||||
}
|
||||
192
src/dbus-freedesktop-powermanager.c
Normal file
192
src/dbus-freedesktop-powermanager.c
Normal 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;
|
||||
}
|
||||
198
src/dbus-freedesktop-screensaver.c
Normal file
198
src/dbus-freedesktop-screensaver.c
Normal 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;
|
||||
}
|
||||
201
src/dbus-gnome-screensaver.c
Normal file
201
src/dbus-gnome-screensaver.c
Normal 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
195
src/dbus-gnome-session.c
Normal 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
192
src/dbus-mate-screensaver.c
Normal 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
128
src/kernel-wakelock.c
Normal 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
637
src/main.c
Normal 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
179
src/shell-command.c
Normal 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
146
src/xidlehook.c
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue