fixes, added window size and position persistation
This commit is contained in:
parent
50c7ebc2e2
commit
6253507917
@ -7,6 +7,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GTK REQUIRED gtk4)
|
||||
pkg_check_modules(CAIRO REQUIRED cairo)
|
||||
find_package(X11)
|
||||
|
||||
# Find glib-compile-resources tool
|
||||
find_program(GLIB_COMPILE_RESOURCES glib-compile-resources REQUIRED)
|
||||
@ -52,6 +53,10 @@ target_link_libraries(temp-monitor
|
||||
m
|
||||
)
|
||||
|
||||
if(X11_FOUND)
|
||||
target_link_libraries(temp-monitor ${X11_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_compile_options(temp-monitor PRIVATE ${GTK_CFLAGS_OTHER})
|
||||
target_compile_options(temp-monitor PRIVATE ${CAIRO_CFLAGS_OTHER})
|
||||
|
||||
|
||||
@ -17,11 +17,17 @@ public:
|
||||
// Getters and setters
|
||||
int getWindowWidth() const { return windowWidth; }
|
||||
int getWindowHeight() const { return windowHeight; }
|
||||
int getWindowX() const { return windowX; }
|
||||
int getWindowY() const { return windowY; }
|
||||
bool hasWindowPosition() const { return hasSavedWindowPosition; }
|
||||
int getPollingTime() const { return pollingTime; }
|
||||
int getHistoryLength() const { return historyLength; }
|
||||
|
||||
void setWindowWidth(int w) { windowWidth = w; }
|
||||
void setWindowHeight(int h) { windowHeight = h; }
|
||||
void setWindowX(int x) { windowX = x; hasSavedWindowPosition = true; }
|
||||
void setWindowY(int y) { windowY = y; hasSavedWindowPosition = true; }
|
||||
void clearWindowPosition() { hasSavedWindowPosition = false; }
|
||||
void setPollingTime(int t) { pollingTime = t; }
|
||||
void setHistoryLength(int m) { historyLength = m; }
|
||||
|
||||
@ -39,6 +45,9 @@ private:
|
||||
mutable std::string cachedConfigPath;
|
||||
int windowWidth;
|
||||
int windowHeight;
|
||||
int windowX;
|
||||
int windowY;
|
||||
bool hasSavedWindowPosition;
|
||||
int pollingTime;
|
||||
int historyLength;
|
||||
|
||||
|
||||
@ -27,9 +27,13 @@ private:
|
||||
static void onHistoryLengthChanged(GtkSpinButton *spinButton, gpointer userData);
|
||||
static void onClearButtonClicked(GtkButton *button, gpointer userData);
|
||||
static void onQuitButtonClicked(GtkButton *button, gpointer userData);
|
||||
static void onWindowMap(GtkWidget *widget, gpointer userData);
|
||||
static void onColorSet(GObject *object, GParamSpec *pspec, gpointer userData);
|
||||
static void onNameChanged(GtkEditable *editable, gpointer userData);
|
||||
static void onVisibilityToggled(GtkCheckButton *checkButton, gpointer userData);
|
||||
|
||||
bool getWindowPosition(int &x, int &y) const;
|
||||
void applySavedWindowPosition();
|
||||
|
||||
GtkWidget *window;
|
||||
GtkWidget *statusLabel;
|
||||
@ -42,6 +46,7 @@ private:
|
||||
int refreshRateSec;
|
||||
GtkWidget *legendBox;
|
||||
std::map<std::string, GtkWidget*> tempLabels;
|
||||
bool restoreWindowPositionPending;
|
||||
};
|
||||
|
||||
// Global main loop reference for proper shutdown
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
#include <unistd.h>
|
||||
|
||||
ConfigManager::ConfigManager()
|
||||
: windowWidth(1200), windowHeight(700), pollingTime(1), historyLength(10)
|
||||
: windowWidth(1200), windowHeight(700),
|
||||
windowX(0), windowY(0), hasSavedWindowPosition(false),
|
||||
pollingTime(1), historyLength(10)
|
||||
{
|
||||
}
|
||||
|
||||
@ -73,6 +75,12 @@ void ConfigManager::load()
|
||||
windowWidth = std::stoi(value);
|
||||
} else if (key == "window_height") {
|
||||
windowHeight = std::stoi(value);
|
||||
} else if (key == "window_x") {
|
||||
windowX = std::stoi(value);
|
||||
hasSavedWindowPosition = true;
|
||||
} else if (key == "window_y") {
|
||||
windowY = std::stoi(value);
|
||||
hasSavedWindowPosition = true;
|
||||
} else if (key == "polling_time") {
|
||||
pollingTime = std::stoi(value);
|
||||
} else if (key == "history_length") {
|
||||
@ -107,6 +115,10 @@ void ConfigManager::save()
|
||||
file << "# Auto-generated, do not edit manually\n\n";
|
||||
file << "window_width = " << windowWidth << "\n";
|
||||
file << "window_height = " << windowHeight << "\n";
|
||||
if (hasSavedWindowPosition) {
|
||||
file << "window_x = " << windowX << "\n";
|
||||
file << "window_y = " << windowY << "\n";
|
||||
}
|
||||
file << "polling_time = " << pollingTime << "\n";
|
||||
file << "history_length = " << historyLength << "\n";
|
||||
|
||||
|
||||
@ -7,10 +7,18 @@
|
||||
#include <gio/gio.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<gdk/x11/gdkx.h>)
|
||||
#include <gdk/x11/gdkx.h>
|
||||
#include <X11/Xlib.h>
|
||||
#define TEMP_MONITOR_HAS_GDK_X11 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: window(nullptr), statusLabel(nullptr),
|
||||
refreshRateSpinBox(nullptr), historyLengthSpinBox(nullptr),
|
||||
timerID(0), refreshRateSec(3)
|
||||
timerID(0), refreshRateSec(3), restoreWindowPositionPending(false)
|
||||
{
|
||||
monitor = std::make_unique<TempMonitor>();
|
||||
config = std::make_unique<ConfigManager>();
|
||||
@ -28,6 +36,7 @@ MainWindow::MainWindow()
|
||||
|
||||
// Set window size from config
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), config->getWindowWidth(), config->getWindowHeight());
|
||||
restoreWindowPositionPending = config->hasWindowPosition();
|
||||
|
||||
// Start update timer
|
||||
timerID = g_timeout_add(refreshRateSec * 1000, onUpdateTimer, this);
|
||||
@ -76,6 +85,7 @@ void MainWindow::setupUI()
|
||||
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 1200, 700);
|
||||
g_signal_connect(window, "close-request", G_CALLBACK(onDeleteWindow), this);
|
||||
g_signal_connect(window, "map", G_CALLBACK(onWindowMap), this);
|
||||
|
||||
// Main box
|
||||
GtkWidget *mainBox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||
@ -208,11 +218,22 @@ void MainWindow::onQuitButtonClicked(GtkButton *button, gpointer userData)
|
||||
|
||||
void MainWindow::saveWindowState()
|
||||
{
|
||||
int width, height;
|
||||
gtk_window_get_default_size(GTK_WINDOW(window), &width, &height);
|
||||
int width = gtk_widget_get_width(window);
|
||||
int height = gtk_widget_get_height(window);
|
||||
if (width <= 0 || height <= 0) {
|
||||
gtk_window_get_default_size(GTK_WINDOW(window), &width, &height);
|
||||
}
|
||||
|
||||
config->setWindowWidth(width > 0 ? width : 1200);
|
||||
config->setWindowHeight(height > 0 ? height : 700);
|
||||
|
||||
int posX = 0;
|
||||
int posY = 0;
|
||||
if (getWindowPosition(posX, posY)) {
|
||||
config->setWindowX(posX);
|
||||
config->setWindowY(posY);
|
||||
}
|
||||
|
||||
config->setPollingTime(refreshRateSec);
|
||||
config->save();
|
||||
}
|
||||
@ -362,6 +383,81 @@ void MainWindow::show()
|
||||
gtk_widget_set_visible(window, TRUE);
|
||||
}
|
||||
|
||||
void MainWindow::onWindowMap(GtkWidget *widget, gpointer userData)
|
||||
{
|
||||
(void)widget;
|
||||
MainWindow *self = static_cast<MainWindow*>(userData);
|
||||
self->applySavedWindowPosition();
|
||||
}
|
||||
|
||||
void MainWindow::applySavedWindowPosition()
|
||||
{
|
||||
if (!restoreWindowPositionPending || !config->hasWindowPosition()) {
|
||||
return;
|
||||
}
|
||||
|
||||
restoreWindowPositionPending = false;
|
||||
|
||||
#ifdef TEMP_MONITOR_HAS_GDK_X11
|
||||
GdkDisplay *display = gtk_widget_get_display(window);
|
||||
if (!display || !GDK_IS_X11_DISPLAY(display)) {
|
||||
return;
|
||||
}
|
||||
|
||||
GdkSurface *surface = gtk_native_get_surface(GTK_NATIVE(window));
|
||||
if (!surface || !GDK_IS_X11_SURFACE(surface)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Display *xDisplay = gdk_x11_display_get_xdisplay(GDK_X11_DISPLAY(display));
|
||||
if (!xDisplay) {
|
||||
return;
|
||||
}
|
||||
|
||||
Window xid = gdk_x11_surface_get_xid(surface);
|
||||
XMoveWindow(xDisplay, xid, config->getWindowX(), config->getWindowY());
|
||||
XFlush(xDisplay);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MainWindow::getWindowPosition(int &x, int &y) const
|
||||
{
|
||||
#ifdef TEMP_MONITOR_HAS_GDK_X11
|
||||
GdkDisplay *display = gtk_widget_get_display(window);
|
||||
if (!display || !GDK_IS_X11_DISPLAY(display)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GdkSurface *surface = gtk_native_get_surface(GTK_NATIVE(window));
|
||||
if (!surface || !GDK_IS_X11_SURFACE(surface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Display *xDisplay = gdk_x11_display_get_xdisplay(GDK_X11_DISPLAY(display));
|
||||
if (!xDisplay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Window xid = gdk_x11_surface_get_xid(surface);
|
||||
Window root = DefaultRootWindow(xDisplay);
|
||||
Window child = 0;
|
||||
int absX = 0;
|
||||
int absY = 0;
|
||||
|
||||
if (!XTranslateCoordinates(xDisplay, xid, root, 0, 0, &absX, &absY, &child)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
x = absX;
|
||||
y = absY;
|
||||
return true;
|
||||
#else
|
||||
(void)x;
|
||||
(void)y;
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void MainWindow::onColorSet(GObject *object, GParamSpec *pspec, gpointer userData)
|
||||
{
|
||||
MainWindow *self = static_cast<MainWindow*>(userData);
|
||||
|
||||
@ -6,17 +6,36 @@
|
||||
#include <sys/stat.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
bool isDebugLoggingEnabled()
|
||||
{
|
||||
static const bool enabled = [] {
|
||||
const char* envValue = std::getenv("TEMP_MONITOR_DEBUG");
|
||||
return envValue && std::strcmp(envValue, "1") == 0;
|
||||
}();
|
||||
return enabled;
|
||||
}
|
||||
}
|
||||
|
||||
TempMonitor::TempMonitor()
|
||||
{
|
||||
std::cerr << "[DEBUG] TempMonitor constructor - starting sensor discovery" << std::endl;
|
||||
if (isDebugLoggingEnabled()) {
|
||||
std::cerr << "[DEBUG] TempMonitor constructor - starting sensor discovery" << std::endl;
|
||||
}
|
||||
discoverSensors();
|
||||
std::cerr << "[DEBUG] Sensor discovery complete - found " << discoveredSensors.size() << " sensors" << std::endl;
|
||||
if (isDebugLoggingEnabled()) {
|
||||
std::cerr << "[DEBUG] Sensor discovery complete - found " << discoveredSensors.size() << " sensors" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TempMonitor::discoverSensors()
|
||||
{
|
||||
std::cerr << "[DEBUG] discoverSensors() started" << std::endl;
|
||||
const bool debug = isDebugLoggingEnabled();
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] discoverSensors() started" << std::endl;
|
||||
}
|
||||
discoveredSensors.clear();
|
||||
DIR* hwmonDir = opendir("/sys/class/hwmon");
|
||||
if (!hwmonDir) {
|
||||
@ -24,13 +43,17 @@ void TempMonitor::discoverSensors()
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "[DEBUG] Opened /sys/class/hwmon successfully" << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Opened /sys/class/hwmon successfully" << std::endl;
|
||||
}
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(hwmonDir)) != nullptr) {
|
||||
std::string hwmonName = entry->d_name;
|
||||
if (hwmonName.find("hwmon") != 0) continue;
|
||||
|
||||
std::cerr << "[DEBUG] Processing hwmon device: " << hwmonName << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Processing hwmon device: " << hwmonName << std::endl;
|
||||
}
|
||||
std::string path = "/sys/class/hwmon/" + hwmonName;
|
||||
|
||||
// Read "name" from sysfs
|
||||
@ -42,24 +65,32 @@ void TempMonitor::discoverSensors()
|
||||
nameFile.close();
|
||||
}
|
||||
|
||||
std::cerr << "[DEBUG] Device name: " << nameFromSysfs << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Device name: " << nameFromSysfs << std::endl;
|
||||
}
|
||||
|
||||
// Filter: Only interested in nvme and coretemp (CPU)
|
||||
if (nameFromSysfs != "nvme" && nameFromSysfs != "coretemp") {
|
||||
std::cerr << "[DEBUG] Skipped - not nvme or coretemp" << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Skipped - not nvme or coretemp" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
DIR* dDir = opendir(path.c_str());
|
||||
if (dDir) {
|
||||
std::cerr << "[DEBUG] Opened directory: " << path << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Opened directory: " << path << std::endl;
|
||||
}
|
||||
struct dirent* sEntry;
|
||||
while ((sEntry = readdir(dDir)) != nullptr) {
|
||||
std::string fname = sEntry->d_name;
|
||||
// Only temperature sensors (temp*_input)
|
||||
if (fname.find("temp") == 0 && fname.find("_input") != std::string::npos) {
|
||||
std::string id = fname.substr(4, fname.find("_input") - 4);
|
||||
std::cerr << "[DEBUG] Found temperature file: " << fname << " (id: " << id << ")" << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Found temperature file: " << fname << " (id: " << id << ")" << std::endl;
|
||||
}
|
||||
|
||||
// Use "label" from sysfs for sensor name if available
|
||||
std::string labelFromSysfs = "";
|
||||
@ -70,12 +101,16 @@ void TempMonitor::discoverSensors()
|
||||
labelFile.close();
|
||||
}
|
||||
|
||||
std::cerr << "[DEBUG] Label: '" << labelFromSysfs << "'" << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Label: '" << labelFromSysfs << "'" << std::endl;
|
||||
}
|
||||
|
||||
// For CPU (coretemp), filter only Package id 0 (if label exists)
|
||||
if (nameFromSysfs == "coretemp") {
|
||||
if (!labelFromSysfs.empty() && labelFromSysfs != "Package id 0") {
|
||||
std::cerr << "[DEBUG] Filtered (coretemp, not Package id 0)" << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Filtered (coretemp, not Package id 0)" << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -83,8 +118,10 @@ void TempMonitor::discoverSensors()
|
||||
std::string finalSensorName = labelFromSysfs.empty() ? "temp" + id : labelFromSysfs;
|
||||
std::string deviceDisplayName = nameFromSysfs + " (" + hwmonName + ")";
|
||||
|
||||
std::cerr << "[DEBUG] Added sensor: " << finalSensorName << " from " << deviceDisplayName << std::endl;
|
||||
std::cerr << "[DEBUG] Path: " << path + "/" + fname << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Added sensor: " << finalSensorName << " from " << deviceDisplayName << std::endl;
|
||||
std::cerr << "[DEBUG] Path: " << path + "/" + fname << std::endl;
|
||||
}
|
||||
|
||||
discoveredSensors.push_back({deviceDisplayName, finalSensorName, path + "/" + fname});
|
||||
}
|
||||
@ -95,17 +132,24 @@ void TempMonitor::discoverSensors()
|
||||
}
|
||||
}
|
||||
closedir(hwmonDir);
|
||||
std::cerr << "[DEBUG] discoverSensors() finished - total sensors: " << discoveredSensors.size() << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] discoverSensors() finished - total sensors: " << discoveredSensors.size() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> TempMonitor::getAvailableDevices()
|
||||
{
|
||||
std::cerr << "[DEBUG] getAvailableDevices() called" << std::endl;
|
||||
const bool debug = isDebugLoggingEnabled();
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] getAvailableDevices() called" << std::endl;
|
||||
}
|
||||
std::vector<std::string> devices;
|
||||
auto all = getAllTemperatures();
|
||||
for (auto const& [name, sensors] : all) {
|
||||
devices.push_back(name);
|
||||
std::cerr << "[DEBUG] Device: " << name << " with " << sensors.size() << " sensors" << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Device: " << name << " with " << sensors.size() << " sensors" << std::endl;
|
||||
}
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
@ -123,7 +167,9 @@ double TempMonitor::readTemperatureFromFile(const std::string &filePath)
|
||||
try {
|
||||
long tempMilliC = std::stol(line);
|
||||
double tempC = tempMilliC / 1000.0;
|
||||
std::cerr << "[DEBUG] Read temperature from " << filePath << ": " << tempC << "°C" << std::endl;
|
||||
if (isDebugLoggingEnabled()) {
|
||||
std::cerr << "[DEBUG] Read temperature from " << filePath << ": " << tempC << "°C" << std::endl;
|
||||
}
|
||||
return tempC;
|
||||
} catch (...) {
|
||||
std::cerr << "[ERROR] Failed to parse temperature value: " << line << std::endl;
|
||||
@ -134,11 +180,16 @@ double TempMonitor::readTemperatureFromFile(const std::string &filePath)
|
||||
|
||||
std::map<std::string, double> TempMonitor::readTemperatures(const std::string &device)
|
||||
{
|
||||
std::cerr << "[DEBUG] readTemperatures() called for device: " << device << std::endl;
|
||||
const bool debug = isDebugLoggingEnabled();
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] readTemperatures() called for device: " << device << std::endl;
|
||||
}
|
||||
auto all = getAllTemperatures();
|
||||
if (all.count(device)) {
|
||||
auto sensors = all.at(device);
|
||||
std::cerr << "[DEBUG] Found " << sensors.size() << " sensors for device" << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] Found " << sensors.size() << " sensors for device" << std::endl;
|
||||
}
|
||||
return sensors;
|
||||
}
|
||||
std::cerr << "[ERROR] Device not found: " << device << std::endl;
|
||||
@ -147,7 +198,10 @@ std::map<std::string, double> TempMonitor::readTemperatures(const std::string &d
|
||||
|
||||
std::map<std::string, std::map<std::string, double>> TempMonitor::getAllTemperatures()
|
||||
{
|
||||
std::cerr << "[DEBUG] getAllTemperatures() called" << std::endl;
|
||||
const bool debug = isDebugLoggingEnabled();
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] getAllTemperatures() called" << std::endl;
|
||||
}
|
||||
std::map<std::string, std::map<std::string, double>> allTemperatures;
|
||||
|
||||
for (const auto& sensor : discoveredSensors) {
|
||||
@ -157,6 +211,8 @@ std::map<std::string, std::map<std::string, double>> TempMonitor::getAllTemperat
|
||||
}
|
||||
}
|
||||
|
||||
std::cerr << "[DEBUG] getAllTemperatures() finished - total devices: " << allTemperatures.size() << std::endl;
|
||||
if (debug) {
|
||||
std::cerr << "[DEBUG] getAllTemperatures() finished - total devices: " << allTemperatures.size() << std::endl;
|
||||
}
|
||||
return allTemperatures;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user