From cee709762ac069885a7066a3d6ae362a4c45656f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 15 Jan 2005 22:00:13 +0000 Subject: move sources to new directory src git-svn-id: file:///home/lennart/svn/public/heatload/trunk@8 3bca8330-beed-0310-b360-ea58cfc96e4b --- src/Makefile | 46 ++++++ src/heatload.cc | 447 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 493 insertions(+) create mode 100644 src/Makefile create mode 100644 src/heatload.cc (limited to 'src') diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..2f96dd2 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,46 @@ +VERSION=0.3 +CXXFLAGS=-Wall -W -pipe -O2 -g -DVERSION=\"$(VERSION)\" `pkg-config --cflags gtkmm-2.4 gdkmm-2.4` +TAR=heatload-$(VERSION).tar.gz +SOURCES=heatload.cc +BINARY=heatload +LIBS=`pkg-config --libs gtkmm-2.4 gdkmm-2.4` +PACKAGE=heatload + +all: $(BINARY) + +$(BINARY): $(SOURCES) + $(CXX) $(CXXFLAGS) $(SOURCES) -o $(BINARY) $(LIBS) + +strip: $(BINARY) + @du -h $(BINARY) + strip -s $(BINARY) + @du -h $(BINARY) + +clean: + rm -f $(BINARY) + rm -f *~ *.bak *.tar.gz + +install: strip + install -g root -o root -m 555 $(BINARY) /usr/local/bin + +deinstall: + rm -f /usr/local/bin/$(BINARY) + +README: README.in + sed s/VERSION/$(VERSION)/ < README.in > README + +index.html: README + txt2html -t "$(PACKAGE) $(VERSION)" < README > index.html + +html: index.html + +$(TAR): clean README + tar -C.. --exclude=$(PACKAGE)/$(TAR) -czvf $(TAR) $(PACKAGE) + +tar: $(TAR) + +web: $(TAR) README + cp README $(TAR) ../../homepage/lennart/projects/$(PACKAGE)/ && $(MAKE) -C ../../homepage/lennart/projects/$(PACKAGE) + +upload: web + $(MAKE) -C ../../homepage/lennart upload diff --git a/src/heatload.cc b/src/heatload.cc new file mode 100644 index 0000000..21b8787 --- /dev/null +++ b/src/heatload.cc @@ -0,0 +1,447 @@ +#include +#include + +#include + +#include +#include +#include + +#define METER_WIDTH 300 +#define METER_HEIGHT 100 + +class MeterStruct { + +protected: + std::deque data_deque; + glong last_time; + bool modified; + +public: + MeterStruct() : last_time(0), modified(true) {}; + + void add_value(gint b); + bool is_modified() { return modified; } + void reset_modified() { modified = false; } + + void draw(const Glib::RefPtr &d, const Glib::RefPtr &g); +}; + +void MeterStruct::add_value(gint b) { + GTimeVal tv; + glong n; + + g_get_current_time(&tv); + + if (last_time == 0) + n = 1; + else if (last_time == tv.tv_sec) { + data_deque.pop_front(); + n = 1; + } else + n = tv.tv_sec - last_time; + + last_time = tv.tv_sec; + + for (; n > 0; n --) + data_deque.push_back(b); + + while (data_deque.size() > METER_WIDTH) + data_deque.pop_front(); + + modified = true; +} + +void MeterStruct::draw(const Glib::RefPtr &d, const Glib::RefPtr &g) { + std::deque copy = data_deque; + + int width, height; + d->get_size(width, height); + + gint lx = -1, ly = -1; + for (gint x = width-1; x >= 0; x--) { + if (copy.size() == 0) + break; + + gint b = copy.back(); + gint y = (100-b)*(height-1)/100; + + if (lx == -1) + d->draw_point(g, x, y); + else + d->draw_line(g, lx, ly, x, y); + + lx = x; + ly = y; + + copy.pop_back(); + } +} + +MeterStruct load_meter; +MeterStruct temperature_meter; + +class GraphDrawingArea : public Gtk::DrawingArea { + +public: + GraphDrawingArea(); + + void refresh_pixmap(); + +protected: + virtual bool on_expose_event(GdkEventExpose* event); + + Glib::RefPtr pixmap; + + Gdk::Color color0; + Gdk::Color color1; + Gdk::Color color2; +}; + +GraphDrawingArea::GraphDrawingArea(): + Gtk::DrawingArea(), color0("black"), color1("green"), color2("tomato") { + set_size_request(METER_WIDTH, METER_HEIGHT); +} + +bool GraphDrawingArea::on_expose_event(GdkEventExpose*) { + + if (!pixmap) + refresh_pixmap(); + + if (pixmap) { + Glib::RefPtr win = get_window(); + Glib::RefPtr gc = get_style()->get_fg_gc(get_state()); + win->draw_drawable(gc, pixmap, 0, 0, 0, 0); + } + + return true; +} + +void GraphDrawingArea::refresh_pixmap() { + Glib::RefPtr win = get_window(); + + if (!pixmap || load_meter.is_modified() || temperature_meter.is_modified()) { + int width, height, width2, height2; + + load_meter.reset_modified(); + temperature_meter.reset_modified(); + + win->get_size(width, height); + if (pixmap) + pixmap->get_size(width2, height2); + + if (!pixmap || width != width2 || height != height2) { + pixmap = Gdk::Pixmap::create(win, width, height); + + Glib::RefPtr cmap = win->get_colormap(); + cmap->alloc_color(color0); + cmap->alloc_color(color1); + cmap->alloc_color(color2); + } + + Glib::RefPtr gc = Gdk::GC::create(pixmap); + + gc->set_foreground(color0); + pixmap->draw_rectangle(gc, TRUE, 0, 0, width, height); + + gc->set_foreground(color1); + load_meter.draw(pixmap, gc); + + gc->set_foreground(color2); + temperature_meter.draw(pixmap, gc); + } +} + +class MainWindow : public Gtk::Window { + +protected: + + Gtk::VBox vbox; + Gtk::Label label; + Gtk::Label cpu_label, temperature_label; + Gtk::Frame frame; + GraphDrawingArea drawing_area; + Gtk::HBox hbox; + +public: + MainWindow(); + + virtual void refresh(); + virtual void update_values(gint v1, gint v2); + virtual bool on_delete_event(GdkEventAny* event); +}; + + +MainWindow::MainWindow(): + vbox(false, 5), + hbox(true, 5) { + + set_border_width(5); + set_title("Heatload"); + + label.set_markup(/*"Heatload "VERSION"\n"*/ + "Green: CPU Load; " + "Red: ACPI CPU Temperature\n" + "(Ranges from 0% to 100%, resp. 0°C to 100°C)"); + + label.set_justify(Gtk::JUSTIFY_CENTER); + label.set_alignment(.5, .5); + + cpu_label.set_justify(Gtk::JUSTIFY_CENTER); + cpu_label.set_alignment(0, 0); + + temperature_label.set_justify(Gtk::JUSTIFY_LEFT); + temperature_label.set_alignment(0, 0); + + frame.set_shadow_type(Gtk::SHADOW_IN); + frame.add(drawing_area); + + vbox.pack_start(label, false, true); + vbox.pack_start(frame, true, true); + + hbox.pack_start(cpu_label, false, true); + hbox.pack_start(temperature_label, false, true); + + vbox.pack_start(hbox, false, true); + + add(vbox); + + show_all(); +} + +void MainWindow::refresh() { + drawing_area.refresh_pixmap(); + + Gdk::Rectangle r; + r.set_x(0); + r.set_y(0); + r.set_width(drawing_area.get_width()); + r.set_height(drawing_area.get_height()); + + drawing_area.get_window()->invalidate_rect(r, false); +} + +bool MainWindow::on_delete_event(GdkEventAny* event) { + Gtk::Main::quit(); + return Gtk::Window::on_delete_event(event); +} + +void MainWindow::update_values(gint v1, gint v2) { + char txt[256]; + static gint ov1 = -1; + static gint ov2 = -1; + + if (ov1 != v1) { + snprintf(txt, sizeof(txt), "CPU Load: %i%%", v1); + cpu_label.set_markup(txt); + ov1 = v1; + } + + if (ov2 != v2) { + snprintf(txt, sizeof(txt), "CPU Temperature: %i°C", v2); + temperature_label.set_markup(txt); + ov2 = v2; + } + +} + +void failure(const Glib::ustring &txt) { + static Gtk::MessageDialog msgbox("Could not read data from /proc file system:\n"+txt+"", true, Gtk::MESSAGE_ERROR); + static bool running = false; + + if (running) + return; + + running = true; + msgbox.run(); + running = false; +} + +gint get_load_value() { + char txt[256]; + char*p; + static int ct[2][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }; + static int n = 0; + int d[4]; + int t, fd; + float v; + static FILE*f = NULL; + + if (!f && !(f = fopen("/proc/stat", "r"))) { + failure("Unable to open kernel statistics file."); + goto fail; + } + + if (!(p = fgets(txt, sizeof(txt), f))) { + failure("Unable to read from kernel statistics file."); + goto fail; + } + + fd = dup(fileno(f)); + fclose(f); + f = fdopen(fd, "r"); + g_assert(f); + fseek(f, 0, SEEK_SET); + + if (strlen(p) <= 5) { + failure("Parse failure"); + goto fail; + } + + sscanf(p+5, "%u %u %u %u", &ct[n][0], &ct[n][1], &ct[n][2], &ct[n][3]); + + t = 0; + + for (int i = 0; i < 4; i++) + t += (d[i] = abs(ct[n][i] - ct[1-n][i])); + + v = (t - d[3])/(float) t; + + n = 1-n; + + return (gint) (v*100); + +fail: + if (f) { + fclose(f); + f = NULL; + } + + return -1; +} + +FILE * fopen_first(const char *pfx, const char *sfx, const char *m) { + g_assert(pfx); + g_assert(sfx); + g_assert(m); + + DIR *dir; + struct dirent *de; + char fn[PATH_MAX]; + + if (!(dir = opendir(pfx))) + return NULL; + + while ((de = readdir(dir))) { + if (de->d_name[0] != '.') { + FILE *f; + snprintf(fn, sizeof(fn), "%s/%s/%s", pfx, de->d_name, sfx); + + if ((f = fopen(fn, m))) { + closedir(dir); + return f; + } + + break; + } + } + + closedir(dir); + return NULL; +} + +gint get_temperature_value() { + char txt[256]; + char*p; + int v, fd; + static FILE*f = NULL; + static gboolean old_acpi = FALSE; + + if (!f) { + if (!(f = fopen_first("/proc/acpi/thermal_zone", "temperature", "r"))) { + if (!(f = fopen_first("/proc/acpi/thermal", "status", "r"))) { + failure("Unable to open ACPI temperature file."); + goto fail; + } + + old_acpi = TRUE; + } + } + + if (!(p = fgets(txt, sizeof(txt), f))) { + failure("Unable to read data from ACPI temperature file."); + goto fail; + } + + fd = dup(fileno(f)); + fclose(f); + f = fdopen(fd, "r"); + g_assert(f); + fseek(f, 0, SEEK_SET); + + if (!old_acpi) { + if (strlen(p) > 20) + v = atoi(p+20); + else + v = 0; + } else { + if (strlen(p) > 15) + v = atoi(p+15); + else + v = 0; + v=((v-2732)/10); /* convert from deciKelvin to degrees Celcius */ + } + + if (v > 100) v = 100; + if (v < 0) v = 0; + + return v; + +fail: + if (f) { + fclose(f); + f = NULL; + } + + return -1; +} + +static MainWindow *mainWindow = NULL; + +int get_values() { + gint v1, v2; + static bool failed = false; + + if (failed || + (v1 = get_load_value()) < 0 || + (v2 = get_temperature_value()) < 0) + goto fail; + + load_meter.add_value(v1); + temperature_meter.add_value(v2); + + if (mainWindow) { + mainWindow->update_values((guint) v1, (guint) v2); + mainWindow->refresh(); + } + + return 0; + +fail: + failed = true; + return -1; +} + +bool timer_proc() { + if (get_values() < 0) { + Gtk::Main::quit(); + return false; + } + + return true; +} + +int main(int argc, char *argv[]) { + Gtk::Main kit(argc, argv); + + if (get_values() < 0) + return 1; + + MainWindow window; + mainWindow = &window; + Glib::signal_timeout().connect(sigc::ptr_fun(&timer_proc), 1000); + + kit.run(window); + + return 0; +} -- cgit