optimized
This commit is contained in:
parent
c8668e5f00
commit
fc1ca721fc
@ -32,6 +32,7 @@ public:
|
||||
private:
|
||||
std::string getConfigFilePath() const;
|
||||
|
||||
mutable std::string cachedConfigPath;
|
||||
int windowWidth;
|
||||
int windowHeight;
|
||||
int pollingTime;
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include "temp_monitor.h"
|
||||
#include "temperature_chart.h"
|
||||
#include "config_manager.h"
|
||||
@ -30,9 +32,9 @@ private:
|
||||
GtkWidget *window;
|
||||
GtkWidget *statusLabel;
|
||||
GtkSpinButton *refreshRateSpinBox;
|
||||
TemperatureChart *chart;
|
||||
TempMonitor *monitor;
|
||||
ConfigManager *config;
|
||||
std::unique_ptr<TemperatureChart> chart;
|
||||
std::unique_ptr<TempMonitor> monitor;
|
||||
std::unique_ptr<ConfigManager> config;
|
||||
guint timerID;
|
||||
int refreshRateSec;
|
||||
GtkWidget *legendBox;
|
||||
|
||||
@ -22,7 +22,7 @@ struct SeriesData {
|
||||
|
||||
class TemperatureChart {
|
||||
public:
|
||||
TemperatureChart(GtkWidget *parent = nullptr);
|
||||
TemperatureChart();
|
||||
~TemperatureChart();
|
||||
|
||||
GtkWidget* getWidget() const { return drawingArea; }
|
||||
@ -48,7 +48,7 @@ private:
|
||||
void redraw();
|
||||
void updateThemeColors();
|
||||
|
||||
static gboolean onTick(gpointer userData);
|
||||
|
||||
static void onLeave(GtkEventControllerMotion *motion, gpointer userData);
|
||||
|
||||
struct NearestPoint {
|
||||
|
||||
@ -5,27 +5,20 @@ window {
|
||||
|
||||
.small-entry {
|
||||
font-size: 9px;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
padding: 0px 1px;
|
||||
padding: 1px;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.small-entry:focus {
|
||||
background: rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.temp-label-small {
|
||||
font-size: 9px;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
margin-left: 1px;
|
||||
color: #ccc;
|
||||
margin-left: 2px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/* Compact box items */
|
||||
.legend-item {
|
||||
margin: 0 4px;
|
||||
padding: 0;
|
||||
margin: 0 5px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
@ -13,13 +13,18 @@ ConfigManager::ConfigManager()
|
||||
|
||||
std::string ConfigManager::getConfigFilePath() const
|
||||
{
|
||||
if (!cachedConfigPath.empty()) {
|
||||
return cachedConfigPath;
|
||||
}
|
||||
|
||||
// Get the directory of the executable using /proc/self/exe
|
||||
char path[1024];
|
||||
ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1);
|
||||
|
||||
if (len == -1) {
|
||||
// Fallback to current directory
|
||||
return "./nvme-monitor.conf";
|
||||
cachedConfigPath = "./nvme-monitor.conf";
|
||||
return cachedConfigPath;
|
||||
}
|
||||
|
||||
path[len] = '\0';
|
||||
@ -29,10 +34,12 @@ std::string ConfigManager::getConfigFilePath() const
|
||||
size_t lastSlash = fullPath.find_last_of('/');
|
||||
if (lastSlash != std::string::npos) {
|
||||
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()
|
||||
@ -61,6 +68,7 @@ void ConfigManager::load()
|
||||
value.erase(0, value.find_first_not_of(" \t"));
|
||||
value.erase(value.find_last_not_of(" \t") + 1);
|
||||
|
||||
try {
|
||||
if (key == "window_width") {
|
||||
windowWidth = std::stoi(value);
|
||||
} else if (key == "window_height") {
|
||||
@ -72,6 +80,9 @@ void ConfigManager::load()
|
||||
} else if (key.find("name_") == 0) {
|
||||
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();
|
||||
|
||||
@ -51,19 +51,13 @@ int main(int argc, char *argv[])
|
||||
|
||||
gtk_init();
|
||||
|
||||
std::cerr << "GTK Initialized" << std::endl;
|
||||
|
||||
// Register resources containing the application icon
|
||||
GResource *resource = resources_get_resource();
|
||||
g_resources_register(resource);
|
||||
|
||||
std::cerr << "Resources registered" << std::endl;
|
||||
|
||||
gMainLoop = g_main_loop_new(nullptr, FALSE);
|
||||
|
||||
std::cerr << "Creating MainWindow" << std::endl;
|
||||
MainWindow *window = new MainWindow();
|
||||
std::cerr << "MainWindow created" << std::endl;
|
||||
window->show();
|
||||
|
||||
// Run the main event loop
|
||||
|
||||
@ -9,11 +9,10 @@
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: window(nullptr), statusLabel(nullptr), refreshRateSpinBox(nullptr),
|
||||
chart(nullptr), monitor(nullptr), config(nullptr), timerID(0),
|
||||
refreshRateSec(3)
|
||||
timerID(0), refreshRateSec(3)
|
||||
{
|
||||
monitor = new TempMonitor();
|
||||
config = new ConfigManager();
|
||||
monitor = std::make_unique<TempMonitor>();
|
||||
config = std::make_unique<ConfigManager>();
|
||||
config->load();
|
||||
|
||||
refreshRateSec = config->getPollingTime();
|
||||
@ -35,15 +34,8 @@ MainWindow::~MainWindow()
|
||||
if (timerID) {
|
||||
g_source_remove(timerID);
|
||||
}
|
||||
if (monitor) {
|
||||
delete monitor;
|
||||
}
|
||||
if (chart) {
|
||||
delete chart;
|
||||
}
|
||||
if (config) {
|
||||
config->save();
|
||||
delete config;
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +87,8 @@ void MainWindow::setupUI()
|
||||
|
||||
// Refresh rate spinner
|
||||
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);
|
||||
gtk_box_append(GTK_BOX(controlBox), GTK_WIDGET(refreshRateSpinBox));
|
||||
|
||||
@ -118,16 +111,17 @@ void MainWindow::setupUI()
|
||||
gtk_box_append(GTK_BOX(mainBox), controlBox);
|
||||
|
||||
// Chart
|
||||
chart = new TemperatureChart();
|
||||
chart = std::make_unique<TemperatureChart>();
|
||||
gtk_box_append(GTK_BOX(mainBox), chart->getWidget());
|
||||
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);
|
||||
|
||||
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_child(GTK_SCROLLED_WINDOW(legendScroll), legendBox);
|
||||
gtk_widget_set_vexpand(legendScroll, FALSE);
|
||||
gtk_widget_set_margin_top(legendScroll, 2);
|
||||
|
||||
gtk_box_append(GTK_BOX(mainBox), legendScroll);
|
||||
@ -199,7 +193,6 @@ void MainWindow::saveWindowState()
|
||||
|
||||
void MainWindow::updateTemperatures()
|
||||
{
|
||||
std::cerr << "updateTemperatures starting" << std::endl;
|
||||
auto allTemps = monitor->getAllTemperatures();
|
||||
|
||||
// Get current real time in milliseconds since epoch
|
||||
@ -213,14 +206,10 @@ void MainWindow::updateTemperatures()
|
||||
const std::string &device = deviceEntry.first;
|
||||
const auto &temps = deviceEntry.second;
|
||||
|
||||
std::cerr << "Processing device: " << device << " with " << temps.size() << " sensors" << std::endl;
|
||||
|
||||
for (const auto &tempEntry : temps) {
|
||||
const std::string &sensorName = tempEntry.first;
|
||||
double temperature = tempEntry.second;
|
||||
|
||||
std::cerr << " Sensor: " << sensorName << " Temp: " << temperature << std::endl;
|
||||
|
||||
if (chart->addTemperatureData(device, sensorName, temperature, currentTime)) {
|
||||
needsLegendUpdate = true;
|
||||
|
||||
@ -297,7 +286,7 @@ void MainWindow::updateLegend()
|
||||
GtkColorDialog *dialog = gtk_color_dialog_new();
|
||||
GtkWidget *colorButton = gtk_color_dialog_button_new(dialog);
|
||||
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
|
||||
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
|
||||
GtkWidget *entry = gtk_entry_new();
|
||||
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_editable_set_width_chars(GTK_EDITABLE(entry), 8);
|
||||
|
||||
// Store series id in user data
|
||||
g_object_set_data_full(G_OBJECT(entry), "series-name", g_strdup(seriesId.c_str()), g_free);
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
TemperatureChart::TemperatureChart(GtkWidget *parent)
|
||||
TemperatureChart::TemperatureChart()
|
||||
: drawingArea(nullptr), tooltipWindow(nullptr), tooltipLabel(nullptr),
|
||||
maxDataPoints(600), tickHandler(0),
|
||||
minTemp(MIN_TEMP), maxTemp(MAX_TEMP), minTime(0), maxTime(0),
|
||||
@ -52,8 +52,15 @@ TemperatureChart::TemperatureChart(GtkWidget *parent)
|
||||
|
||||
setupColors();
|
||||
|
||||
// Setup tick callback for redrawing
|
||||
tickHandler = g_timeout_add(100, onTick, this);
|
||||
// Listen for theme changes
|
||||
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()
|
||||
@ -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;
|
||||
maxTemp = MAX_TEMP;
|
||||
}
|
||||
|
||||
// Update time range - keep 10 minute window
|
||||
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)
|
||||
{
|
||||
// Update theme colors before drawing
|
||||
updateThemeColors();
|
||||
|
||||
// Background with theme color
|
||||
cairo_set_source_rgb(cr, bgColor.red, bgColor.green, bgColor.blue);
|
||||
cairo_paint(cr);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user