From 11931f1bc856ae34de6666423efc9257960506ce Mon Sep 17 00:00:00 2001 From: Hisham Muhammad Date: Tue, 23 Sep 2008 06:21:28 +0000 Subject: [PATCH] ACPI Battery meter contributed by Ian Hands --- BatteryMeter.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++ CRT.c | 7 +++ CRT.h | 1 + ChangeLog | 6 ++- Makefile.am | 4 +- Meter.c | 7 ++- Meter.h | 2 + String.c | 27 ++++++++++ String.h | 2 + configure.ac | 2 +- 10 files changed, 193 insertions(+), 6 deletions(-) create mode 100644 BatteryMeter.c diff --git a/BatteryMeter.c b/BatteryMeter.c new file mode 100644 index 00000000..977a1919 --- /dev/null +++ b/BatteryMeter.c @@ -0,0 +1,141 @@ +/* + htop + (C) 2004-2006 Hisham H. Muhammad + Released under the GNU GPL, see the COPYING file + in the source distribution for its full text. + + This "Meter" written by Ian P. Hands (iphands@gmail.com). +*/ + +#include "BatteryMeter.h" +#include "Meter.h" +#include "ProcessList.h" +#include "CRT.h" +#include "String.h" +#include "debug.h" + +int BatteryMeter_attributes[] = { + BATTERY +}; + +static unsigned long int parseBatInfo(const char * fileName, const unsigned short int lineNum, const unsigned short int wordNum) { + const DIR *batteryDir; + const struct dirent *pDirEnt; + + const char batteryPath[] = PROCDIR "/acpi/battery/"; + batteryDir = opendir(batteryPath); + + if (batteryDir == NULL) { + return 0; + } + + char * string; + typedef struct listLbl { char* content; struct listLbl* next; } list; + + list *myList = NULL; + list *newEntry; + + /* + Some of this is based off of code found in kismet (they claim it came from gkrellm). + Written for multi battery use... + */ + for (pDirEnt= readdir((DIR*)batteryDir); pDirEnt; pDirEnt = readdir((DIR*)batteryDir)) { + string = (char*)pDirEnt->d_name; + if(!strcmp(string, ".") || !strcmp(string, "..")) + continue; + + newEntry = calloc(1, sizeof(list)); + newEntry->next = myList; + newEntry->content = string; + myList = newEntry; + } + + unsigned long int total = 0; + for (newEntry = myList; newEntry; newEntry = newEntry->next) { + const char infoPath[30]; + const FILE * file; + char line[50]; + + sprintf((char*)infoPath, "%s%s/%s", batteryPath, newEntry->content, fileName); + + if ((file = fopen(infoPath, "r")) == NULL) { + return 0; + } + + for (unsigned short int i = 0; i < lineNum; i++){ + fgets(line, sizeof line, (FILE*)file); + } + + fclose((FILE*)file); + + const char * foundNumTmp = String_getToken(line, wordNum); + const unsigned long int foundNum = atoi(foundNumTmp); + free((char*)foundNumTmp); + + total += foundNum; + } + + free(myList); + free(newEntry); + closedir((DIR*)batteryDir); + return total; +} + +static void BatteryMeter_setValues(Meter* this, char* buffer, int len) { + FILE* file = fopen(PROCDIR "/acpi/ac_adapter/AC/state", "r"); + if (!file) + file = fopen(PROCDIR "/acpi/ac_adapter/ADP1/state", "r"); + if (!file) { + snprintf(buffer, len, "n/a"); + return; + } + + char line [100]; + fgets(line, sizeof line, file); + line[sizeof(line) - 1] = '\0'; + fclose(file); + + const unsigned long int totalFull = parseBatInfo("info", 3, 4); + const unsigned long int totalRemain = parseBatInfo("state", 5, 3); + const double percent = totalFull > 0 ? ((double)totalRemain * 100) / (double)totalFull : 0; + + if (totalFull == 0) { + snprintf(buffer, len, "n/a"); + return; + } + + this->values[0] = percent; + + const char* isOnline = String_getToken(line, 2); + + char *onAcText, *onBatteryText; + + if (this->mode == TEXT_METERMODE) { + onAcText = "%.1f%% (Running on A/C)"; + onBatteryText = "%.1f%% (Running on battery)"; + } else { + onAcText = "%.1f%%(A/C)"; + onBatteryText = "%.1f%%(bat)"; + } + + if (strcmp(String_getToken(line, 2),"on-line") == 0) { + snprintf(buffer, len, onAcText, percent); + } else { + snprintf(buffer, len, onBatteryText, percent); + } + + free((char*)isOnline); + return; +} + +MeterType BatteryMeter = { + .setValues = BatteryMeter_setValues, + .display = NULL, + .mode = TEXT_METERMODE, + .items = 1, + .total = 100.0, + .attributes = BatteryMeter_attributes, + .name = "Battery", + .uiName = "Battery", + .caption = "Battery: " +}; diff --git a/CRT.c b/CRT.c index 942e2775..3b54db11 100644 --- a/CRT.c +++ b/CRT.c @@ -56,6 +56,7 @@ typedef enum ColorElements_ { METER_VALUE, LED_COLOR, UPTIME, + BATTERY, TASKS_TOTAL, TASKS_RUNNING, SWAP, @@ -216,6 +217,7 @@ void CRT_setColors(int colorScheme) { CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = A_BOLD; CRT_colors[FAILED_SEARCH] = A_REVERSE | A_BOLD; CRT_colors[UPTIME] = A_BOLD; + CRT_colors[BATTERY] = A_BOLD; CRT_colors[LARGE_NUMBER] = A_BOLD; CRT_colors[METER_TEXT] = A_NORMAL; CRT_colors[METER_VALUE] = A_BOLD; @@ -273,6 +275,7 @@ void CRT_setColors(int colorScheme) { CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = ColorPair(Blue,White); CRT_colors[FAILED_SEARCH] = ColorPair(Red,Cyan); CRT_colors[UPTIME] = ColorPair(Yellow,White); + CRT_colors[BATTERY] = ColorPair(Yellow,White); CRT_colors[LARGE_NUMBER] = ColorPair(Red,White); CRT_colors[METER_TEXT] = ColorPair(Blue,White); CRT_colors[METER_VALUE] = ColorPair(Black,White); @@ -330,6 +333,7 @@ void CRT_setColors(int colorScheme) { CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = ColorPair(Blue,Black); CRT_colors[FAILED_SEARCH] = ColorPair(Red,Cyan); CRT_colors[UPTIME] = ColorPair(Yellow,Black); + CRT_colors[BATTERY] = ColorPair(Yellow,Black); CRT_colors[LARGE_NUMBER] = ColorPair(Red,Black); CRT_colors[METER_TEXT] = ColorPair(Blue,Black); CRT_colors[METER_VALUE] = ColorPair(Black,Black); @@ -387,6 +391,7 @@ void CRT_setColors(int colorScheme) { CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = A_BOLD | ColorPair(Yellow,Blue); CRT_colors[FAILED_SEARCH] = ColorPair(Red,Cyan); CRT_colors[UPTIME] = A_BOLD | ColorPair(Yellow,Blue); + CRT_colors[BATTERY] = A_BOLD | ColorPair(Yellow,Blue); CRT_colors[LARGE_NUMBER] = A_BOLD | ColorPair(Red,Blue); CRT_colors[METER_TEXT] = ColorPair(Cyan,Blue); CRT_colors[METER_VALUE] = A_BOLD | ColorPair(Cyan,Blue); @@ -444,6 +449,7 @@ void CRT_setColors(int colorScheme) { CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = ColorPair(Black,White); CRT_colors[FAILED_SEARCH] = ColorPair(Red,Cyan); CRT_colors[UPTIME] = ColorPair(Green,Black); + CRT_colors[BATTERY] = ColorPair(Green,Black); CRT_colors[LARGE_NUMBER] = A_BOLD | ColorPair(Red,Black); CRT_colors[METER_TEXT] = ColorPair(Cyan,Black); CRT_colors[METER_VALUE] = ColorPair(Green,Black); @@ -502,6 +508,7 @@ void CRT_setColors(int colorScheme) { CRT_colors[PANEL_HIGHLIGHT_UNFOCUS] = ColorPair(Black,White); CRT_colors[FAILED_SEARCH] = ColorPair(Red,Cyan); CRT_colors[UPTIME] = A_BOLD | ColorPair(Cyan,Black); + CRT_colors[BATTERY] = A_BOLD | ColorPair(Cyan,Black); CRT_colors[LARGE_NUMBER] = A_BOLD | ColorPair(Red,Black); CRT_colors[METER_TEXT] = ColorPair(Cyan,Black); CRT_colors[METER_VALUE] = A_BOLD | ColorPair(Cyan,Black); diff --git a/CRT.h b/CRT.h index cba59d1a..4d228351 100644 --- a/CRT.h +++ b/CRT.h @@ -58,6 +58,7 @@ typedef enum ColorElements_ { METER_VALUE, LED_COLOR, UPTIME, + BATTERY, TASKS_TOTAL, TASKS_RUNNING, SWAP, diff --git a/ChangeLog b/ChangeLog index 31b80fae..da7929b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,7 +2,11 @@ What's new in version 0.8.1 * Linux-VServer support - (thanks to Jonathan Sambrook and Benedikt Bohm) + (thanks to Jonathan Sambrook and Benedikt Bohm) +* Battery meter + (thanks to Ian Page Hands) +* BUGFIX: Fix collection of IO stats in multithreaded processes + (thanks to Gerhard Heift) What's new in version 0.8 diff --git a/Makefile.am b/Makefile.am index 5c148685..2ffda5c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,7 +17,7 @@ myhtopsources = AvailableMetersPanel.c CategoriesPanel.c CheckItem.c \ ClockMeter.c ColorsPanel.c ColumnsPanel.c CPUMeter.c CRT.c DebugMemory.c \ DisplayOptionsPanel.c FunctionBar.c Hashtable.c Header.c htop.c ListItem.c \ LoadAverageMeter.c MemoryMeter.c Meter.c MetersPanel.c Object.c Panel.c \ -Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ +BatteryMeter.c Process.c ProcessList.c RichString.c ScreenManager.c Settings.c \ SignalItem.c SignalsPanel.c String.c SwapMeter.c TasksMeter.c TraceScreen.c \ UptimeMeter.c UsersTable.c Vector.c AvailableColumnsPanel.c AffinityPanel.c @@ -25,7 +25,7 @@ myhtopheaders = AvailableColumnsPanel.h AvailableMetersPanel.h \ CategoriesPanel.h CheckItem.h ClockMeter.h ColorsPanel.h ColumnsPanel.h \ CPUMeter.h CRT.h DebugMemory.h DisplayOptionsPanel.h FunctionBar.h \ Hashtable.h Header.h htop.h ListItem.h LoadAverageMeter.h MemoryMeter.h \ -Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ +BatteryMeter.h Meter.h MetersPanel.h Object.h Panel.h ProcessList.h RichString.h \ ScreenManager.h Settings.h SignalItem.h SignalsPanel.h String.h \ SwapMeter.h TasksMeter.h TraceScreen.h UptimeMeter.h UsersTable.h Vector.h \ Process.h AffinityPanel.h diff --git a/Meter.c b/Meter.c index 7ed241d0..eec5ca56 100644 --- a/Meter.c +++ b/Meter.c @@ -96,8 +96,10 @@ typedef enum { #include "TasksMeter.h" #include "LoadAverageMeter.h" #include "UptimeMeter.h" +#include "BatteryMeter.h" #include "ClockMeter.h" + #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif @@ -120,6 +122,7 @@ MeterType* Meter_types[] = { &SwapMeter, &TasksMeter, &UptimeMeter, + &BatteryMeter, &AllCPUsMeter, NULL }; @@ -242,8 +245,8 @@ static void BarMeterMode_draw(Meter* this, int x, int y, int w) { w -= 2; attrset(CRT_colors[METER_TEXT]); - mvaddstr(y, x, this->caption); - int captionLen = strlen(this->caption); + int captionLen = 3; + mvaddnstr(y, x, this->caption, captionLen); x += captionLen; w -= captionLen; attrset(CRT_colors[BAR_BORDER]); diff --git a/Meter.h b/Meter.h index f05791bb..34f83816 100644 --- a/Meter.h +++ b/Meter.h @@ -97,8 +97,10 @@ typedef enum { #include "TasksMeter.h" #include "LoadAverageMeter.h" #include "UptimeMeter.h" +#include "BatteryMeter.h" #include "ClockMeter.h" + #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) #endif diff --git a/String.c b/String.c index a671f2c9..99b27707 100644 --- a/String.c +++ b/String.c @@ -103,3 +103,30 @@ int String_contains_i(char* s, char* match) { } return 0; } + +char* String_getToken(const char* line, const unsigned short int numMatch) { + const unsigned short int len = strlen(line); + char inWord = 0; + unsigned short int count = 0; + char match[50]; + + unsigned short int foundCount = 0; + + for (unsigned short int i = 0; i < len; i++) { + char lastState = inWord; + inWord = line[i] == ' ' ? 0:1; + + if (lastState == 0 && inWord == 1) + count++; + + if(inWord == 1){ + if (count == numMatch && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != EOF) { + match[foundCount] = line[i]; + foundCount++; + } + } + } + + match[foundCount] = '\0'; + return((char*)strdup(match)); +} diff --git a/String.h b/String.h index eed0ef63..82c958f0 100644 --- a/String.h +++ b/String.h @@ -33,4 +33,6 @@ void String_freeArray(char** s); int String_contains_i(char* s, char* match); +char* String_getToken(const char* line, const unsigned short int numMatch); + #endif diff --git a/configure.ac b/configure.ac index 4aba11fd..955b32ce 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.57) -AC_INIT([htop],[0.8],[loderunner@users.sourceforge.net]) +AC_INIT([htop],[0.8.1],[loderunner@users.sourceforge.net]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([htop.c]) AC_CONFIG_HEADER([config.h])