various: log memory events
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I6a6a69643b6d00277bb9bcfeb4cd01dc78d7cd3d
This commit is contained in:
parent
0bc2decb7c
commit
bc77b887ad
7 changed files with 280 additions and 47 deletions
15
include/chroma.h
vendored
15
include/chroma.h
vendored
|
@ -17,6 +17,13 @@
|
||||||
#define MAX_PATH_LEN 4096
|
#define MAX_PATH_LEN 4096
|
||||||
#define CONFIG_FILE_NAME "chroma.conf"
|
#define CONFIG_FILE_NAME "chroma.conf"
|
||||||
|
|
||||||
|
// Log levels
|
||||||
|
#define CHROMA_LOG_ERROR 0
|
||||||
|
#define CHROMA_LOG_WARN 1
|
||||||
|
#define CHROMA_LOG_INFO 2
|
||||||
|
#define CHROMA_LOG_DEBUG 3
|
||||||
|
#define CHROMA_LOG_TRACE 4
|
||||||
|
|
||||||
// Error codes
|
// Error codes
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CHROMA_OK = 0,
|
CHROMA_OK = 0,
|
||||||
|
@ -219,6 +226,14 @@ void chroma_sleep_ms(long ms);
|
||||||
void chroma_format_memory_size(size_t bytes, char *buffer, size_t buffer_size);
|
void chroma_format_memory_size(size_t bytes, char *buffer, size_t buffer_size);
|
||||||
void chroma_utils_cleanup(void);
|
void chroma_utils_cleanup(void);
|
||||||
|
|
||||||
|
// Memory tracking and logging
|
||||||
|
void chroma_log_memory_stats(const char *context);
|
||||||
|
size_t chroma_get_memory_usage(void);
|
||||||
|
void chroma_log_resource_allocation(const char *resource_type, size_t size,
|
||||||
|
const char *description);
|
||||||
|
void chroma_log_resource_deallocation(const char *resource_type, size_t size,
|
||||||
|
const char *description);
|
||||||
|
|
||||||
// Listener structures
|
// Listener structures
|
||||||
extern const struct wl_registry_listener chroma_registry_listener_impl;
|
extern const struct wl_registry_listener chroma_registry_listener_impl;
|
||||||
extern const struct wl_output_listener chroma_output_listener_impl;
|
extern const struct wl_output_listener chroma_output_listener_impl;
|
||||||
|
|
34
src/config.c
34
src/config.c
|
@ -78,6 +78,9 @@ static int add_output_mapping(chroma_config_t *config, const char *output_name,
|
||||||
config->mapping_count++;
|
config->mapping_count++;
|
||||||
|
|
||||||
chroma_log("DEBUG", "Added mapping: %s -> %s", output_name, image_path);
|
chroma_log("DEBUG", "Added mapping: %s -> %s", output_name, image_path);
|
||||||
|
chroma_log("TRACE", "Output mapping %d: '%s' -> '%s' (path length: %zu)",
|
||||||
|
config->mapping_count, output_name, image_path,
|
||||||
|
strlen(image_path));
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,11 +141,16 @@ static int parse_config_line(chroma_config_t *config, char *line,
|
||||||
strncpy(config->default_image, value, sizeof(config->default_image) - 1);
|
strncpy(config->default_image, value, sizeof(config->default_image) - 1);
|
||||||
config->default_image[sizeof(config->default_image) - 1] = '\0';
|
config->default_image[sizeof(config->default_image) - 1] = '\0';
|
||||||
chroma_log("DEBUG", "Set default image: %s", value);
|
chroma_log("DEBUG", "Set default image: %s", value);
|
||||||
|
chroma_log("TRACE", "Default image path set: length=%zu, expanded='%s'",
|
||||||
|
strlen(value), value);
|
||||||
} else if (strcasecmp(key, "daemon") == 0 ||
|
} else if (strcasecmp(key, "daemon") == 0 ||
|
||||||
strcasecmp(key, "daemon_mode") == 0) {
|
strcasecmp(key, "daemon_mode") == 0) {
|
||||||
config->daemon_mode = parse_bool(value);
|
config->daemon_mode = parse_bool(value);
|
||||||
chroma_log("DEBUG", "Set daemon mode: %s",
|
chroma_log("DEBUG", "Set daemon mode: %s",
|
||||||
config->daemon_mode ? "true" : "false");
|
config->daemon_mode ? "true" : "false");
|
||||||
|
chroma_log("TRACE",
|
||||||
|
"Daemon mode configuration: key='%s', value='%s', parsed=%s",
|
||||||
|
key, value, config->daemon_mode ? "true" : "false");
|
||||||
} else if (strncasecmp(key, "output.", 7) == 0) {
|
} else if (strncasecmp(key, "output.", 7) == 0) {
|
||||||
// Output-specific mapping: e.g., output.DP-1=/path/to/image.jpg
|
// Output-specific mapping: e.g., output.DP-1=/path/to/image.jpg
|
||||||
const char *output_name = key + 7;
|
const char *output_name = key + 7;
|
||||||
|
@ -167,6 +175,8 @@ static int parse_config_line(chroma_config_t *config, char *line,
|
||||||
} else {
|
} else {
|
||||||
chroma_log("WARN", "Unknown configuration key line %d: %s", line_number,
|
chroma_log("WARN", "Unknown configuration key line %d: %s", line_number,
|
||||||
key);
|
key);
|
||||||
|
chroma_log("TRACE", "Unrecognized config line %d: key='%s', value='%s'",
|
||||||
|
line_number, key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
|
@ -200,6 +210,9 @@ int chroma_config_load(chroma_config_t *config, const char *config_file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
chroma_log("INFO", "Loading configuration from: %s", config_file);
|
chroma_log("INFO", "Loading configuration from: %s", config_file);
|
||||||
|
chroma_log("TRACE",
|
||||||
|
"Starting configuration parsing, estimated config size: %ld bytes",
|
||||||
|
chroma_get_file_size(config_file));
|
||||||
|
|
||||||
char line[1024];
|
char line[1024];
|
||||||
int line_number = 0;
|
int line_number = 0;
|
||||||
|
@ -229,6 +242,14 @@ int chroma_config_load(chroma_config_t *config, const char *config_file) {
|
||||||
"Loaded configuration: %d output mappings, default image: %s",
|
"Loaded configuration: %d output mappings, default image: %s",
|
||||||
config->mapping_count, config->default_image);
|
config->mapping_count, config->default_image);
|
||||||
|
|
||||||
|
// Log configuration memory usage
|
||||||
|
size_t config_size =
|
||||||
|
sizeof(chroma_config_t) +
|
||||||
|
(config->mapping_count * sizeof(chroma_config_mapping_t));
|
||||||
|
chroma_log_resource_allocation("config_data", config_size,
|
||||||
|
"configuration structure");
|
||||||
|
chroma_log_memory_stats("post-config-load");
|
||||||
|
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,6 +259,15 @@ void chroma_config_free(chroma_config_t *config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log configuration deallocation
|
||||||
|
size_t config_size =
|
||||||
|
sizeof(chroma_config_t) +
|
||||||
|
(config->mapping_count * sizeof(chroma_config_mapping_t));
|
||||||
|
chroma_log_resource_deallocation("config_data", config_size,
|
||||||
|
"configuration structure");
|
||||||
|
|
||||||
|
chroma_log("TRACE", "Clearing %d output mappings from configuration",
|
||||||
|
config->mapping_count);
|
||||||
memset(config->mappings, 0, sizeof(config->mappings));
|
memset(config->mappings, 0, sizeof(config->mappings));
|
||||||
config->mapping_count = 0;
|
config->mapping_count = 0;
|
||||||
|
|
||||||
|
@ -321,6 +351,10 @@ void chroma_config_print(const chroma_config_t *config) {
|
||||||
for (int i = 0; i < config->mapping_count; i++) {
|
for (int i = 0; i < config->mapping_count; i++) {
|
||||||
chroma_log("INFO", " %s -> %s", config->mappings[i].output_name,
|
chroma_log("INFO", " %s -> %s", config->mappings[i].output_name,
|
||||||
config->mappings[i].image_path);
|
config->mappings[i].image_path);
|
||||||
|
chroma_log(
|
||||||
|
"TRACE", " Mapping %d: output='%s', image='%s', path_exists=%s", i,
|
||||||
|
config->mappings[i].output_name, config->mappings[i].image_path,
|
||||||
|
chroma_path_exists(config->mappings[i].image_path) ? "yes" : "no");
|
||||||
}
|
}
|
||||||
chroma_log("INFO", "====================");
|
chroma_log("INFO", "====================");
|
||||||
}
|
}
|
||||||
|
|
116
src/core.c
116
src/core.c
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
#include "../include/chroma.h"
|
#include "../include/chroma.h"
|
||||||
|
|
||||||
// Global logging level
|
// Global logging level (using CHROMA_LOG_* constants)
|
||||||
static int log_level = 0; // 0=ERROR, 1=WARN, 2=INFO, 3=DEBUG
|
static int log_level = CHROMA_LOG_WARN; // Default to WARN and ERROR only
|
||||||
|
|
||||||
// Initialize chroma state
|
// Initialize chroma state
|
||||||
int chroma_init(chroma_state_t *state) {
|
int chroma_init(chroma_state_t *state) {
|
||||||
|
@ -32,6 +32,8 @@ int chroma_init(chroma_state_t *state) {
|
||||||
|
|
||||||
state->initialized = true;
|
state->initialized = true;
|
||||||
chroma_log("INFO", "Chroma state initialized");
|
chroma_log("INFO", "Chroma state initialized");
|
||||||
|
chroma_log_resource_allocation("chroma_state", sizeof(chroma_state_t),
|
||||||
|
"main application state");
|
||||||
|
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +45,7 @@ void chroma_cleanup(chroma_state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
chroma_log("INFO", "Cleaning up chroma state");
|
chroma_log("INFO", "Cleaning up chroma state");
|
||||||
|
chroma_log_memory_stats("pre-cleanup");
|
||||||
|
|
||||||
// Stop the main loop
|
// Stop the main loop
|
||||||
state->running = false;
|
state->running = false;
|
||||||
|
@ -60,6 +63,8 @@ void chroma_cleanup(chroma_state_t *state) {
|
||||||
chroma_config_free(&state->config);
|
chroma_config_free(&state->config);
|
||||||
|
|
||||||
state->initialized = false;
|
state->initialized = false;
|
||||||
|
chroma_log_resource_deallocation("chroma_state", sizeof(chroma_state_t),
|
||||||
|
"main application state");
|
||||||
chroma_log("INFO", "Chroma cleanup complete");
|
chroma_log("INFO", "Chroma cleanup complete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +121,7 @@ static int assign_wallpaper_to_output(chroma_state_t *state,
|
||||||
|
|
||||||
chroma_log("INFO", "Assigned wallpaper to output %u (%s): %s", output->id,
|
chroma_log("INFO", "Assigned wallpaper to output %u (%s): %s", output->id,
|
||||||
output->name ? output->name : "unknown", image_path);
|
output->name ? output->name : "unknown", image_path);
|
||||||
|
chroma_log_memory_stats("post-wallpaper-assignment");
|
||||||
|
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
}
|
}
|
||||||
|
@ -173,20 +179,20 @@ static int process_wayland_events(chroma_state_t *state) {
|
||||||
return CHROMA_ERROR_WAYLAND;
|
return CHROMA_ERROR_WAYLAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dispatch pending events */
|
// Dispatch pending events
|
||||||
if (wl_display_dispatch_pending(state->display) == -1) {
|
if (wl_display_dispatch_pending(state->display) == -1) {
|
||||||
chroma_log("ERROR", "Failed to dispatch pending Wayland events: %s",
|
chroma_log("ERROR", "Failed to dispatch pending Wayland events: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return CHROMA_ERROR_WAYLAND;
|
return CHROMA_ERROR_WAYLAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read events from the server */
|
// Read events from the server
|
||||||
if (wl_display_read_events(state->display) == -1) {
|
if (wl_display_read_events(state->display) == -1) {
|
||||||
chroma_log("ERROR", "Failed to read Wayland events: %s", strerror(errno));
|
chroma_log("ERROR", "Failed to read Wayland events: %s", strerror(errno));
|
||||||
return CHROMA_ERROR_WAYLAND;
|
return CHROMA_ERROR_WAYLAND;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dispatch the read events */
|
// Dispatch the read events
|
||||||
if (wl_display_dispatch_pending(state->display) == -1) {
|
if (wl_display_dispatch_pending(state->display) == -1) {
|
||||||
chroma_log("ERROR", "Failed to dispatch read Wayland events: %s",
|
chroma_log("ERROR", "Failed to dispatch read Wayland events: %s",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
@ -203,6 +209,7 @@ int chroma_run(chroma_state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
chroma_log("INFO", "Starting main event loop");
|
chroma_log("INFO", "Starting main event loop");
|
||||||
|
chroma_log_memory_stats("main-loop-start");
|
||||||
state->running = true;
|
state->running = true;
|
||||||
|
|
||||||
// Initial wallpaper assignment
|
// Initial wallpaper assignment
|
||||||
|
@ -247,7 +254,7 @@ int chroma_run(chroma_state_t *state) {
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_SET(fd, &readfds);
|
FD_SET(fd, &readfds);
|
||||||
|
|
||||||
timeout.tv_sec = 1; // 1 second timeout
|
timeout.tv_sec = 1; // 1s timeout
|
||||||
timeout.tv_usec = 0;
|
timeout.tv_usec = 0;
|
||||||
|
|
||||||
int select_result = select(fd + 1, &readfds, NULL, NULL, &timeout);
|
int select_result = select(fd + 1, &readfds, NULL, NULL, &timeout);
|
||||||
|
@ -307,24 +314,41 @@ const char *chroma_error_string(chroma_error_t error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging function
|
// Convert log level string to numeric level
|
||||||
|
static int log_level_from_string(const char *level) {
|
||||||
|
if (strcmp(level, "ERROR") == 0)
|
||||||
|
return CHROMA_LOG_ERROR;
|
||||||
|
if (strcmp(level, "WARN") == 0)
|
||||||
|
return CHROMA_LOG_WARN;
|
||||||
|
if (strcmp(level, "INFO") == 0)
|
||||||
|
return CHROMA_LOG_INFO;
|
||||||
|
if (strcmp(level, "DEBUG") == 0)
|
||||||
|
return CHROMA_LOG_DEBUG;
|
||||||
|
if (strcmp(level, "TRACE") == 0)
|
||||||
|
return CHROMA_LOG_TRACE;
|
||||||
|
return CHROMA_LOG_ERROR; // default to ERROR for unknown levels
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logging function with level filtering
|
||||||
void chroma_log(const char *level, const char *format, ...) {
|
void chroma_log(const char *level, const char *format, ...) {
|
||||||
|
int msg_level = log_level_from_string(level);
|
||||||
|
if (msg_level > log_level) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
char timestamp[32];
|
char timestamp[32];
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct tm *tm_info;
|
struct tm *tm_info;
|
||||||
|
|
||||||
// Get current time
|
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
tm_info = localtime(&tv.tv_sec);
|
tm_info = localtime(&tv.tv_sec);
|
||||||
|
|
||||||
// Format timestamp
|
|
||||||
snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
|
snprintf(timestamp, sizeof(timestamp), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
|
||||||
tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
|
tm_info->tm_year + 1900, tm_info->tm_mon + 1, tm_info->tm_mday,
|
||||||
tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec,
|
tm_info->tm_hour, tm_info->tm_min, tm_info->tm_sec,
|
||||||
(int)(tv.tv_usec / 1000));
|
(int)(tv.tv_usec / 1000));
|
||||||
|
|
||||||
// Print log message
|
|
||||||
printf("[%s] %s: ", timestamp, level);
|
printf("[%s] %s: ", timestamp, level);
|
||||||
|
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
@ -445,3 +469,75 @@ void chroma_get_stats(chroma_state_t *state, int *active_outputs,
|
||||||
if (loaded_images)
|
if (loaded_images)
|
||||||
*loaded_images = loaded;
|
*loaded_images = loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get current memory usage from /proc/self/status
|
||||||
|
// FIXME: some users may choose to confine /proc, we need a cleaner
|
||||||
|
// way of getting this data in the future
|
||||||
|
size_t chroma_get_memory_usage(void) {
|
||||||
|
FILE *file = fopen("/proc/self/status", "r");
|
||||||
|
if (!file) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t vm_rss = 0;
|
||||||
|
char line[256];
|
||||||
|
|
||||||
|
while (fgets(line, sizeof(line), file)) {
|
||||||
|
if (strncmp(line, "VmRSS:", 6) == 0) {
|
||||||
|
// Parse VmRSS line: "VmRSS: 1234 kB"
|
||||||
|
char *ptr = line + 6;
|
||||||
|
while (*ptr == ' ' || *ptr == '\t')
|
||||||
|
ptr++; // Skip whitespace
|
||||||
|
vm_rss = (size_t)strtoul(ptr, NULL, 10) * 1024; // Convert kB to bytes
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return vm_rss;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log memory statistics with context
|
||||||
|
void chroma_log_memory_stats(const char *context) {
|
||||||
|
size_t memory_usage = chroma_get_memory_usage();
|
||||||
|
char mem_str[64];
|
||||||
|
|
||||||
|
chroma_format_memory_size(memory_usage, mem_str, sizeof(mem_str));
|
||||||
|
chroma_log("INFO", "Memory usage [%s]: %s", context, mem_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log resource allocation
|
||||||
|
void chroma_log_resource_allocation(const char *resource_type, size_t size,
|
||||||
|
const char *description) {
|
||||||
|
if (size > 0) {
|
||||||
|
char size_str[64];
|
||||||
|
chroma_format_memory_size(size, size_str, sizeof(size_str));
|
||||||
|
chroma_log("DEBUG", "Allocated %s: %s (%s)", resource_type, size_str,
|
||||||
|
description);
|
||||||
|
} else {
|
||||||
|
chroma_log("DEBUG", "Allocated %s: %s", resource_type, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log memory stats after significant allocations (>1MB)
|
||||||
|
if (size > 1024 * 1024) {
|
||||||
|
chroma_log_memory_stats("post-allocation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log resource deallocation
|
||||||
|
void chroma_log_resource_deallocation(const char *resource_type, size_t size,
|
||||||
|
const char *description) {
|
||||||
|
if (size > 0) {
|
||||||
|
char size_str[64];
|
||||||
|
chroma_format_memory_size(size, size_str, sizeof(size_str));
|
||||||
|
chroma_log("DEBUG", "Deallocated %s: %s (%s)", resource_type, size_str,
|
||||||
|
description);
|
||||||
|
} else {
|
||||||
|
chroma_log("DEBUG", "Deallocated %s: %s", resource_type, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log memory stats after significant deallocations (>1MB)
|
||||||
|
if (size > 1024 * 1024) {
|
||||||
|
chroma_log_memory_stats("post-deallocation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
src/image.c
15
src/image.c
|
@ -1,7 +1,6 @@
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "../include/stb_image.h"
|
#include "../include/stb_image.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -79,10 +78,13 @@ int chroma_image_load(chroma_image_t *image, const char *path) {
|
||||||
|
|
||||||
image->loaded = true;
|
image->loaded = true;
|
||||||
|
|
||||||
|
// Calculate and log memory allocation
|
||||||
|
size_t image_size = (size_t)image->width * image->height * image->channels;
|
||||||
|
chroma_log_resource_allocation("image_data", image_size, path);
|
||||||
|
|
||||||
chroma_log("INFO", "Loaded image: %s (%dx%d, %d channels, %.2f MB)", path,
|
chroma_log("INFO", "Loaded image: %s (%dx%d, %d channels, %.2f MB)", path,
|
||||||
image->width, image->height, image->channels,
|
image->width, image->height, image->channels,
|
||||||
(double)(image->width * image->height * image->channels) /
|
(double)image_size / (1024.0 * 1024.0));
|
||||||
(1024.0 * 1024.0));
|
|
||||||
|
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
}
|
}
|
||||||
|
@ -94,6 +96,10 @@ void chroma_image_free(chroma_image_t *image) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image->data) {
|
if (image->data) {
|
||||||
|
// Log memory deallocation before freeing
|
||||||
|
size_t image_size = (size_t)image->width * image->height * image->channels;
|
||||||
|
chroma_log_resource_deallocation("image_data", image_size, image->path);
|
||||||
|
|
||||||
// Always use stbi_image_free since we load directly with stbi_load
|
// Always use stbi_image_free since we load directly with stbi_load
|
||||||
stbi_image_free(image->data);
|
stbi_image_free(image->data);
|
||||||
image->data = NULL;
|
image->data = NULL;
|
||||||
|
@ -218,12 +224,15 @@ void chroma_images_cleanup(chroma_state_t *state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chroma_log("DEBUG", "Cleaning up %d images", state->image_count);
|
||||||
|
|
||||||
for (int i = 0; i < state->image_count; i++) {
|
for (int i = 0; i < state->image_count; i++) {
|
||||||
chroma_image_free(&state->images[i]);
|
chroma_image_free(&state->images[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
state->image_count = 0;
|
state->image_count = 0;
|
||||||
chroma_log("INFO", "Cleaned up all images");
|
chroma_log("INFO", "Cleaned up all images");
|
||||||
|
chroma_log_memory_stats("post-image-cleanup");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preload common image formats for validation
|
// Preload common image formats for validation
|
||||||
|
|
28
src/main.c
28
src/main.c
|
@ -1,4 +1,3 @@
|
||||||
#include <errno.h>
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -9,7 +8,7 @@
|
||||||
|
|
||||||
#include "../include/chroma.h"
|
#include "../include/chroma.h"
|
||||||
|
|
||||||
/* Global state for signal handling */
|
// Global state for signal handling
|
||||||
volatile sig_atomic_t chroma_should_quit = 0;
|
volatile sig_atomic_t chroma_should_quit = 0;
|
||||||
|
|
||||||
static void print_usage(const char *program_name) {
|
static void print_usage(const char *program_name) {
|
||||||
|
@ -18,7 +17,9 @@ static void print_usage(const char *program_name) {
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -c, --config FILE Configuration file path\n");
|
printf(" -c, --config FILE Configuration file path\n");
|
||||||
printf(" -d, --daemon Run as daemon\n");
|
printf(" -d, --daemon Run as daemon\n");
|
||||||
printf(" -v, --verbose Verbose logging\n");
|
printf(" -v, --verbose Increase verbosity (can be used multiple "
|
||||||
|
"times)\n");
|
||||||
|
printf(" -v: INFO, -vv: DEBUG, -vvv: TRACE\n");
|
||||||
printf(" -h, --help Show this help\n");
|
printf(" -h, --help Show this help\n");
|
||||||
printf(" --version Show version information\n");
|
printf(" --version Show version information\n");
|
||||||
printf("\nExamples:\n");
|
printf("\nExamples:\n");
|
||||||
|
@ -124,7 +125,7 @@ int main(int argc, char *argv[]) {
|
||||||
chroma_state_t state;
|
chroma_state_t state;
|
||||||
char *config_file = NULL;
|
char *config_file = NULL;
|
||||||
bool daemon_mode = false;
|
bool daemon_mode = false;
|
||||||
bool verbose = false;
|
int verbose_level = 0;
|
||||||
int opt;
|
int opt;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
@ -143,7 +144,7 @@ int main(int argc, char *argv[]) {
|
||||||
daemon_mode = true;
|
daemon_mode = true;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = true;
|
verbose_level++;
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
|
@ -161,10 +162,9 @@ int main(int argc, char *argv[]) {
|
||||||
memset(&state, 0, sizeof(state));
|
memset(&state, 0, sizeof(state));
|
||||||
state.config.daemon_mode = daemon_mode;
|
state.config.daemon_mode = daemon_mode;
|
||||||
|
|
||||||
// Set log level based on verbose flag
|
// Set log level based on verbosity count
|
||||||
if (verbose) {
|
// 0: ERROR+WARN only, 1: +INFO, 2: +DEBUG, 3+: +TRACE
|
||||||
chroma_set_log_level(1); // Enable debug logging
|
chroma_set_log_level(verbose_level);
|
||||||
}
|
|
||||||
|
|
||||||
// Set up signal handlers
|
// Set up signal handlers
|
||||||
if (setup_signals() != 0) {
|
if (setup_signals() != 0) {
|
||||||
|
@ -189,6 +189,8 @@ int main(int argc, char *argv[]) {
|
||||||
// Initialize chroma
|
// Initialize chroma
|
||||||
chroma_log("INFO", "Initializing chroma wallpaper daemon v%s",
|
chroma_log("INFO", "Initializing chroma wallpaper daemon v%s",
|
||||||
CHROMA_VERSION);
|
CHROMA_VERSION);
|
||||||
|
chroma_log_memory_stats("startup");
|
||||||
|
|
||||||
ret = chroma_init(&state);
|
ret = chroma_init(&state);
|
||||||
if (ret != CHROMA_OK) {
|
if (ret != CHROMA_OK) {
|
||||||
chroma_log("ERROR", "Failed to initialize chroma: %s",
|
chroma_log("ERROR", "Failed to initialize chroma: %s",
|
||||||
|
@ -196,6 +198,7 @@ int main(int argc, char *argv[]) {
|
||||||
chroma_cleanup(&state);
|
chroma_cleanup(&state);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
chroma_log_memory_stats("post-init");
|
||||||
|
|
||||||
// Load configuration
|
// Load configuration
|
||||||
chroma_log("INFO", "Loading configuration from: %s", config_file);
|
chroma_log("INFO", "Loading configuration from: %s", config_file);
|
||||||
|
@ -203,6 +206,7 @@ int main(int argc, char *argv[]) {
|
||||||
chroma_log("WARN", "Failed to load config file, using defaults");
|
chroma_log("WARN", "Failed to load config file, using defaults");
|
||||||
// Continue with default configuration
|
// Continue with default configuration
|
||||||
}
|
}
|
||||||
|
chroma_log_memory_stats("post-config-load");
|
||||||
|
|
||||||
// Connect to Wayland
|
// Connect to Wayland
|
||||||
ret = chroma_wayland_connect(&state);
|
ret = chroma_wayland_connect(&state);
|
||||||
|
@ -212,6 +216,7 @@ int main(int argc, char *argv[]) {
|
||||||
chroma_cleanup(&state);
|
chroma_cleanup(&state);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
chroma_log_memory_stats("post-wayland-connect");
|
||||||
|
|
||||||
// Initialize EGL
|
// Initialize EGL
|
||||||
ret = chroma_egl_init(&state);
|
ret = chroma_egl_init(&state);
|
||||||
|
@ -221,18 +226,23 @@ int main(int argc, char *argv[]) {
|
||||||
chroma_cleanup(&state);
|
chroma_cleanup(&state);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
chroma_log_memory_stats("post-egl-init");
|
||||||
|
|
||||||
chroma_log("INFO", "Chroma daemon initialized successfully");
|
chroma_log("INFO", "Chroma daemon initialized successfully");
|
||||||
|
chroma_log_memory_stats("pre-main-loop");
|
||||||
|
|
||||||
// Main event loop
|
// Main event loop
|
||||||
ret = chroma_run(&state);
|
ret = chroma_run(&state);
|
||||||
if (ret != CHROMA_OK) {
|
if (ret != CHROMA_OK) {
|
||||||
chroma_log("ERROR", "Main loop failed: %s", chroma_error_string(ret));
|
chroma_log("ERROR", "Main loop failed: %s", chroma_error_string(ret));
|
||||||
}
|
}
|
||||||
|
chroma_log_memory_stats("post-main-loop");
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
chroma_log("INFO", "Shutting down chroma daemon");
|
chroma_log("INFO", "Shutting down chroma daemon");
|
||||||
|
chroma_log_memory_stats("pre-cleanup");
|
||||||
chroma_cleanup(&state);
|
chroma_cleanup(&state);
|
||||||
|
chroma_log_memory_stats("post-cleanup");
|
||||||
|
|
||||||
return (ret == CHROMA_OK) ? 0 : 1;
|
return (ret == CHROMA_OK) ? 0 : 1;
|
||||||
}
|
}
|
29
src/render.c
29
src/render.c
|
@ -156,6 +156,15 @@ static int update_texture_from_image(chroma_output_t *output,
|
||||||
|
|
||||||
// Delete existing texture if it exists
|
// Delete existing texture if it exists
|
||||||
if (output->texture_id != 0) {
|
if (output->texture_id != 0) {
|
||||||
|
// Estimate texture size for logging
|
||||||
|
// FIXME: Unfortunately this only works if we have previous image info.
|
||||||
|
// Could this b made more accurate?
|
||||||
|
if (output->image && output->image->loaded) {
|
||||||
|
size_t texture_size = (size_t)output->image->width *
|
||||||
|
output->image->height * output->image->channels;
|
||||||
|
chroma_log_resource_deallocation("gpu_texture", texture_size,
|
||||||
|
"texture replacement");
|
||||||
|
}
|
||||||
glDeleteTextures(1, &output->texture_id);
|
glDeleteTextures(1, &output->texture_id);
|
||||||
output->texture_id = 0;
|
output->texture_id = 0;
|
||||||
}
|
}
|
||||||
|
@ -164,6 +173,10 @@ static int update_texture_from_image(chroma_output_t *output,
|
||||||
glGenTextures(1, &output->texture_id);
|
glGenTextures(1, &output->texture_id);
|
||||||
glBindTexture(GL_TEXTURE_2D, output->texture_id);
|
glBindTexture(GL_TEXTURE_2D, output->texture_id);
|
||||||
|
|
||||||
|
// Log GPU texture allocation
|
||||||
|
size_t texture_size = (size_t)image->width * image->height * image->channels;
|
||||||
|
chroma_log_resource_allocation("gpu_texture", texture_size, image->path);
|
||||||
|
|
||||||
// Set texture parameters
|
// Set texture parameters
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
@ -207,6 +220,9 @@ static int update_texture_from_image(chroma_output_t *output,
|
||||||
"GPU: %s",
|
"GPU: %s",
|
||||||
(double)freed_bytes / (1024.0 * 1024.0), total_using,
|
(double)freed_bytes / (1024.0 * 1024.0), total_using,
|
||||||
image->path);
|
image->path);
|
||||||
|
chroma_log_resource_deallocation("image_data", freed_bytes,
|
||||||
|
"post-gpu-upload");
|
||||||
|
chroma_log_memory_stats("post-gpu-upload");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +238,7 @@ static void cleanup_gl_resources(chroma_output_t *output) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output->texture_id != 0) {
|
if (output->texture_id != 0) {
|
||||||
|
chroma_log_resource_deallocation("gpu_texture", 0, "cleanup");
|
||||||
glDeleteTextures(1, &output->texture_id);
|
glDeleteTextures(1, &output->texture_id);
|
||||||
output->texture_id = 0;
|
output->texture_id = 0;
|
||||||
}
|
}
|
||||||
|
@ -296,6 +313,7 @@ int chroma_egl_init(chroma_state_t *state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
chroma_log("INFO", "EGL initialized: version %d.%d", major, minor);
|
chroma_log("INFO", "EGL initialized: version %d.%d", major, minor);
|
||||||
|
chroma_log_memory_stats("post-egl-init");
|
||||||
|
|
||||||
// Bind OpenGL API
|
// Bind OpenGL API
|
||||||
if (!eglBindAPI(EGL_OPENGL_API)) {
|
if (!eglBindAPI(EGL_OPENGL_API)) {
|
||||||
|
@ -420,6 +438,11 @@ int chroma_surface_create(chroma_state_t *state, chroma_output_t *output) {
|
||||||
chroma_log("INFO", "Created surface for output %u (%dx%d)", output->id,
|
chroma_log("INFO", "Created surface for output %u (%dx%d)", output->id,
|
||||||
output->width, output->height);
|
output->width, output->height);
|
||||||
|
|
||||||
|
// Log surface creation resource allocation
|
||||||
|
size_t surface_size =
|
||||||
|
(size_t)output->width * output->height * 4; // estimate RGBA surface
|
||||||
|
chroma_log_resource_allocation("egl_surface", surface_size, "output surface");
|
||||||
|
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +475,12 @@ void chroma_surface_destroy(chroma_output_t *output) {
|
||||||
output->surface = NULL;
|
output->surface = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log surface destruction
|
||||||
|
size_t surface_size =
|
||||||
|
(size_t)output->width * output->height * 4; // estimate RGBA surface
|
||||||
|
chroma_log_resource_deallocation("egl_surface", surface_size,
|
||||||
|
"output surface cleanup");
|
||||||
|
|
||||||
chroma_log("DEBUG", "Destroyed surface for output %u", output->id);
|
chroma_log("DEBUG", "Destroyed surface for output %u", output->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ static void registry_global(void *data, struct wl_registry *registry,
|
||||||
|
|
||||||
chroma_log("DEBUG", "Registry global: %s (id=%u, version=%u)", interface, id,
|
chroma_log("DEBUG", "Registry global: %s (id=%u, version=%u)", interface, id,
|
||||||
version);
|
version);
|
||||||
|
chroma_log("TRACE", "Checking interface binding for: %s", interface);
|
||||||
|
|
||||||
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
||||||
state->compositor = wl_registry_bind(registry, id, &wl_compositor_interface,
|
state->compositor = wl_registry_bind(registry, id, &wl_compositor_interface,
|
||||||
|
@ -22,6 +23,7 @@ static void registry_global(void *data, struct wl_registry *registry,
|
||||||
chroma_log("ERROR", "Failed to bind compositor");
|
chroma_log("ERROR", "Failed to bind compositor");
|
||||||
} else {
|
} else {
|
||||||
chroma_log("INFO", "Bound compositor (version %u)", version);
|
chroma_log("INFO", "Bound compositor (version %u)", version);
|
||||||
|
chroma_log("TRACE", "Compositor binding successful, interface ready");
|
||||||
}
|
}
|
||||||
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
|
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
|
||||||
state->layer_shell =
|
state->layer_shell =
|
||||||
|
@ -31,6 +33,9 @@ static void registry_global(void *data, struct wl_registry *registry,
|
||||||
chroma_log("ERROR", "Failed to bind layer shell");
|
chroma_log("ERROR", "Failed to bind layer shell");
|
||||||
} else {
|
} else {
|
||||||
chroma_log("INFO", "Bound layer shell (version %u)", version);
|
chroma_log("INFO", "Bound layer shell (version %u)", version);
|
||||||
|
chroma_log(
|
||||||
|
"TRACE",
|
||||||
|
"wlr-layer-shell protocol available, wallpaper support enabled");
|
||||||
}
|
}
|
||||||
} else if (strcmp(interface, wl_output_interface.name) == 0) {
|
} else if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||||
struct wl_output *output = wl_registry_bind(
|
struct wl_output *output = wl_registry_bind(
|
||||||
|
@ -52,9 +57,10 @@ static void registry_global(void *data, struct wl_registry *registry,
|
||||||
static void registry_global_remove(void *data, struct wl_registry *registry,
|
static void registry_global_remove(void *data, struct wl_registry *registry,
|
||||||
uint32_t id) {
|
uint32_t id) {
|
||||||
chroma_state_t *state = (chroma_state_t *)data;
|
chroma_state_t *state = (chroma_state_t *)data;
|
||||||
(void)registry; // Unused parameter
|
(void)registry;
|
||||||
|
|
||||||
chroma_log("DEBUG", "Registry global remove: id=%u", id);
|
chroma_log("DEBUG", "Registry global remove: id=%u", id);
|
||||||
|
chroma_log("TRACE", "Global object removal initiated for id=%u", id);
|
||||||
chroma_output_remove(state, id);
|
chroma_output_remove(state, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,24 +69,31 @@ const struct wl_registry_listener chroma_registry_listener_impl = {
|
||||||
.global_remove = registry_global_remove,
|
.global_remove = registry_global_remove,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Layer surface event handlers */
|
// Layer surface event handlers
|
||||||
static void layer_surface_configure(void *data,
|
static void layer_surface_configure(void *data,
|
||||||
struct zwlr_layer_surface_v1 *layer_surface,
|
struct zwlr_layer_surface_v1 *layer_surface,
|
||||||
uint32_t serial, uint32_t width,
|
uint32_t serial, uint32_t width,
|
||||||
uint32_t height) {
|
uint32_t height) {
|
||||||
chroma_output_t *output = (chroma_output_t *)data;
|
chroma_output_t *output = (chroma_output_t *)data;
|
||||||
(void)layer_surface; // Unused parameter
|
(void)layer_surface;
|
||||||
|
|
||||||
chroma_log("DEBUG", "Layer surface configure: %ux%u, serial=%u", width,
|
chroma_log("DEBUG", "Layer surface configure: %ux%u, serial=%u", width,
|
||||||
height, serial);
|
height, serial);
|
||||||
|
chroma_log(
|
||||||
|
"TRACE",
|
||||||
|
"Configuring layer surface for output %u: dimensions=%ux%u, serial=%u",
|
||||||
|
output->id, width, height, serial);
|
||||||
|
|
||||||
output->configure_serial = serial;
|
output->configure_serial = serial;
|
||||||
|
|
||||||
/* Acknowledge the configure event */
|
// Acknowledge the configure event
|
||||||
zwlr_layer_surface_v1_ack_configure(output->layer_surface, serial);
|
zwlr_layer_surface_v1_ack_configure(output->layer_surface, serial);
|
||||||
|
chroma_log("TRACE", "Sent configure acknowledgment for output %u serial %u",
|
||||||
|
output->id, serial);
|
||||||
|
|
||||||
/* Commit the surface to apply the acknowledgment */
|
// Commit the surface to apply the acknowledgment
|
||||||
wl_surface_commit(output->surface);
|
wl_surface_commit(output->surface);
|
||||||
|
chroma_log("TRACE", "Surface committed for output %u", output->id);
|
||||||
|
|
||||||
chroma_log("DEBUG", "Acknowledged layer surface configure for output %u",
|
chroma_log("DEBUG", "Acknowledged layer surface configure for output %u",
|
||||||
output->id);
|
output->id);
|
||||||
|
@ -89,11 +102,11 @@ static void layer_surface_configure(void *data,
|
||||||
static void layer_surface_closed(void *data,
|
static void layer_surface_closed(void *data,
|
||||||
struct zwlr_layer_surface_v1 *layer_surface) {
|
struct zwlr_layer_surface_v1 *layer_surface) {
|
||||||
chroma_output_t *output = (chroma_output_t *)data;
|
chroma_output_t *output = (chroma_output_t *)data;
|
||||||
(void)layer_surface; /* Unused parameter */
|
(void)layer_surface;
|
||||||
|
|
||||||
chroma_log("INFO", "Layer surface closed for output %u", output->id);
|
chroma_log("INFO", "Layer surface closed for output %u", output->id);
|
||||||
|
|
||||||
/* Clean up the surface */
|
// Clean up the surface
|
||||||
if (output->surface) {
|
if (output->surface) {
|
||||||
chroma_surface_destroy(output);
|
chroma_surface_destroy(output);
|
||||||
}
|
}
|
||||||
|
@ -105,17 +118,17 @@ const struct zwlr_layer_surface_v1_listener chroma_layer_surface_listener_impl =
|
||||||
.closed = layer_surface_closed,
|
.closed = layer_surface_closed,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Output event handlers */
|
// Output event handlers
|
||||||
static void output_geometry(void *data, struct wl_output *output, int32_t x,
|
static void output_geometry(void *data, struct wl_output *output, int32_t x,
|
||||||
int32_t y, int32_t physical_width,
|
int32_t y, int32_t physical_width,
|
||||||
int32_t physical_height, int32_t subpixel,
|
int32_t physical_height, int32_t subpixel,
|
||||||
const char *make, const char *model,
|
const char *make, const char *model,
|
||||||
int32_t transform) {
|
int32_t transform) {
|
||||||
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
||||||
(void)output; // Unused parameter
|
(void)output;
|
||||||
(void)subpixel; // Unused parameter
|
(void)subpixel;
|
||||||
(void)make; // Unused parameter
|
(void)make;
|
||||||
(void)model; // Unused parameter
|
(void)model;
|
||||||
|
|
||||||
chroma_output->x = x;
|
chroma_output->x = x;
|
||||||
chroma_output->y = y;
|
chroma_output->y = y;
|
||||||
|
@ -124,24 +137,36 @@ static void output_geometry(void *data, struct wl_output *output, int32_t x,
|
||||||
chroma_log("DEBUG", "Output %u geometry: %dx%d at (%d,%d), transform=%d",
|
chroma_log("DEBUG", "Output %u geometry: %dx%d at (%d,%d), transform=%d",
|
||||||
chroma_output->id, physical_width, physical_height, x, y,
|
chroma_output->id, physical_width, physical_height, x, y,
|
||||||
transform);
|
transform);
|
||||||
|
chroma_log("TRACE",
|
||||||
|
"Output %u geometry details: physical_size=%dx%dmm, "
|
||||||
|
"position=(%d,%d), transform=%d",
|
||||||
|
chroma_output->id, physical_width, physical_height, x, y,
|
||||||
|
transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_mode(void *data, struct wl_output *output, uint32_t flags,
|
static void output_mode(void *data, struct wl_output *output, uint32_t flags,
|
||||||
int32_t width, int32_t height, int32_t refresh) {
|
int32_t width, int32_t height, int32_t refresh) {
|
||||||
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
||||||
(void)output; // Unused parameter
|
(void)output;
|
||||||
|
|
||||||
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
||||||
chroma_output->width = width;
|
chroma_output->width = width;
|
||||||
chroma_output->height = height;
|
chroma_output->height = height;
|
||||||
chroma_log("DEBUG", "Output %u mode: %dx%d@%d (current)", chroma_output->id,
|
chroma_log("DEBUG", "Output %u mode: %dx%d@%d (current)", chroma_output->id,
|
||||||
width, height, refresh);
|
width, height, refresh);
|
||||||
|
chroma_log("TRACE",
|
||||||
|
"Current mode set for output %u: %dx%d@%dHz, flags=0x%x",
|
||||||
|
chroma_output->id, width, height, refresh, flags);
|
||||||
|
} else {
|
||||||
|
chroma_log("TRACE",
|
||||||
|
"Non-current mode for output %u: %dx%d@%dHz, flags=0x%x",
|
||||||
|
chroma_output->id, width, height, refresh, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_scale(void *data, struct wl_output *output, int32_t scale) {
|
static void output_scale(void *data, struct wl_output *output, int32_t scale) {
|
||||||
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
||||||
(void)output; // Unused parameter
|
(void)output;
|
||||||
|
|
||||||
chroma_output->scale = scale;
|
chroma_output->scale = scale;
|
||||||
chroma_log("DEBUG", "Output %u scale: %d", chroma_output->id, scale);
|
chroma_log("DEBUG", "Output %u scale: %d", chroma_output->id, scale);
|
||||||
|
@ -150,7 +175,7 @@ static void output_scale(void *data, struct wl_output *output, int32_t scale) {
|
||||||
static void output_name(void *data, struct wl_output *output,
|
static void output_name(void *data, struct wl_output *output,
|
||||||
const char *name) {
|
const char *name) {
|
||||||
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
||||||
(void)output; // Unused parameter
|
(void)output;
|
||||||
|
|
||||||
free(chroma_output->name);
|
free(chroma_output->name);
|
||||||
chroma_output->name = strdup(name);
|
chroma_output->name = strdup(name);
|
||||||
|
@ -165,7 +190,7 @@ static void output_name(void *data, struct wl_output *output,
|
||||||
static void output_description(void *data, struct wl_output *output,
|
static void output_description(void *data, struct wl_output *output,
|
||||||
const char *description) {
|
const char *description) {
|
||||||
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
||||||
(void)output; // Unused parameter
|
(void)output;
|
||||||
|
|
||||||
free(chroma_output->description);
|
free(chroma_output->description);
|
||||||
chroma_output->description = strdup(description);
|
chroma_output->description = strdup(description);
|
||||||
|
@ -180,16 +205,23 @@ static void output_description(void *data, struct wl_output *output,
|
||||||
|
|
||||||
static void output_done(void *data, struct wl_output *output) {
|
static void output_done(void *data, struct wl_output *output) {
|
||||||
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
chroma_output_t *chroma_output = (chroma_output_t *)data;
|
||||||
(void)output; /* Unused parameter */
|
(void)output;
|
||||||
|
|
||||||
chroma_log("DEBUG", "Output %u done - configuration complete",
|
chroma_log("DEBUG", "Output %u done - configuration complete",
|
||||||
chroma_output->id);
|
chroma_output->id);
|
||||||
|
chroma_log("TRACE",
|
||||||
|
"Output %u configuration finalized: %dx%d, scale=%d, name='%s'",
|
||||||
|
chroma_output->id, chroma_output->width, chroma_output->height,
|
||||||
|
chroma_output->scale,
|
||||||
|
chroma_output->name ? chroma_output->name : "unknown");
|
||||||
|
|
||||||
// Mark output as active and ready for wallpaper assignment
|
// Mark output as active and ready for wallpaper assignment
|
||||||
chroma_output->active = true;
|
chroma_output->active = true;
|
||||||
|
|
||||||
// Trigger wallpaper assignment for this output
|
// Trigger wallpaper assignment for this output
|
||||||
if (chroma_output->state) {
|
if (chroma_output->state) {
|
||||||
|
chroma_log("TRACE", "Triggering wallpaper assignment for output %u",
|
||||||
|
chroma_output->id);
|
||||||
handle_output_done(chroma_output->state, chroma_output);
|
handle_output_done(chroma_output->state, chroma_output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +235,7 @@ const struct wl_output_listener chroma_output_listener_impl = {
|
||||||
.done = output_done,
|
.done = output_done,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Wayland connection functions */
|
// Wayland connection functions
|
||||||
int chroma_wayland_connect(chroma_state_t *state) {
|
int chroma_wayland_connect(chroma_state_t *state) {
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return CHROMA_ERROR_INIT;
|
return CHROMA_ERROR_INIT;
|
||||||
|
@ -230,11 +262,13 @@ int chroma_wayland_connect(chroma_state_t *state) {
|
||||||
state);
|
state);
|
||||||
|
|
||||||
// Roundtrip to get all globals
|
// Roundtrip to get all globals
|
||||||
|
chroma_log("TRACE", "Starting Wayland display roundtrip to discover globals");
|
||||||
if (wl_display_roundtrip(state->display) == -1) {
|
if (wl_display_roundtrip(state->display) == -1) {
|
||||||
chroma_log("ERROR", "Failed to roundtrip Wayland display");
|
chroma_log("ERROR", "Failed to roundtrip Wayland display");
|
||||||
chroma_wayland_disconnect(state);
|
chroma_wayland_disconnect(state);
|
||||||
return CHROMA_ERROR_WAYLAND;
|
return CHROMA_ERROR_WAYLAND;
|
||||||
}
|
}
|
||||||
|
chroma_log("TRACE", "Wayland display roundtrip completed");
|
||||||
|
|
||||||
// Check if we got a compositor
|
// Check if we got a compositor
|
||||||
if (!state->compositor) {
|
if (!state->compositor) {
|
||||||
|
@ -301,7 +335,7 @@ void chroma_wayland_disconnect(chroma_state_t *state) {
|
||||||
chroma_log("INFO", "Disconnected from Wayland display");
|
chroma_log("INFO", "Disconnected from Wayland display");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output management functions */
|
// Output management functions
|
||||||
int chroma_output_add(chroma_state_t *state, uint32_t id,
|
int chroma_output_add(chroma_state_t *state, uint32_t id,
|
||||||
struct wl_output *output) {
|
struct wl_output *output) {
|
||||||
if (!state || !output) {
|
if (!state || !output) {
|
||||||
|
@ -318,16 +352,19 @@ int chroma_output_add(chroma_state_t *state, uint32_t id,
|
||||||
|
|
||||||
chroma_output->wl_output = output;
|
chroma_output->wl_output = output;
|
||||||
chroma_output->id = id;
|
chroma_output->id = id;
|
||||||
chroma_output->scale = 1; // Default scale
|
chroma_output->scale = 1; // default scale
|
||||||
chroma_output->active = false;
|
chroma_output->active = false;
|
||||||
chroma_output->state = state;
|
chroma_output->state = state;
|
||||||
|
|
||||||
// Add output listener
|
// Add output listener
|
||||||
wl_output_add_listener(output, &chroma_output_listener_impl, chroma_output);
|
wl_output_add_listener(output, &chroma_output_listener_impl, chroma_output);
|
||||||
|
chroma_log("TRACE", "Output listener attached for output %u", id);
|
||||||
|
|
||||||
state->output_count++;
|
state->output_count++;
|
||||||
|
|
||||||
chroma_log("INFO", "Added output %u (total: %d)", id, state->output_count);
|
chroma_log("INFO", "Added output %u (total: %d)", id, state->output_count);
|
||||||
|
chroma_log("TRACE",
|
||||||
|
"Output %u initialized with default scale=1, active=false", id);
|
||||||
return CHROMA_OK;
|
return CHROMA_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,25 +382,28 @@ void chroma_output_remove(chroma_state_t *state, uint32_t id) {
|
||||||
chroma_log("INFO", "Removing output %u (%s)", id,
|
chroma_log("INFO", "Removing output %u (%s)", id,
|
||||||
output->name ? output->name : "unknown");
|
output->name ? output->name : "unknown");
|
||||||
|
|
||||||
/* Clean up surface if it exists */
|
// Clean up surface if it exists
|
||||||
if (output->surface) {
|
if (output->surface) {
|
||||||
chroma_surface_destroy(output);
|
chroma_surface_destroy(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up Wayland output */
|
// Clean up Wayland output
|
||||||
if (output->wl_output) {
|
if (output->wl_output) {
|
||||||
wl_output_destroy(output->wl_output);
|
wl_output_destroy(output->wl_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free allocated strings */
|
// Free allocated strings
|
||||||
free(output->name);
|
free(output->name);
|
||||||
free(output->description);
|
free(output->description);
|
||||||
|
|
||||||
/* Remove from array by shifting remaining elements */
|
// Remove from array by shifting remaining elements
|
||||||
int index = output - state->outputs;
|
int index = output - state->outputs;
|
||||||
int remaining = state->output_count - index - 1;
|
int remaining = state->output_count - index - 1;
|
||||||
|
chroma_log("TRACE", "Removing output %u from array: index=%d, remaining=%d",
|
||||||
|
id, index, remaining);
|
||||||
if (remaining > 0) {
|
if (remaining > 0) {
|
||||||
memmove(output, output + 1, remaining * sizeof(chroma_output_t));
|
memmove(output, output + 1, remaining * sizeof(chroma_output_t));
|
||||||
|
chroma_log("TRACE", "Shifted %d outputs in array after removal", remaining);
|
||||||
}
|
}
|
||||||
|
|
||||||
state->output_count--;
|
state->output_count--;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue