optimized

This commit is contained in:
rdavidek 2026-01-11 13:01:53 +01:00
parent c8668e5f00
commit fc1ca721fc
8 changed files with 88 additions and 74 deletions

View File

@ -32,6 +32,7 @@ public:
private: private:
std::string getConfigFilePath() const; std::string getConfigFilePath() const;
mutable std::string cachedConfigPath;
int windowWidth; int windowWidth;
int windowHeight; int windowHeight;
int pollingTime; int pollingTime;

View File

@ -2,6 +2,8 @@
#define MAINWINDOW_H #define MAINWINDOW_H
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include <memory>
#include <map>
#include "temp_monitor.h" #include "temp_monitor.h"
#include "temperature_chart.h" #include "temperature_chart.h"
#include "config_manager.h" #include "config_manager.h"
@ -30,9 +32,9 @@ private:
GtkWidget *window; GtkWidget *window;
GtkWidget *statusLabel; GtkWidget *statusLabel;
GtkSpinButton *refreshRateSpinBox; GtkSpinButton *refreshRateSpinBox;
TemperatureChart *chart; std::unique_ptr<TemperatureChart> chart;
TempMonitor *monitor; std::unique_ptr<TempMonitor> monitor;
ConfigManager *config; std::unique_ptr<ConfigManager> config;
guint timerID; guint timerID;
int refreshRateSec; int refreshRateSec;
GtkWidget *legendBox; GtkWidget *legendBox;

View File

