diff --git a/.SRCINFO b/.SRCINFO index 3902cb5..ff86653 100644 --- a/.SRCINFO +++ b/.SRCINFO @@ -1,6 +1,6 @@ pkgbase = coolerdash pkgdesc = Extends CoolerControl with a polished LCD dashboard - pkgver = 1.91 + pkgver = 1.92 pkgrel = 1 url = https://github.com/damachine/coolerdash install = coolerdash.install diff --git a/.gitignore b/.gitignore index 36482f6..6304761 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ gnupg/ *.tmp *.log *.bak +*.env # Editor files *.code-workspace diff --git a/README.md b/README.md index 54eeceb..05147e7 100644 --- a/README.md +++ b/README.md @@ -146,8 +146,10 @@ make help # Show all options # Run manually (with minimal status logging) coolerdash -# Run with detailed debug logging -coolerdash --log +# Run with detailed verbose logging +coolerdash --verbose +# or short form: +coolerdash -v ``` #### Debugging Steps @@ -160,11 +162,13 @@ curl http://localhost:11987/devices # 2. Test CoolerDash manually (with clean output) coolerdash -# 3. Test CoolerDash with detailed debug logging -coolerdash --log +# 3. Test CoolerDash with detailed verbose logging +coolerdash --verbose +# or short form: +coolerdash -v # 4. Debug build for detailed information (if needed) -make debug && coolerdash --log +make debug && coolerdash --verbose # 5. Check service logs (STATUS messages always visible) journalctl -xeu coolerdash.service -f diff --git a/VERSION b/VERSION index 0573181..939c310 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91 +1.92 diff --git a/src/config.c b/src/config.c index e91ac17..ac7c192 100644 --- a/src/config.c +++ b/src/config.c @@ -476,7 +476,8 @@ static int get_temperature_config(Config *config, const char *name, const char * static const TemperatureConfigEntry entries[] = { {"temp_threshold_1", offsetof(Config, temp_threshold_1)}, {"temp_threshold_2", offsetof(Config, temp_threshold_2)}, - {"temp_threshold_3", offsetof(Config, temp_threshold_3)}}; + {"temp_threshold_3", offsetof(Config, temp_threshold_3)}, + {"temp_max_scale", offsetof(Config, temp_max_scale)}}; for (size_t i = 0; i < sizeof(entries) / sizeof(entries[0]); i++) { @@ -484,7 +485,7 @@ static int get_temperature_config(Config *config, const char *name, const char * { void *field_ptr = (void *)((char *)config + entries[i].offset); float *dest = (float *)field_ptr; - *dest = safe_atof(value, 50.0f + i * 15.0f); // 50, 65, 80 + *dest = safe_atof(value, 50.0f + i * 15.0f); // 50, 65, 80, 115 return 1; } } @@ -686,22 +687,48 @@ static void set_display_positioning_defaults(Config *config) /** * @brief Set font default values. - * @details Helper function to set default font configuration values. + * @details Helper function to set default font configuration values with dynamic scaling based on display resolution. */ static void set_font_defaults(Config *config) { if (config->font_face[0] == '\0') SAFE_STRCPY(config->font_face, "Roboto Black"); + + // Dynamic font size scaling based on display resolution + // Base: 240×240 with font_size_temp=100.0 and font_size_labels=30.0 if (config->font_size_temp == 0.0f) - config->font_size_temp = 100.0f; + { + const double base_resolution = 240.0; + const double base_font_size_temp = 100.0; + + // Calculate scaling factor from average of width and height + const double scale_factor = ((double)config->display_width + (double)config->display_height) / (2.0 * base_resolution); + + config->font_size_temp = (float)(base_font_size_temp * scale_factor); + + log_message(LOG_INFO, "Font size (temp) auto-scaled: %.1f (display: %dx%d, scale: %.2f)", + config->font_size_temp, config->display_width, config->display_height, scale_factor); + } + if (config->font_size_labels == 0.0f) - config->font_size_labels = 30.0f; + { + const double base_resolution = 240.0; + const double base_font_size_labels = 30.0; + + // Calculate scaling factor from average of width and height + const double scale_factor = ((double)config->display_width + (double)config->display_height) / (2.0 * base_resolution); + + config->font_size_labels = (float)(base_font_size_labels * scale_factor); + + log_message(LOG_INFO, "Font size (labels) auto-scaled: %.1f (display: %dx%d, scale: %.2f)", + config->font_size_labels, config->display_width, config->display_height, scale_factor); + } set_display_positioning_defaults(config); } /** - * @brief Set temperature threshold default values. + * @brief Set temperature defaults * @details Helper function to set default temperature threshold values. */ static void set_temperature_defaults(Config *config) @@ -712,6 +739,8 @@ static void set_temperature_defaults(Config *config) config->temp_threshold_2 = 65.0f; if (config->temp_threshold_3 == 0.0f) config->temp_threshold_3 = 75.0f; + if (config->temp_max_scale == 0.0f) + config->temp_max_scale = 115.0f; } /** diff --git a/src/config.h b/src/config.h index 43b3d64..739de6c 100644 --- a/src/config.h +++ b/src/config.h @@ -76,6 +76,8 @@ typedef struct Config uint32_t display_refresh_interval_nsec; uint8_t lcd_brightness; uint8_t lcd_orientation; + // Developer/testing override: force display to be treated as circular (1) or not (0) + int force_display_circular; // Layout configuration - all positioning is now calculated dynamically from display dimensions uint16_t layout_bar_width; // Legacy - not used in dynamic scaling @@ -104,6 +106,7 @@ typedef struct Config float temp_threshold_1; float temp_threshold_2; float temp_threshold_3; + float temp_max_scale; // Maximum temperature for bar scaling (default: 115°C) Color temp_threshold_1_bar; Color temp_threshold_2_bar; Color temp_threshold_3_bar; diff --git a/src/coolercontrol.c b/src/coolercontrol.c index b858ac2..9875dbd 100644 --- a/src/coolercontrol.c +++ b/src/coolercontrol.c @@ -787,6 +787,8 @@ static int validate_device_dimensions(void) */ static int update_dimension(uint16_t *config_dim, int device_dim, const char *dim_name) { + const uint16_t original_value = *config_dim; + if (*config_dim == 0) { *config_dim = (uint16_t)device_dim; @@ -795,8 +797,18 @@ static int update_dimension(uint16_t *config_dim, int device_dim, const char *di return 1; } - log_message(LOG_INFO, "Display %s from config.ini: %d (overrides device value %d)", - dim_name, *config_dim, device_dim); + // Only log if the values differ (to avoid misleading logs when using defaults) + if (original_value != (uint16_t)device_dim) + { + log_message(LOG_INFO, "Display %s from config.ini: %d (device reports %d)", + dim_name, *config_dim, device_dim); + } + else + { + // Values match - using device value (config was commented, default matches device) + log_message(LOG_INFO, "Display %s: %d (device and default match)", + dim_name, *config_dim); + } return 0; } diff --git a/src/display.c b/src/display.c index 6e3d91b..9a47688 100644 --- a/src/display.c +++ b/src/display.c @@ -65,13 +65,16 @@ static inline void set_cairo_color(cairo_t *cr, const Color *color) /** * @brief Calculate temperature fill width with bounds checking + * @param temp_value Current temperature value + * @param max_width Maximum width of the bar in pixels + * @param max_temp Maximum temperature from configuration (highest threshold) */ -static inline int calculate_temp_fill_width(float temp_value, int max_width) +static inline int calculate_temp_fill_width(float temp_value, int max_width, float max_temp) { if (temp_value <= 0.0f) return 0; - const float ratio = fminf(temp_value / 105.0f, 1.0f); + const float ratio = fminf(temp_value / max_temp, 1.0f); return (int)(ratio * max_width); } @@ -106,8 +109,19 @@ static void calculate_scaling_params(const struct Config *config, ScalingParams int is_circular_by_device = is_circular_display_device(device_name, config->display_width, config->display_height); - params->is_circular = is_circular_by_device; - params->inscribe_factor = params->is_circular ? M_SQRT1_2 : 1.0; + + // Allow developer override from config (set via CLI --develop) + if (config->force_display_circular) + { + params->is_circular = 1; + params->inscribe_factor = M_SQRT1_2; + log_message(LOG_INFO, "Developer override active: forcing circular display detection (device: %s)", device_name ? device_name : "unknown"); + } + else + { + params->is_circular = is_circular_by_device; + params->inscribe_factor = params->is_circular ? M_SQRT1_2 : 1.0; + } // Calculate safe area width const double safe_area_width = config->display_width * params->inscribe_factor; @@ -115,6 +129,10 @@ static void calculate_scaling_params(const struct Config *config, ScalingParams params->safe_content_margin = (config->display_width - params->safe_bar_width) / 2.0; params->corner_radius = 8.0 * scale_avg; + + // Log detailed scaling calculations (verbose only) + log_message(LOG_INFO, "Scaling: safe_area=%.0fpx, bar_width=%dpx, margin=%.1fpx", + safe_area_width, params->safe_bar_width, params->safe_content_margin); } /** @@ -128,6 +146,16 @@ static Color get_temperature_bar_color(const struct Config *config, float val); static void draw_rounded_rectangle_path(cairo_t *cr, int x, int y, int width, int height, double radius); static cairo_t *create_cairo_context(const struct Config *config, cairo_surface_t **surface); static void render_display_content(cairo_t *cr, const struct Config *config, const monitor_sensor_data_t *data, const ScalingParams *params); +// Helper to draw degree symbol at calculated position with proper font scaling +static void draw_degree_symbol(cairo_t *cr, double x, double y, const struct Config *config) +{ + if (!cr || !config) + return; + cairo_set_font_size(cr, config->font_size_temp / 1.66); + cairo_move_to(cr, x, y); + cairo_show_text(cr, "°"); + cairo_set_font_size(cr, config->font_size_temp); +} /** * @brief Draw rounded rectangle path for temperature bars @@ -194,13 +222,24 @@ static void draw_temperature_displays(cairo_t *cr, const monitor_sensor_data_t * cairo_font_extents_t font_ext; cairo_font_extents(cr, &font_ext); - // Calculate maximum width for 2-digit numbers to keep position stable - cairo_text_extents_t max_num_ext; - cairo_text_extents(cr, "88", &max_num_ext); // Widest 2-digit number + // Use actual text extents for positioning to handle 3-digit temperatures correctly + // For values ≥100, use actual width; for <100, use fixed width of "88" for stability + double cpu_width = (data->temp_cpu >= 100.0f) ? cpu_num_ext.width : cpu_num_ext.width; + double gpu_width = (data->temp_gpu >= 100.0f) ? gpu_num_ext.width : gpu_num_ext.width; + + // Calculate reference width (widest 2-digit number) for sub-100 alignment + cairo_text_extents_t ref_width_ext; + cairo_text_extents(cr, "88", &ref_width_ext); + + // Use reference width for values <100 to keep position stable + if (data->temp_cpu < 100.0f) + cpu_width = ref_width_ext.width; + if (data->temp_gpu < 100.0f) + gpu_width = ref_width_ext.width; - // Left-align numbers at center position (fixed X to prevent jumping) - double cpu_temp_x = bar_x + (effective_bar_width - max_num_ext.width) / 2.0; - double gpu_temp_x = bar_x + (effective_bar_width - max_num_ext.width) / 2.0; + // Center-align based on actual or reference width + double cpu_temp_x = bar_x + (effective_bar_width - cpu_width) / 2.0; + double gpu_temp_x = bar_x + (effective_bar_width - gpu_width) / 2.0; // For small displays (≤240×240), shift temperatures 12px to the right if (config->display_width <= 240 && config->display_height <= 240) @@ -241,15 +280,17 @@ static void draw_temperature_displays(cairo_t *cr, const monitor_sensor_data_t * // Draw degree symbols at fixed offset cairo_set_font_size(cr, config->font_size_temp / 1.66); - // Position degree symbols 18px to the right of temperature numbers - double degree_symbol_x = cpu_temp_x + max_num_ext.width + 16; + // Position degree symbols 16px to the right of temperature numbers (using actual widths) + double degree_cpu_x = cpu_temp_x + cpu_width + 16; + double degree_gpu_x = gpu_temp_x + gpu_width + 16; double degree_cpu_y = cpu_temp_y - cpu_num_ext.height * 0.40; double degree_gpu_y = gpu_temp_y - gpu_num_ext.height * 0.40; // Apply user-defined degree offsets if set if (config->display_degree_offset_x != -9999) { - degree_symbol_x += config->display_degree_offset_x; + degree_cpu_x += config->display_degree_offset_x; + degree_gpu_x += config->display_degree_offset_x; } if (config->display_degree_offset_y != -9999) { @@ -257,13 +298,8 @@ static void draw_temperature_displays(cairo_t *cr, const monitor_sensor_data_t * degree_gpu_y += config->display_degree_offset_y; } - cairo_move_to(cr, degree_symbol_x, degree_cpu_y); - cairo_show_text(cr, "°"); - - cairo_move_to(cr, degree_symbol_x, degree_gpu_y); - cairo_show_text(cr, "°"); - - cairo_set_font_size(cr, config->font_size_temp); + draw_degree_symbol(cr, degree_cpu_x, degree_cpu_y, config); + draw_degree_symbol(cr, degree_gpu_x, degree_gpu_y, config); } /** @@ -274,7 +310,9 @@ static void draw_single_temperature_bar(cairo_t *cr, const struct Config *config if (!cr || !config || !params) return; - const int fill_width = calculate_temp_fill_width(temp_value, bar_width); + // Use configured maximum temperature for bar scaling (default: 115°C) + const float max_temp = config->temp_max_scale; + const int fill_width = calculate_temp_fill_width(temp_value, bar_width, max_temp); // Background set_cairo_color(cr, &config->layout_bar_color_background); diff --git a/src/main.c b/src/main.c index 700c5c8..3d63a23 100644 --- a/src/main.c +++ b/src/main.c @@ -65,6 +65,8 @@ static volatile sig_atomic_t running = 1; // flag whether daemon is running * @details Controls whether detailed INFO logs are shown (enabled with --log parameter). */ int verbose_logging = 0; // Only ERROR and WARNING by default (exported) +// Developer/testing flag: when set (via --develop), force displays to be treated as circular +int force_display_circular = 0; /** * @brief Global pointer to configuration. @@ -453,12 +455,14 @@ static void show_help(const char *program_name, const Config *config) printf("USAGE:\n"); printf(" %s [OPTIONS] [CONFIG_PATH]\n\n", program_name); printf("OPTIONS:\n"); - printf(" -h, --help Show this help message and exit\n"); - printf(" --log Enable detailed INFO logging for debugging\n\n"); + printf(" -h, --help Show this help message and exit\n"); + printf(" -v, --verbose Enable verbose logging (shows detailed INFO messages)\n\n"); + printf(" --develop Developer: force display to be treated as circular for testing\n\n"); printf("EXAMPLES:\n"); printf(" sudo systemctl start coolerdash # Start as system service (recommended)\n"); printf(" %s # Manual start with default config\n", program_name); - printf(" %s --log # Start with detailed logging enabled\n", program_name); + printf(" %s --verbose # Start with detailed logging enabled\n", program_name); + printf(" %s -v # Short form: enable verbose logging\n", program_name); printf(" %s /custom/config.ini # Start with custom configuration\n\n", program_name); printf("FILES:\n"); printf(" /usr/bin/coolerdash # Main program executable\n"); @@ -747,10 +751,15 @@ static const char *parse_arguments(int argc, char **argv) show_help(argv[0], NULL); exit(EXIT_SUCCESS); } - else if (strcmp(argv[i], "--log") == 0) + else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0) { verbose_logging = 1; } + else if (strcmp(argv[i], "--develop") == 0) + { + force_display_circular = 1; + verbose_logging = 1; // Developer mode implies verbose logging + } else if (argv[i][0] != '-') { config_path = argv[i]; @@ -782,6 +791,13 @@ static int initialize_config_and_instance(const char *config_path, Config *confi return -1; } + /* Apply CLI overrides (developer/testing) */ + if (force_display_circular) + { + config->force_display_circular = 1; + log_message(LOG_INFO, "Developer override: forcing circular display detection (via --develop)"); + } + int is_service_start = is_started_by_systemd(); log_message(LOG_INFO, "Running mode: %s", is_service_start ? "systemd service" : "manual");