mirror of
https://github.com/perk11/runwhenidle.git
synced 2026-01-09 13:48:01 -05:00
Cron support
This commit is contained in:
2
Makefile
2
Makefile
@@ -1,5 +1,5 @@
|
|||||||
TARGET_EXEC := runwhenidle
|
TARGET_EXEC := runwhenidle
|
||||||
LDLIBS=-lXss -lX11 -lwayland-client -lm
|
LDLIBS=-lXss -lX11 -lwayland-client
|
||||||
CC=gcc
|
CC=gcc
|
||||||
ifeq ($(PREFIX),)
|
ifeq ($(PREFIX),)
|
||||||
PREFIX := /usr
|
PREFIX := /usr
|
||||||
|
|||||||
499
main.c
499
main.c
@@ -11,9 +11,11 @@
|
|||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/timerfd.h>
|
#include <sys/timerfd.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
|
|
||||||
#include "ext-idle-notify-v1-client-protocol.h"
|
#include "ext-idle-notify-v1-client-protocol.h"
|
||||||
|
|
||||||
#include <X11/extensions/scrnsaver.h>
|
#include <X11/extensions/scrnsaver.h>
|
||||||
@@ -56,6 +58,8 @@ volatile sig_atomic_t command_paused = 0;
|
|||||||
volatile sig_atomic_t sigchld_received = 0;
|
volatile sig_atomic_t sigchld_received = 0;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
static int invoked_from_cron = 0;
|
||||||
|
|
||||||
static struct wl_display *wayland_display = NULL;
|
static struct wl_display *wayland_display = NULL;
|
||||||
static struct wl_registry *wayland_registry = NULL;
|
static struct wl_registry *wayland_registry = NULL;
|
||||||
static struct wl_seat *wayland_seat = NULL;
|
static struct wl_seat *wayland_seat = NULL;
|
||||||
@@ -64,6 +68,335 @@ static uint32_t wayland_idle_notifier_version = 0;
|
|||||||
static struct ext_idle_notification_v1 *wayland_idle_notification = NULL;
|
static struct ext_idle_notification_v1 *wayland_idle_notification = NULL;
|
||||||
static int wayland_idle_notify_available = 0;
|
static int wayland_idle_notify_available = 0;
|
||||||
|
|
||||||
|
static int is_string_null_or_empty(const char *value) {
|
||||||
|
return value == NULL || value[0] == '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_is_socket(const char *path) {
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return S_ISSOCK(st.st_mode) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_is_readable_regular_file(const char *path) {
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!S_ISREG(st.st_mode)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return access(path, R_OK) == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int directory_exists_and_accessible(const char *path) {
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return access(path, R_OK | X_OK) == 0 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_process_status_ppid(pid_t target_pid, pid_t *out_ppid) {
|
||||||
|
char status_path[64];
|
||||||
|
snprintf(status_path, sizeof(status_path), "/proc/%d/status", target_pid);
|
||||||
|
|
||||||
|
FILE *fp = fopen(status_path, "r");
|
||||||
|
if (!fp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char line[256];
|
||||||
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
|
if (strncmp(line, "PPid:", 5) == 0) {
|
||||||
|
long parsed = strtol(line + 5, NULL, 10);
|
||||||
|
fclose(fp);
|
||||||
|
if (parsed <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*out_ppid = (pid_t)parsed;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_process_comm(pid_t target_pid, char *out_comm, size_t out_comm_size) {
|
||||||
|
char comm_path[64];
|
||||||
|
snprintf(comm_path, sizeof(comm_path), "/proc/%d/comm", target_pid);
|
||||||
|
|
||||||
|
FILE *fp = fopen(comm_path, "r");
|
||||||
|
if (!fp) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fgets(out_comm, (int)out_comm_size, fp)) {
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
out_comm[strcspn(out_comm, "\n")] = '\0';
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int comm_matches_any_cron_name(const char *comm) {
|
||||||
|
const char *cron_names[] = { "cron", "crond", "anacron", "cronie", "fcron", NULL };
|
||||||
|
for (int i = 0; cron_names[i] != NULL; i++) {
|
||||||
|
if (strcmp(comm, cron_names[i]) == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int detect_invoked_from_cron_via_process_tree(void) {
|
||||||
|
pid_t current_pid = getpid();
|
||||||
|
|
||||||
|
for (int depth = 0; depth < 12; depth++) {
|
||||||
|
pid_t parent_pid = 0;
|
||||||
|
if (!read_process_status_ppid(current_pid, &parent_pid)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (parent_pid <= 1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char comm[128];
|
||||||
|
if (read_process_comm(parent_pid, comm, sizeof(comm))) {
|
||||||
|
if (comm_matches_any_cron_name(comm)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current_pid = parent_pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_home_directory_for_current_user(char *out_home, size_t out_home_size) {
|
||||||
|
const char *home_env = getenv("HOME");
|
||||||
|
if (!is_string_null_or_empty(home_env)) {
|
||||||
|
snprintf(out_home, out_home_size, "%s", home_env);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct passwd *pw = getpwuid(getuid());
|
||||||
|
if (!pw || !pw->pw_dir) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(out_home, out_home_size, "%s", pw->pw_dir);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int build_xauthority_path_from_home_dir(char *xauthority_path,
|
||||||
|
size_t xauthority_path_size,
|
||||||
|
const char *home_dir) {
|
||||||
|
static const char xauthority_suffix[] = "/.Xauthority";
|
||||||
|
size_t home_dir_length = strnlen(home_dir, xauthority_path_size);
|
||||||
|
size_t suffix_length = sizeof(xauthority_suffix) - 1;
|
||||||
|
|
||||||
|
if (home_dir_length == 0 || home_dir_length >= xauthority_path_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (home_dir_length + suffix_length + 1 > xauthority_path_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(xauthority_path, home_dir, home_dir_length);
|
||||||
|
memcpy(xauthority_path + home_dir_length, xauthority_suffix, suffix_length + 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ensure_xauthority_is_set_if_possible(void) {
|
||||||
|
if (!is_string_null_or_empty(getenv("XAUTHORITY"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char home_dir[PATH_MAX];
|
||||||
|
if (!get_home_directory_for_current_user(home_dir, sizeof(home_dir))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char xauthority_path[PATH_MAX];
|
||||||
|
if (!build_xauthority_path_from_home_dir(xauthority_path, sizeof(xauthority_path), home_dir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_is_readable_regular_file(xauthority_path)) {
|
||||||
|
setenv("XAUTHORITY", xauthority_path, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int build_default_xdg_runtime_dir_for_current_user(char *out_runtime_dir, size_t out_runtime_dir_size) {
|
||||||
|
uid_t uid = getuid();
|
||||||
|
snprintf(out_runtime_dir, out_runtime_dir_size, "/run/user/%u", (unsigned)uid);
|
||||||
|
if (!directory_exists_and_accessible(out_runtime_dir)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_best_wayland_socket_in_runtime_dir(const char *runtime_dir,
|
||||||
|
char *out_socket_path,
|
||||||
|
size_t out_socket_path_size,
|
||||||
|
char *out_socket_name,
|
||||||
|
size_t out_socket_name_size) {
|
||||||
|
DIR *dir = opendir(runtime_dir);
|
||||||
|
if (!dir) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int found = 0;
|
||||||
|
int best_numeric_suffix = INT_MAX;
|
||||||
|
char best_name[NAME_MAX + 1];
|
||||||
|
best_name[0] = '\0';
|
||||||
|
|
||||||
|
struct dirent *entry;
|
||||||
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
|
if (strncmp(entry->d_name, "wayland-", 8) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
char full_path[PATH_MAX];
|
||||||
|
snprintf(full_path, sizeof(full_path), "%s/%s", runtime_dir, entry->d_name);
|
||||||
|
|
||||||
|
if (!file_is_socket(full_path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numeric_suffix = -1;
|
||||||
|
const char *suffix = entry->d_name + 8;
|
||||||
|
if (*suffix >= '0' && *suffix <= '9') {
|
||||||
|
numeric_suffix = (int)strtol(suffix, NULL, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
found = 1;
|
||||||
|
best_numeric_suffix = (numeric_suffix >= 0) ? numeric_suffix : INT_MAX;
|
||||||
|
snprintf(best_name, sizeof(best_name), "%s", entry->d_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numeric_suffix >= 0 && numeric_suffix < best_numeric_suffix) {
|
||||||
|
best_numeric_suffix = numeric_suffix;
|
||||||
|
snprintf(best_name, sizeof(best_name), "%s", entry->d_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (best_numeric_suffix == INT_MAX && numeric_suffix == -1) {
|
||||||
|
snprintf(best_name, sizeof(best_name), "%s", entry->d_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(out_socket_path, out_socket_path_size, "%s/%s", runtime_dir, best_name);
|
||||||
|
if (out_socket_name && out_socket_name_size > 0) {
|
||||||
|
snprintf(out_socket_name, out_socket_name_size, "%s", best_name);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_best_x11_display_from_socket_dir(char *out_display, size_t out_display_size) {
|
||||||
|
const char *x11_socket_dir = "/tmp/.X11-unix";
|
||||||
|
DIR *dir = opendir(x11_socket_dir);
|
||||||
|
if (!dir) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int found = 0;
|
||||||
|
int best_display_number = INT_MAX;
|
||||||
|
|
||||||
|
struct dirent *entry;
|
||||||
|
while ((entry = readdir(dir)) != NULL) {
|
||||||
|
if (entry->d_name[0] != 'X') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const char *digits = entry->d_name + 1;
|
||||||
|
if (*digits < '0' || *digits > '9') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int display_number = (int)strtol(digits, NULL, 10);
|
||||||
|
|
||||||
|
char socket_path[PATH_MAX];
|
||||||
|
snprintf(socket_path, sizeof(socket_path), "%s/%s", x11_socket_dir, entry->d_name);
|
||||||
|
|
||||||
|
if (!file_is_socket(socket_path)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found || display_number < best_display_number) {
|
||||||
|
found = 1;
|
||||||
|
best_display_number = display_number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(out_display, out_display_size, ":%d", best_display_number);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void best_effort_infer_graphical_session_environment_if_missing(void) {
|
||||||
|
if (!is_string_null_or_empty(getenv("WAYLAND_DISPLAY")) || !is_string_null_or_empty(getenv("DISPLAY"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char inferred_runtime_dir[PATH_MAX];
|
||||||
|
if (is_string_null_or_empty(getenv("XDG_RUNTIME_DIR"))) {
|
||||||
|
if (build_default_xdg_runtime_dir_for_current_user(inferred_runtime_dir, sizeof(inferred_runtime_dir))) {
|
||||||
|
setenv("XDG_RUNTIME_DIR", inferred_runtime_dir, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
|
||||||
|
if (!is_string_null_or_empty(runtime_dir) && is_string_null_or_empty(getenv("WAYLAND_DISPLAY"))) {
|
||||||
|
char wayland_socket_path[PATH_MAX];
|
||||||
|
char wayland_socket_name[NAME_MAX + 1];
|
||||||
|
if (find_best_wayland_socket_in_runtime_dir(runtime_dir, wayland_socket_path, sizeof(wayland_socket_path),
|
||||||
|
wayland_socket_name, sizeof(wayland_socket_name))) {
|
||||||
|
setenv("WAYLAND_DISPLAY", wayland_socket_name, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string_null_or_empty(getenv("DISPLAY"))) {
|
||||||
|
char inferred_display[32];
|
||||||
|
if (find_best_x11_display_from_socket_dir(inferred_display, sizeof(inferred_display))) {
|
||||||
|
setenv("DISPLAY", inferred_display, 0);
|
||||||
|
ensure_xauthority_is_set_if_possible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose && invoked_from_cron) {
|
||||||
|
const char *wd = getenv("WAYLAND_DISPLAY");
|
||||||
|
const char *xdg = getenv("XDG_RUNTIME_DIR");
|
||||||
|
const char *dpy = getenv("DISPLAY");
|
||||||
|
fprintf(stderr, "Detected cron context; inferred session vars: XDG_RUNTIME_DIR=%s WAYLAND_DISPLAY=%s DISPLAY=%s\n",
|
||||||
|
xdg ? xdg : "(unset)", wd ? wd : "(unset)", dpy ? dpy : "(unset)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int open_pid_file_descriptor_for_process(pid_t process_id) {
|
static int open_pid_file_descriptor_for_process(pid_t process_id) {
|
||||||
#if defined(SYS_pidfd_open)
|
#if defined(SYS_pidfd_open)
|
||||||
return (int)syscall(SYS_pidfd_open, process_id, 0);
|
return (int)syscall(SYS_pidfd_open, process_id, 0);
|
||||||
@@ -190,74 +523,6 @@ void sigchld_handler(int signum) {
|
|||||||
sigchld_received = 1;
|
sigchld_received = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
long long pause_or_resume_command_depending_on_user_activity(
|
|
||||||
long long sleep_time_ms,
|
|
||||||
unsigned long user_idle_time_ms) {
|
|
||||||
if (user_idle_time_ms >= user_idle_timeout_ms) {
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr, "Idle time: %lums, idle timeout: %lums, user is inactive\n", user_idle_time_ms,
|
|
||||||
user_idle_timeout_ms);
|
|
||||||
if (command_paused) {
|
|
||||||
sleep_time_ms = POLLING_INTERVAL_MS; //reset to default value
|
|
||||||
if (verbose) {
|
|
||||||
fprintf(stderr, "Idle time: %lums, idle timeout: %lums, resuming command\n", user_idle_time_ms,
|
|
||||||
user_idle_timeout_ms);
|
|
||||||
}
|
|
||||||
if (!quiet) {
|
|
||||||
printf("Lack of user activity detected. ");
|
|
||||||
//intentionally no new line here, resume_command will print the rest of the message.
|
|
||||||
}
|
|
||||||
resume_command_recursively(pid);
|
|
||||||
command_paused = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct timespec time_when_starting_to_pause;
|
|
||||||
int command_was_paused_this_iteration = 0;
|
|
||||||
// User is active
|
|
||||||
if (!command_paused) {
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &time_when_starting_to_pause);
|
|
||||||
if (verbose) {
|
|
||||||
fprintf(stderr, "Idle time: %lums.\n", user_idle_time_ms);
|
|
||||||
}
|
|
||||||
pause_command_recursively(pid);
|
|
||||||
if (debug) fprintf(stderr, "Command paused\n");
|
|
||||||
command_paused = 1;
|
|
||||||
command_was_paused_this_iteration = 1;
|
|
||||||
}
|
|
||||||
sleep_time_ms = user_idle_timeout_ms - user_idle_time_ms;
|
|
||||||
if (debug) fprintf(stderr, "Target sleep time: %llums\n", sleep_time_ms);
|
|
||||||
if (command_was_paused_this_iteration) {
|
|
||||||
if (debug) fprintf(stderr, "Command was paused this iteration\n");
|
|
||||||
struct timespec time_before_sleep;
|
|
||||||
clock_gettime(CLOCK_MONOTONIC, &time_before_sleep);
|
|
||||||
long long pausing_time_ms = get_elapsed_time_ms(time_when_starting_to_pause, time_before_sleep);
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr,
|
|
||||||
"Target sleep time before taking into account time it took to pause: %lldms, time it took to pause: %lldms\n",
|
|
||||||
sleep_time_ms, pausing_time_ms);
|
|
||||||
sleep_time_ms = sleep_time_ms - pausing_time_ms;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sleep_time_ms < POLLING_INTERVAL_MS) {
|
|
||||||
if (debug)
|
|
||||||
fprintf(stderr,
|
|
||||||
"Target sleep time %lldms is less than polling interval %lldms, resetting it to polling interval\n",
|
|
||||||
sleep_time_ms, POLLING_INTERVAL_MS);
|
|
||||||
sleep_time_ms = POLLING_INTERVAL_MS;
|
|
||||||
}
|
|
||||||
if (verbose) {
|
|
||||||
fprintf(
|
|
||||||
stderr,
|
|
||||||
"Polling every second is temporarily disabled due to user activity, idle time: %lums, next activity check scheduled in %lldms\n",
|
|
||||||
user_idle_time_ms,
|
|
||||||
sleep_time_ms
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sleep_time_ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void wayland_idle_notification_idled(void *data, struct ext_idle_notification_v1 *notification) {
|
static void wayland_idle_notification_idled(void *data, struct ext_idle_notification_v1 *notification) {
|
||||||
(void)data;
|
(void)data;
|
||||||
(void)notification;
|
(void)notification;
|
||||||
@@ -341,8 +606,45 @@ static const struct wl_registry_listener wayland_registry_listener = {
|
|||||||
.global_remove = wayland_registry_global_remove
|
.global_remove = wayland_registry_global_remove
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct wl_display *connect_to_wayland_best_effort(void) {
|
||||||
|
struct wl_display *display = wl_display_connect(NULL);
|
||||||
|
if (display) {
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
|
||||||
|
char inferred_runtime_dir[PATH_MAX];
|
||||||
|
if (is_string_null_or_empty(runtime_dir)) {
|
||||||
|
if (!build_default_xdg_runtime_dir_for_current_user(inferred_runtime_dir, sizeof(inferred_runtime_dir))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
runtime_dir = inferred_runtime_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
char wayland_socket_path[PATH_MAX];
|
||||||
|
char wayland_socket_name[NAME_MAX + 1];
|
||||||
|
if (!find_best_wayland_socket_in_runtime_dir(runtime_dir, wayland_socket_path, sizeof(wayland_socket_path),
|
||||||
|
wayland_socket_name, sizeof(wayland_socket_name))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
display = wl_display_connect(wayland_socket_path);
|
||||||
|
if (!display) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string_null_or_empty(getenv("XDG_RUNTIME_DIR"))) {
|
||||||
|
setenv("XDG_RUNTIME_DIR", runtime_dir, 0);
|
||||||
|
}
|
||||||
|
if (is_string_null_or_empty(getenv("WAYLAND_DISPLAY"))) {
|
||||||
|
setenv("WAYLAND_DISPLAY", wayland_socket_name, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
static int try_initialize_wayland_idle_backend(void) {
|
static int try_initialize_wayland_idle_backend(void) {
|
||||||
wayland_display = wl_display_connect(NULL);
|
wayland_display = connect_to_wayland_best_effort();
|
||||||
if (!wayland_display) {
|
if (!wayland_display) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -358,10 +660,8 @@ static int try_initialize_wayland_idle_backend(void) {
|
|||||||
wl_display_roundtrip(wayland_display);
|
wl_display_roundtrip(wayland_display);
|
||||||
|
|
||||||
if (wayland_seat == NULL || wayland_idle_notifier == NULL) {
|
if (wayland_seat == NULL || wayland_idle_notifier == NULL) {
|
||||||
if (wayland_registry) {
|
wl_registry_destroy(wayland_registry);
|
||||||
wl_registry_destroy(wayland_registry);
|
wayland_registry = NULL;
|
||||||
wayland_registry = NULL;
|
|
||||||
}
|
|
||||||
wl_display_disconnect(wayland_display);
|
wl_display_disconnect(wayland_display);
|
||||||
wayland_display = NULL;
|
wayland_display = NULL;
|
||||||
wayland_seat = NULL;
|
wayland_seat = NULL;
|
||||||
@@ -431,10 +731,6 @@ static int run_wayland_idle_event_loop(void) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
fprintf(stderr, "Wayland backend: waiting for idle notifications\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (interruption_received) {
|
if (interruption_received) {
|
||||||
if (start_monitor_timer_file_descriptor >= 0) close(start_monitor_timer_file_descriptor);
|
if (start_monitor_timer_file_descriptor >= 0) close(start_monitor_timer_file_descriptor);
|
||||||
@@ -464,10 +760,6 @@ static int run_wayland_idle_event_loop(void) {
|
|||||||
consume_timer_file_descriptor(start_monitor_timer_file_descriptor);
|
consume_timer_file_descriptor(start_monitor_timer_file_descriptor);
|
||||||
monitoring_started = 1;
|
monitoring_started = 1;
|
||||||
|
|
||||||
if (verbose) {
|
|
||||||
fprintf(stderr, "Starting to monitor user activity (Wayland ext-idle-notify-v1)\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start_wayland_idle_notification_object() < 0) {
|
if (start_wayland_idle_notification_object() < 0) {
|
||||||
fprintf_error("Failed to create Wayland idle notification object, user will be considered idle.\n");
|
fprintf_error("Failed to create Wayland idle notification object, user will be considered idle.\n");
|
||||||
} else {
|
} else {
|
||||||
@@ -517,9 +809,31 @@ static int run_wayland_idle_event_loop(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Display *open_x11_display_best_effort(void) {
|
||||||
|
Display *display = XOpenDisplay(NULL);
|
||||||
|
if (display) {
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_string_null_or_empty(getenv("DISPLAY"))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char inferred_display[32];
|
||||||
|
if (!find_best_x11_display_from_socket_dir(inferred_display, sizeof(inferred_display))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
setenv("DISPLAY", inferred_display, 0);
|
||||||
|
ensure_xauthority_is_set_if_possible();
|
||||||
|
return XOpenDisplay(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
parse_command_line_arguments(argc, argv);
|
parse_command_line_arguments(argc, argv);
|
||||||
|
|
||||||
|
invoked_from_cron = detect_invoked_from_cron_via_process_tree();
|
||||||
|
|
||||||
if (external_pid == 0) {
|
if (external_pid == 0) {
|
||||||
pid = run_shell_command(shell_command_to_run);
|
pid = run_shell_command(shell_command_to_run);
|
||||||
} else {
|
} else {
|
||||||
@@ -535,6 +849,8 @@ int main(int argc, char *argv[]) {
|
|||||||
signal(SIGTERM, sigterm_handler);
|
signal(SIGTERM, sigterm_handler);
|
||||||
signal(SIGCHLD, sigchld_handler);
|
signal(SIGCHLD, sigchld_handler);
|
||||||
|
|
||||||
|
best_effort_infer_graphical_session_environment_if_missing();
|
||||||
|
|
||||||
if (try_initialize_wayland_idle_backend()) {
|
if (try_initialize_wayland_idle_backend()) {
|
||||||
int wayland_loop_result = run_wayland_idle_event_loop();
|
int wayland_loop_result = run_wayland_idle_event_loop();
|
||||||
|
|
||||||
@@ -562,7 +878,7 @@ int main(int argc, char *argv[]) {
|
|||||||
return wayland_loop_result;
|
return wayland_loop_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
x_display = XOpenDisplay(NULL);
|
x_display = open_x11_display_best_effort();
|
||||||
if (!x_display) {
|
if (!x_display) {
|
||||||
xscreensaver_is_available = 0;
|
xscreensaver_is_available = 0;
|
||||||
fprintf_error("Couldn't open an X11 display!\n");
|
fprintf_error("Couldn't open an X11 display!\n");
|
||||||
@@ -615,9 +931,20 @@ int main(int argc, char *argv[]) {
|
|||||||
exit_if_pid_has_finished(pid);
|
exit_if_pid_has_finished(pid);
|
||||||
|
|
||||||
if (monitoring_started) {
|
if (monitoring_started) {
|
||||||
sleep_time_ms = pause_or_resume_command_depending_on_user_activity(
|
if (user_idle_time_ms >= user_idle_timeout_ms) {
|
||||||
sleep_time_ms,
|
if (command_paused) {
|
||||||
user_idle_time_ms);
|
if (!quiet) {
|
||||||
|
printf("Lack of user activity detected. ");
|
||||||
|
}
|
||||||
|
resume_command_recursively(pid);
|
||||||
|
command_paused = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!command_paused) {
|
||||||
|
pause_command_recursively(pid);
|
||||||
|
command_paused = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (debug) fprintf(stderr, "Sleeping for %lldms\n", sleep_time_ms);
|
if (debug) fprintf(stderr, "Sleeping for %lldms\n", sleep_time_ms);
|
||||||
sleep_for_milliseconds(sleep_time_ms);
|
sleep_for_milliseconds(sleep_time_ms);
|
||||||
|
|||||||
Reference in New Issue
Block a user