@ -22,7 +22,7 @@ struct SeriesData {
class TemperatureChart { class TemperatureChart {
public: public:
TemperatureChart(GtkWidget *parent = nullptr); TemperatureChart();
~TemperatureChart(); ~TemperatureChart();
GtkWidget* getWidget() const { return drawingArea; } GtkWidget* getWidget() const { return drawingArea; }
@ -48,7 +48,7 @@ private:
void redraw(); void redraw();
void updateThemeColors(); void updateThemeColors();
static gboolean onTick(gpointer userData);
static void onLeave(GtkEventControllerMotion *motion, gpointer userData); static void onLeave(GtkEventControllerMotion *motion, gpointer userData);
struct NearestPoint { struct NearestPoint {

View File

@ -5,27 +5,20 @@ window {
.small-entry { .small-entry {
font-size: 9px; font-size: 9px;
min-height: 0; padding: 1px;
min-width: 0;
padding: 0px 1px;
margin: 0; margin: 0;
border: none; border: none;
background: transparent; background: transparent;
} }
.small-entry:focus {
background: rgba(255,255,255,0.1);
}
.temp-label-small { .temp-label-small {
font-size: 9px; font-size: 10px;
font-weight: bold; font-weight: bold;
margin-left: 1px; margin-left: 2px;
color: #ccc; color: #888;
} }
/* Compact box items */
.legend-item { .legend-item {
margin: 0 4px; margin: 0 5px;
padding: 0; padding: 2px;
} }

View File

@ -13,13 +13,18 @@ ConfigManager::ConfigManager()
std::string ConfigManager::getConfigFilePath() const std::string ConfigManager::getConfigFilePath() const
{ {
if (!cachedConfigPath.empty()) {
return cachedConfigPath;
}
// Get the directory of the executable using /proc/self/exe // Get the directory of the executable using /proc/self/exe
char path[1024]; char path[1024];
ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1); ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (len == -1) { if (len == -1) {
// Fallback to current directory // Fallback to current directory
return "./nvme-monitor.conf"; cachedConfigPath = "./nvme-monitor.conf";
return cachedConfigPath;
} }
path[len] = '\0'; path[len] = '\0';
@ -29,10 +34,12 @@ std::string ConfigManager::getConfigFilePath() const
size_t lastSlash = fullPath.find_last_of('/'); size_t lastSlash = fullPath.find_last_of('/');
if (lastSlash != std::string::npos) { if (lastSlash != std::string::npos) {
std::string exeDir = fullPath.substr(0, lastSlash); std::string exeDir = fullPath.substr(0, lastSlash);
return exeDir + "/nvme-monitor.conf"; cachedConfigPath = exeDir + "/nvme-monitor.conf";
return cachedConfigPath;
} }
return "./nvme-monitor.conf"; cachedConfigPath = "./nvme-monitor.conf";
return cachedConfigPath;
} }
void ConfigManager::load() void ConfigManager::load()
@ -61,6 +68,7 @@ void ConfigManager::load()
value.erase(0, value.find_first_not_of(" \t")); value.erase(0, value.find_first_not_of(" \t"));
value.erase(value.find_last_not_of(" \t") + 1); value.erase(value.find_last_not_of(" \t") + 1);
try {
if (key == "window_width") { if (key == "window_width") {
windowWidth = std::stoi(value); windowWidth = std::stoi(value);
} else if (key == "window_height") { } else if (key == "window_height") {
@ -72,6 +80,9 @@ void ConfigManager::load()
} else if (key.find("name_") == 0) { } else if (key.find("name_") == 0) {
sensorNames[key.substr(5)] = value; sensorNames[key.substr(5)] = value;
} }
} catch (const std::exception &e) {
std::cerr << "Config error: invalid value for '" << key << "': " << value << " (" << e.what() << ")" << std::endl;
}
} }
file.close(); file.close();

View File

@ -51,19 +51,13 @@ int main(int argc, char *argv[])
gtk_init(); gtk_init();
std::cerr << "GTK Initialized" << std::endl;
// Register resources containing the application icon // Register resources containing the application icon
GResource *resource = resources_get_resource(); GResource *resource = resources_get_resource();
g_resources_register(resource); g_resources_register(resource);
std::cerr << "Resources registered" << std::endl;
gMainLoop = g_main_loop_new(nullptr, FALSE); gMainLoop = g_main_loop_new(nullptr, FALSE);
std::cerr << "Creating MainWindow" << std::endl;
MainWindow *window = new MainWindow(); MainWindow *window = new MainWindow();
std::cerr << "MainWindow created" << std::endl;
window->show(); window->show();
// Run the main event loop // Run the main event loop

View File

@ -9,11 +9,10 @@
MainWindow::MainWindow() MainWindow::MainWindow()
: window(nullptr), statusLabel(nullptr), refreshRateSpinBox(nullptr), : window(nullptr), statusLabel(nullptr), refreshRateSpinBox(nullptr),
chart(nullptr), monitor(nullptr), config(nullptr), timerID(0), timerID(0), refreshRateSec(3)
refreshRateSec(3)
{ {
monitor = new TempMonitor(); monitor = std::make_unique<TempMonitor>();
config = new ConfigManager(); config = std::make_unique<ConfigManager>();
config->load(); config->load();
refreshRateSec = config->getPollingTime(); refreshRateSec = config->getPollingTime();
@ -35,15 +34,8 @@ MainWindow::~MainWindow()
if (timerID) { if (timerID) {
g_source_remove(timerID); g_source_remove(timerID);
} }
if (monitor) {
delete monitor;
}
if (chart) {
delete chart;
}
if (config) { if (config) {
config->save(); config->save();
delete config;
} }
} }
@ -95,7 +87,8 @@ void MainWindow::setupUI()
// Refresh rate spinner // Refresh rate spinner
GtkAdjustment *adjustment = gtk_adjustment_new(refreshRateSec, 1, 60, 1, 5, 0); GtkAdjustment *adjustment = gtk_adjustment_new(refreshRateSec, 1, 60, 1, 5, 0);
refreshRateSpinBox = GTK_SPIN_BUTTON(gtk_spin_button_new(adjustment, 100, 0)); refreshRateSpinBox = GTK_SPIN_BUTTON(gtk_spin_button_new(adjustment, 1, 0));
gtk_widget_set_size_request(GTK_WIDGET(refreshRateSpinBox), 80, -1);
g_signal_connect(refreshRateSpinBox, "value-changed", G_CALLBACK(onRefreshRateChanged), this); g_signal_connect(refreshRateSpinBox, "value-changed", G_CALLBACK(onRefreshRateChanged), this);
gtk_box_append(GTK_BOX(controlBox), GTK_WIDGET(refreshRateSpinBox)); gtk_box_append(GTK_BOX(controlBox), GTK_WIDGET(refreshRateSpinBox));
@ -118,16 +111,17 @@ void MainWindow::setupUI()
gtk_box_append(GTK_BOX(mainBox), controlBox); gtk_box_append(GTK_BOX(mainBox), controlBox);
// Chart // Chart
chart = new TemperatureChart(); chart = std::make_unique<TemperatureChart>();
gtk_box_append(GTK_BOX(mainBox), chart->getWidget()); gtk_box_append(GTK_BOX(mainBox), chart->getWidget());
gtk_widget_set_vexpand(chart->getWidget(), TRUE); gtk_widget_set_vexpand(chart->getWidget(), TRUE);
// Legend box with horizontal scrolling only // Legend box with horizontal scrolling
legendBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); legendBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
GtkWidget *legendScroll = gtk_scrolled_window_new(); GtkWidget *legendScroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(legendScroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(legendScroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(legendScroll), legendBox); gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(legendScroll), legendBox);
gtk_widget_set_vexpand(legendScroll, FALSE);
gtk_widget_set_margin_top(legendScroll, 2); gtk_widget_set_margin_top(legendScroll, 2);
gtk_box_append(GTK_BOX(mainBox), legendScroll); gtk_box_append(GTK_BOX(mainBox), legendScroll);
@ -199,7 +193,6 @@ void MainWindow::saveWindowState()
void MainWindow::updateTemperatures() void MainWindow::updateTemperatures()
{ {
std::cerr << "updateTemperatures starting" << std::endl;
auto allTemps = monitor->getAllTemperatures(); auto allTemps = monitor->getAllTemperatures();
// Get current real time in milliseconds since epoch // Get current real time in milliseconds since epoch
@ -213,14 +206,10 @@ void MainWindow::updateTemperatures()
const std::string &device = deviceEntry.first; const std::string &device = deviceEntry.first;
const auto &temps = deviceEntry.second; const auto &temps = deviceEntry.second;
std::cerr << "Processing device: " << device << " with " << temps.size() << " sensors" << std::endl;
for (const auto &tempEntry : temps) { for (const auto &tempEntry : temps) {
const std::string &sensorName = tempEntry.first; const std::string &sensorName = tempEntry.first;
double temperature = tempEntry.second; double temperature = tempEntry.second;
std::cerr << " Sensor: " << sensorName << " Temp: " << temperature << std::endl;
if (chart->addTemperatureData(device, sensorName, temperature, currentTime)) { if (chart->addTemperatureData(device, sensorName, temperature, currentTime)) {
needsLegendUpdate = true; needsLegendUpdate = true;
@ -297,7 +286,7 @@ void MainWindow::updateLegend()
GtkColorDialog *dialog = gtk_color_dialog_new(); GtkColorDialog *dialog = gtk_color_dialog_new();
GtkWidget *colorButton = gtk_color_dialog_button_new(dialog); GtkWidget *colorButton = gtk_color_dialog_button_new(dialog);
gtk_color_dialog_button_set_rgba(GTK_COLOR_DIALOG_BUTTON(colorButton), &color); gtk_color_dialog_button_set_rgba(GTK_COLOR_DIALOG_BUTTON(colorButton), &color);
gtk_widget_set_size_request(colorButton, 12, 12); gtk_widget_set_size_request(colorButton, 16, 16);
// Store series id in user data // Store series id in user data
g_object_set_data_full(G_OBJECT(colorButton), "series-name", g_strdup(seriesId.c_str()), g_free); g_object_set_data_full(G_OBJECT(colorButton), "series-name", g_strdup(seriesId.c_str()), g_free);
@ -307,8 +296,8 @@ void MainWindow::updateLegend()
// Create editable label for series name // Create editable label for series name
GtkWidget *entry = gtk_entry_new(); GtkWidget *entry = gtk_entry_new();
gtk_editable_set_text(GTK_EDITABLE(entry), displayName.c_str()); gtk_editable_set_text(GTK_EDITABLE(entry), displayName.c_str());
gtk_widget_set_size_request(entry, 60, -1);
gtk_widget_add_css_class(entry, "small-entry"); gtk_widget_add_css_class(entry, "small-entry");
gtk_editable_set_width_chars(GTK_EDITABLE(entry), 8);
// Store series id in user data // Store series id in user data
g_object_set_data_full(G_OBJECT(entry), "series-name", g_strdup(seriesId.c_str()), g_free); g_object_set_data_full(G_OBJECT(entry), "series-name", g_strdup(seriesId.c_str()), g_free);

View File

@ -6,7 +6,7 @@
#include <limits> #include <limits>
#include <string> #include <string>
TemperatureChart::TemperatureChart(GtkWidget *parent) TemperatureChart::TemperatureChart()
: drawingArea(nullptr), tooltipWindow(nullptr), tooltipLabel(nullptr), : drawingArea(nullptr), tooltipWindow(nullptr), tooltipLabel(nullptr),
maxDataPoints(600), tickHandler(0), maxDataPoints(600), tickHandler(0),
minTemp(MIN_TEMP), maxTemp(MAX_TEMP), minTime(0), maxTime(0), minTemp(MIN_TEMP), maxTemp(MAX_TEMP), minTime(0), maxTime(0),
@ -52,8 +52,15 @@ TemperatureChart::TemperatureChart(GtkWidget *parent)
setupColors(); setupColors();
// Setup tick callback for redrawing // Listen for theme changes
tickHandler = g_timeout_add(100, onTick, this); GtkSettings *settings = gtk_settings_get_default();
if (settings) {
g_signal_connect_swapped(settings, "notify::gtk-theme-name",
G_CALLBACK(+[](TemperatureChart *self) {
self->updateThemeColors();
gtk_widget_queue_draw(self->drawingArea);
}), this);
}
} }
TemperatureChart::~TemperatureChart() TemperatureChart::~TemperatureChart()
@ -203,9 +210,35 @@ bool TemperatureChart::addTemperatureData(const std::string &device, const std::
} }
} }
// Update temperature range // Update temperature range dynamically
double currentMin = 1000.0;
double currentMax = -1000.0;
bool hasData = false;
for (const auto &entry : seriesMap) {
for (const auto &p : entry.second.points) {
if (p.temperature < currentMin) currentMin = p.temperature;
if (p.temperature > currentMax) currentMax = p.temperature;
hasData = true;
}
}
if (hasData) {
// Round down min to nearest 10, round up max to nearest 10
minTemp = std::floor(currentMin / 10.0) * 10.0;
maxTemp = std::ceil(currentMax / 10.0) * 10.0;
// Ensure at least 20 degrees range
if (maxTemp - minTemp < 20.0) {
maxTemp = minTemp + 20.0;
}
// Don't let it be too small
if (minTemp > 30.0) minTemp = 30.0;
} else {
minTemp = MIN_TEMP; minTemp = MIN_TEMP;
maxTemp = MAX_TEMP; maxTemp = MAX_TEMP;
}
// Update time range - keep 10 minute window // Update time range - keep 10 minute window
maxTime = timestamp; maxTime = timestamp;
@ -266,18 +299,9 @@ void TemperatureChart::setSeriesName(const std::string &seriesId, const std::str
} }
} }
gboolean TemperatureChart::onTick(gpointer userData)
{
TemperatureChart *self = static_cast<TemperatureChart*>(userData);
gtk_widget_queue_draw(self->drawingArea);
return TRUE;
}
void TemperatureChart::drawChart(GtkDrawingArea *area, cairo_t *cr, int width, int height) void TemperatureChart::drawChart(GtkDrawingArea *area, cairo_t *cr, int width, int height)
{ {
// Update theme colors before drawing
updateThemeColors();
// Background with theme color // Background with theme color
cairo_set_source_rgb(cr, bgColor.red, bgColor.green, bgColor.blue); cairo_set_source_rgb(cr, bgColor.red, bgColor.green, bgColor.blue);
cairo_paint(cr); cairo_paint(cr);