initial commit
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I6a6a6964ee9e6ebe436ca8328c6e4a7ec7c9d8d4
This commit is contained in:
commit
fcc080871a
11 changed files with 12536 additions and 0 deletions
238
src/main.c
Normal file
238
src/main.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../include/chroma.h"
|
||||
|
||||
/* Global state for signal handling */
|
||||
volatile sig_atomic_t chroma_should_quit = 0;
|
||||
|
||||
static void print_usage(const char *program_name) {
|
||||
printf("Usage: %s [OPTIONS]\n", program_name);
|
||||
printf("Minimal Wayland Multi-Monitor Wallpaper Daemon\n\n");
|
||||
printf("Options:\n");
|
||||
printf(" -c, --config FILE Configuration file path\n");
|
||||
printf(" -d, --daemon Run as daemon\n");
|
||||
printf(" -v, --verbose Verbose logging\n");
|
||||
printf(" -h, --help Show this help\n");
|
||||
printf(" --version Show version information\n");
|
||||
printf("\nExamples:\n");
|
||||
printf(" %s -c ~/.config/chroma/chroma.conf\n", program_name);
|
||||
printf(" %s --daemon\n", program_name);
|
||||
}
|
||||
|
||||
static void print_version(void) {
|
||||
printf("chroma %s\n", CHROMA_VERSION);
|
||||
printf("Minimal Wayland Multi-Monitor Wallpaper Daemon\n");
|
||||
}
|
||||
|
||||
static void signal_handler(int sig) {
|
||||
switch (sig) {
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
chroma_should_quit = 1;
|
||||
break;
|
||||
case SIGHUP:
|
||||
// TODO: Implement config reload
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int setup_signals(void) {
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
|
||||
if (sigaction(SIGTERM, &sa, NULL) == -1) {
|
||||
perror("sigaction(SIGTERM)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sigaction(SIGINT, &sa, NULL) == -1) {
|
||||
perror("sigaction(SIGINT)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sigaction(SIGHUP, &sa, NULL) == -1) {
|
||||
perror("sigaction(SIGHUP)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int daemonize(void) {
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
// Parent process exits
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Child process continues
|
||||
if (setsid() < 0) {
|
||||
perror("setsid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Change working directory to root
|
||||
if (chdir("/") < 0) {
|
||||
perror("chdir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Close standard file descriptors
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *get_default_config_path(void) {
|
||||
static char config_path[MAX_PATH_LEN];
|
||||
const char *home = getenv("HOME");
|
||||
const char *xdg_config = getenv("XDG_CONFIG_HOME");
|
||||
|
||||
if (xdg_config) {
|
||||
snprintf(config_path, sizeof(config_path), "%s/chroma/%s", xdg_config,
|
||||
CONFIG_FILE_NAME);
|
||||
} else if (home) {
|
||||
snprintf(config_path, sizeof(config_path), "%s/.config/chroma/%s", home,
|
||||
CONFIG_FILE_NAME);
|
||||
} else {
|
||||
strcpy(config_path, CONFIG_FILE_NAME);
|
||||
}
|
||||
|
||||
return config_path;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
chroma_state_t state;
|
||||
char *config_file = NULL;
|
||||
bool daemon_mode = false;
|
||||
bool verbose = false;
|
||||
int opt;
|
||||
int ret = 0;
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"config", required_argument, 0, 'c'}, {"daemon", no_argument, 0, 'd'},
|
||||
{"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'}, {0, 0, 0, 0}};
|
||||
|
||||
// Parse command line arguments
|
||||
while ((opt = getopt_long(argc, argv, "c:dvhV", long_options, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
config_file = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
daemon_mode = true;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
return 0;
|
||||
case 'V':
|
||||
print_version();
|
||||
return 0;
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize state
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.config.daemon_mode = daemon_mode;
|
||||
|
||||
// Set log level based on verbose flag
|
||||
if (verbose) {
|
||||
chroma_set_log_level(1); // Enable debug logging
|
||||
}
|
||||
|
||||
// Set up signal handlers
|
||||
if (setup_signals() != 0) {
|
||||
fprintf(stderr, "Failed to set up signal handlers\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load configuration
|
||||
if (!config_file) {
|
||||
config_file = get_default_config_path();
|
||||
}
|
||||
|
||||
// Daemonize if requested
|
||||
if (daemon_mode) {
|
||||
chroma_log("INFO", "Starting daemon mode");
|
||||
if (daemonize() != 0) {
|
||||
fprintf(stderr, "Failed to daemonize\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize chroma
|
||||
chroma_log("INFO", "Initializing chroma wallpaper daemon v%s",
|
||||
CHROMA_VERSION);
|
||||
ret = chroma_init(&state);
|
||||
if (ret != CHROMA_OK) {
|
||||
chroma_log("ERROR", "Failed to initialize chroma: %s",
|
||||
chroma_error_string(ret));
|
||||
chroma_cleanup(&state);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load configuration
|
||||
chroma_log("INFO", "Loading configuration from: %s", config_file);
|
||||
if (chroma_config_load(&state.config, config_file) != CHROMA_OK) {
|
||||
chroma_log("WARN", "Failed to load config file, using defaults");
|
||||
// Continue with default configuration
|
||||
}
|
||||
|
||||
// Connect to Wayland
|
||||
ret = chroma_wayland_connect(&state);
|
||||
if (ret != CHROMA_OK) {
|
||||
chroma_log("ERROR", "Failed to connect to Wayland: %s",
|
||||
chroma_error_string(ret));
|
||||
chroma_cleanup(&state);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize EGL
|
||||
ret = chroma_egl_init(&state);
|
||||
if (ret != CHROMA_OK) {
|
||||
chroma_log("ERROR", "Failed to initialize EGL: %s",
|
||||
chroma_error_string(ret));
|
||||
chroma_cleanup(&state);
|
||||
return 1;
|
||||
}
|
||||
|
||||
chroma_log("INFO", "Chroma daemon initialized successfully");
|
||||
|
||||
// Main event loop
|
||||
ret = chroma_run(&state);
|
||||
if (ret != CHROMA_OK) {
|
||||
chroma_log("ERROR", "Main loop failed: %s", chroma_error_string(ret));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
chroma_log("INFO", "Shutting down chroma daemon");
|
||||
chroma_cleanup(&state);
|
||||
|
||||
return (ret == CHROMA_OK) ? 0 : 1;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue