From cfa47369d8af6513da2c9ba7c8f8c10fd911df6c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 21:08:54 +0800 Subject: [PATCH 01/12] Obsolete the CUSTOM_METERMODE use in default mode The use of CUSTOM_METERMODE value in meter default mode was a bad design. There are no meter that really has a "custom" mode to work with and currently that value serves as a useless placeholder that hides the real default mode for a meter. Replace CUSTOM_METERMODE in `defaultMode` of all meters with the real intended default modes. Currently only CPU meters and MemorySwapMeter used this, and their real defaults are BAR_METERMODE. In Meter_setMode(), remove the special treatment of `defaultMode == CUSTOM_METERMODE`, Meter_setMode() still calls the `updateMode` function for custom treatment when it's present for a meter class. As CUSTOM_METERMODE is obsolete from `defaultMode`, the init functions of CPU meters and MemorySwapMeter need to be adjusted to avoid incomplete initialization (Meter.draw function bring NULL). Signed-off-by: Kang-Che Sung --- CPUMeter.c | 28 +++++++++++++++------------- MemorySwapMeter.c | 6 ++++-- Meter.c | 7 +++---- Meter.h | 1 - 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/CPUMeter.c b/CPUMeter.c index afcddeb1a..93cf099e9 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -251,8 +251,10 @@ static void CPUMeterCommonInit(Meter* this, int ncol) { Meter_init(meters[i]); } - if (this->mode == 0) + if (this->mode == 0) { this->mode = BAR_METERMODE; + this->draw = Meter_drawFn(this); + } int h = Meter_modes[this->mode]->h; this->h = h * ((count + ncol - 1) / ncol); @@ -380,7 +382,7 @@ const MeterClass AllCPUsMeter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .total = 100.0, .attributes = CPUMeter_attributes, .name = "AllCPUs", @@ -400,7 +402,7 @@ const MeterClass AllCPUs2Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -421,7 +423,7 @@ const MeterClass LeftCPUsMeter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -442,7 +444,7 @@ const MeterClass RightCPUsMeter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -463,7 +465,7 @@ const MeterClass LeftCPUs2Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -484,7 +486,7 @@ const MeterClass RightCPUs2Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -505,7 +507,7 @@ const MeterClass AllCPUs4Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -526,7 +528,7 @@ const MeterClass LeftCPUs4Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -547,7 +549,7 @@ const MeterClass RightCPUs4Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -568,7 +570,7 @@ const MeterClass AllCPUs8Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -589,7 +591,7 @@ const MeterClass LeftCPUs8Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, @@ -610,7 +612,7 @@ const MeterClass RightCPUs8Meter_class = { .display = CPUMeter_display }, .updateValues = AllCPUsMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .total = 100.0, .attributes = CPUMeter_attributes, diff --git a/MemorySwapMeter.c b/MemorySwapMeter.c index 82eddee21..6aea784fa 100644 --- a/MemorySwapMeter.c +++ b/MemorySwapMeter.c @@ -65,8 +65,10 @@ static void MemorySwapMeter_init(Meter* this) { if (Meter_initFn(data->swapMeter)) Meter_init(data->swapMeter); - if (this->mode == 0) + if (this->mode == 0) { this->mode = BAR_METERMODE; + this->draw = Meter_drawFn(this); + } this->h = MAXIMUM(Meter_modes[data->memoryMeter->mode]->h, Meter_modes[data->swapMeter->mode]->h); } @@ -97,7 +99,7 @@ const MeterClass MemorySwapMeter_class = { .delete = Meter_delete, }, .updateValues = MemorySwapMeter_updateValues, - .defaultMode = CUSTOM_METERMODE, + .defaultMode = BAR_METERMODE, .isMultiColumn = true, .name = "MemorySwap", .uiName = "Memory & Swap", diff --git a/Meter.c b/Meter.c index 938b907b1..1fc7e9db2 100644 --- a/Meter.c +++ b/Meter.c @@ -122,11 +122,10 @@ void Meter_setMode(Meter* this, int modeIndex) { } assert(modeIndex < LAST_METERMODE); - if (Meter_defaultMode(this) == CUSTOM_METERMODE) { + if (Meter_updateModeFn(this)) { + assert(Meter_drawFn(this)); this->draw = Meter_drawFn(this); - if (Meter_updateModeFn(this)) { - Meter_updateMode(this, modeIndex); - } + Meter_updateMode(this, modeIndex); } else { assert(modeIndex >= 1); free(this->drawData.values); diff --git a/Meter.h b/Meter.h index 17d77f3e1..ce474da08 100644 --- a/Meter.h +++ b/Meter.h @@ -87,7 +87,6 @@ typedef struct MeterClass_ { #define Meter_getUiName(this_,n_,l_) As_Meter(this_)->getUiName((const Meter*)(this_),n_,l_) #define Meter_getCaptionFn(this_) As_Meter(this_)->getCaption #define Meter_getCaption(this_) (Meter_getCaptionFn(this_) ? As_Meter(this_)->getCaption((const Meter*)(this_)) : (this_)->caption) -#define Meter_defaultMode(this_) As_Meter(this_)->defaultMode #define Meter_attributes(this_) As_Meter(this_)->attributes #define Meter_name(this_) As_Meter(this_)->name #define Meter_uiName(this_) As_Meter(this_)->uiName From 9198181b568492a7493ee92813a2b89bda87b710 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 21:30:46 +0800 Subject: [PATCH 02/12] Don't initialize meter mode in custom meter init functions Let the respective `MeterClass.updateMode` functions initialize the meter mode instead. The `updateMode` function is always called after the `MeterClass.init` function by `Meter_new()`. This not only simplifies the init functions of meter subclasses, but avoids the use of the global `Meter_modes` array when it's unnecessary. Signed-off-by: Kang-Che Sung --- CPUMeter.c | 50 ++++++++++++----------------------------------- MemorySwapMeter.c | 11 +++-------- 2 files changed, 16 insertions(+), 45 deletions(-) diff --git a/CPUMeter.c b/CPUMeter.c index 93cf099e9..2f777b2e7 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -233,7 +233,7 @@ static void AllCPUsMeter_updateValues(Meter* this) { Meter_updateValues(meters[i]); } -static void CPUMeterCommonInit(Meter* this, int ncol) { +static void CPUMeterCommonInit(Meter* this) { unsigned int cpus = this->host->existingCPUs; CPUMeterData* data = this->meterData; if (!data) { @@ -250,14 +250,6 @@ static void CPUMeterCommonInit(Meter* this, int ncol) { Meter_init(meters[i]); } - - if (this->mode == 0) { - this->mode = BAR_METERMODE; - this->draw = Meter_drawFn(this); - } - - int h = Meter_modes[this->mode]->h; - this->h = h * ((count + ncol - 1) / ncol); } static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) { @@ -284,34 +276,18 @@ static void AllCPUsMeter_done(Meter* this) { free(data); } -static void SingleColCPUsMeter_init(Meter* this) { - CPUMeterCommonInit(this, 1); -} - static void SingleColCPUsMeter_updateMode(Meter* this, int mode) { CPUMeterCommonUpdateMode(this, mode, 1); } -static void DualColCPUsMeter_init(Meter* this) { - CPUMeterCommonInit(this, 2); -} - static void DualColCPUsMeter_updateMode(Meter* this, int mode) { CPUMeterCommonUpdateMode(this, mode, 2); } -static void QuadColCPUsMeter_init(Meter* this) { - CPUMeterCommonInit(this, 4); -} - static void QuadColCPUsMeter_updateMode(Meter* this, int mode) { CPUMeterCommonUpdateMode(this, mode, 4); } -static void OctoColCPUsMeter_init(Meter* this) { - CPUMeterCommonInit(this, 8); -} - static void OctoColCPUsMeter_updateMode(Meter* this, int mode) { CPUMeterCommonUpdateMode(this, mode, 8); } @@ -390,7 +366,7 @@ const MeterClass AllCPUsMeter_class = { .description = "CPUs (1/1): all CPUs", .caption = "CPU", .draw = SingleColCPUsMeter_draw, - .init = SingleColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = SingleColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -411,7 +387,7 @@ const MeterClass AllCPUs2Meter_class = { .description = "CPUs (1&2/2): all CPUs in 2 shorter columns", .caption = "CPU", .draw = DualColCPUsMeter_draw, - .init = DualColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = DualColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -432,7 +408,7 @@ const MeterClass LeftCPUsMeter_class = { .description = "CPUs (1/2): first half of list", .caption = "CPU", .draw = SingleColCPUsMeter_draw, - .init = SingleColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = SingleColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -453,7 +429,7 @@ const MeterClass RightCPUsMeter_class = { .description = "CPUs (2/2): second half of list", .caption = "CPU", .draw = SingleColCPUsMeter_draw, - .init = SingleColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = SingleColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -474,7 +450,7 @@ const MeterClass LeftCPUs2Meter_class = { .description = "CPUs (1&2/4): first half in 2 shorter columns", .caption = "CPU", .draw = DualColCPUsMeter_draw, - .init = DualColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = DualColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -495,7 +471,7 @@ const MeterClass RightCPUs2Meter_class = { .description = "CPUs (3&4/4): second half in 2 shorter columns", .caption = "CPU", .draw = DualColCPUsMeter_draw, - .init = DualColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = DualColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -516,7 +492,7 @@ const MeterClass AllCPUs4Meter_class = { .description = "CPUs (1&2&3&4/4): all CPUs in 4 shorter columns", .caption = "CPU", .draw = QuadColCPUsMeter_draw, - .init = QuadColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = QuadColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -537,7 +513,7 @@ const MeterClass LeftCPUs4Meter_class = { .description = "CPUs (1-4/8): first half in 4 shorter columns", .caption = "CPU", .draw = QuadColCPUsMeter_draw, - .init = QuadColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = QuadColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -558,7 +534,7 @@ const MeterClass RightCPUs4Meter_class = { .description = "CPUs (5-8/8): second half in 4 shorter columns", .caption = "CPU", .draw = QuadColCPUsMeter_draw, - .init = QuadColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = QuadColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -579,7 +555,7 @@ const MeterClass AllCPUs8Meter_class = { .description = "CPUs (1-8/8): all CPUs in 8 shorter columns", .caption = "CPU", .draw = OctoColCPUsMeter_draw, - .init = OctoColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = OctoColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -600,7 +576,7 @@ const MeterClass LeftCPUs8Meter_class = { .description = "CPUs (1-8/16): first half in 8 shorter columns", .caption = "CPU", .draw = OctoColCPUsMeter_draw, - .init = OctoColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = OctoColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; @@ -621,7 +597,7 @@ const MeterClass RightCPUs8Meter_class = { .description = "CPUs (9-16/16): second half in 8 shorter columns", .caption = "CPU", .draw = OctoColCPUsMeter_draw, - .init = OctoColCPUsMeter_init, + .init = CPUMeterCommonInit, .updateMode = OctoColCPUsMeter_updateMode, .done = AllCPUsMeter_done }; diff --git a/MemorySwapMeter.c b/MemorySwapMeter.c index 6aea784fa..6e9f45c20 100644 --- a/MemorySwapMeter.c +++ b/MemorySwapMeter.c @@ -60,17 +60,12 @@ static void MemorySwapMeter_init(Meter* this) { if (!data->swapMeter) data->swapMeter = Meter_new(this->host, 0, (const MeterClass*) Class(SwapMeter)); - if (Meter_initFn(data->memoryMeter)) + if (Meter_initFn(data->memoryMeter)) { Meter_init(data->memoryMeter); - if (Meter_initFn(data->swapMeter)) + } + if (Meter_initFn(data->swapMeter)) { Meter_init(data->swapMeter); - - if (this->mode == 0) { - this->mode = BAR_METERMODE; - this->draw = Meter_drawFn(this); } - - this->h = MAXIMUM(Meter_modes[data->memoryMeter->mode]->h, Meter_modes[data->swapMeter->mode]->h); } static void MemorySwapMeter_updateMode(Meter* this, int mode) { From 98e66cd5d269192ad5e7e924d5345fc3f8896113 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 21:33:25 +0800 Subject: [PATCH 03/12] Remove CUSTOM_METERMODE MeterModeId Meter mode ID 0 will now be reserved. --- Meter.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Meter.h b/Meter.h index ce474da08..a587e4b5b 100644 --- a/Meter.h +++ b/Meter.h @@ -124,8 +124,8 @@ typedef struct MeterMode_ { } MeterMode; typedef enum { - CUSTOM_METERMODE = 0, - BAR_METERMODE, + /* Meter mode 0 is reserved */ + BAR_METERMODE = 1, TEXT_METERMODE, GRAPH_METERMODE, LED_METERMODE, From ef434c99c269ecc8584614bae14611cada7a4ae0 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Tue, 16 Apr 2024 20:18:08 +0800 Subject: [PATCH 04/12] CPUMeter: Read height from sub-meter objects The Meter objects have their own 'h' properties. Avoid access to the `Meter_modes` array. Signed-off-by: Kang-Che Sung --- CPUMeter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CPUMeter.c b/CPUMeter.c index 2f777b2e7..58f4455de 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -9,6 +9,7 @@ in the source distribution for its full text. #include "CPUMeter.h" +#include #include #include #include @@ -256,12 +257,13 @@ static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) { CPUMeterData* data = this->meterData; Meter** meters = data->meters; this->mode = mode; - int h = Meter_modes[mode]->h; int start, count; AllCPUsMeter_getRange(this, &start, &count); for (int i = 0; i < count; i++) { Meter_setMode(meters[i], mode); } + int h = meters[0]->h; + assert(h > 0); this->h = h * ((count + ncol - 1) / ncol); } From d136bf7cc7d6d2c4dbb91bdfb9313d8d32fcebe7 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Tue, 16 Apr 2024 20:18:08 +0800 Subject: [PATCH 05/12] MemorySwapMeter: Read height from sub-meter objects The Meter objects have their own 'h' properties. Avoid access to the `Meter_modes` array. Signed-off-by: Kang-Che Sung --- MemorySwapMeter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MemorySwapMeter.c b/MemorySwapMeter.c index 6e9f45c20..2e49817d4 100644 --- a/MemorySwapMeter.c +++ b/MemorySwapMeter.c @@ -76,7 +76,7 @@ static void MemorySwapMeter_updateMode(Meter* this, int mode) { Meter_setMode(data->memoryMeter, mode); Meter_setMode(data->swapMeter, mode); - this->h = MAXIMUM(Meter_modes[data->memoryMeter->mode]->h, Meter_modes[data->swapMeter->mode]->h); + this->h = MAXIMUM(data->memoryMeter->h, data->swapMeter->h); } static void MemorySwapMeter_done(Meter* this) { From 1b15d292304a2a1b4eb848503e50103cb4f63e93 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 21:46:48 +0800 Subject: [PATCH 06/12] Reorder Meter.c sections. No code changes. This section reordering is a prerequisite to privatizing the `Meter_modes` array. --- Meter.c | 250 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 127 insertions(+), 123 deletions(-) diff --git a/Meter.c b/Meter.c index 1fc7e9db2..fbfc29589 100644 --- a/Meter.c +++ b/Meter.c @@ -26,83 +26,7 @@ in the source distribution for its full text. #define GRAPH_HEIGHT 4 /* Unit: rows (lines) */ -const MeterClass Meter_class = { - .super = { - .extends = Class(Object) - } -}; - -Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type) { - Meter* this = xCalloc(1, sizeof(Meter)); - Object_setClass(this, type); - this->h = 1; - this->param = param; - this->host = host; - this->curItems = type->maxItems; - this->curAttributes = NULL; - this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL; - this->total = type->total; - this->caption = xStrdup(type->caption); - if (Meter_initFn(this)) { - Meter_init(this); - } - Meter_setMode(this, type->defaultMode); - return this; -} - -/* Converts 'value' in kibibytes into a human readable string. - Example output strings: "0K", "1023K", "98.7M" and "1.23G" */ -int Meter_humanUnit(char* buffer, double value, size_t size) { - size_t i = 0; - - assert(value >= 0.0); - while (value >= ONE_K) { - if (i >= ARRAYSIZE(unitPrefixes) - 1) { - if (value > 9999.0) { - return xSnprintf(buffer, size, "inf"); - } - break; - } - - value /= ONE_K; - ++i; - } - - int precision = 0; - - if (i > 0) { - // Fraction digits for mebibytes and above - precision = value <= 99.9 ? (value <= 9.99 ? 2 : 1) : 0; - - // Round up if 'value' is in range (99.9, 100) or (9.99, 10) - if (precision < 2) { - double limit = precision == 1 ? 10.0 : 100.0; - if (value < limit) { - value = limit; - } - } - } - - return xSnprintf(buffer, size, "%.*f%c", precision, value, unitPrefixes[i]); -} - -void Meter_delete(Object* cast) { - if (!cast) - return; - - Meter* this = (Meter*) cast; - if (Meter_doneFn(this)) { - Meter_done(this); - } - free(this->drawData.values); - free(this->caption); - free(this->values); - free(this); -} - -void Meter_setCaption(Meter* this, const char* caption) { - free_and_xStrdup(&this->caption, caption); -} +/* Meter drawing modes */ static inline void Meter_displayBuffer(const Meter* this, RichString* out) { if (Object_displayFn(this)) { @@ -112,52 +36,6 @@ static inline void Meter_displayBuffer(const Meter* this, RichString* out) { } } -void Meter_setMode(Meter* this, int modeIndex) { - if (modeIndex > 0 && modeIndex == this->mode) { - return; - } - - if (!modeIndex) { - modeIndex = 1; - } - - assert(modeIndex < LAST_METERMODE); - if (Meter_updateModeFn(this)) { - assert(Meter_drawFn(this)); - this->draw = Meter_drawFn(this); - Meter_updateMode(this, modeIndex); - } else { - assert(modeIndex >= 1); - free(this->drawData.values); - this->drawData.values = NULL; - this->drawData.nValues = 0; - - const MeterMode* mode = Meter_modes[modeIndex]; - this->draw = mode->draw; - this->h = mode->h; - } - this->mode = modeIndex; -} - -ListItem* Meter_toListItem(const Meter* this, bool moving) { - char mode[20]; - if (this->mode) { - xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName); - } else { - mode[0] = '\0'; - } - char name[32]; - if (Meter_getUiNameFn(this)) - Meter_getUiName(this, name, sizeof(name)); - else - xSnprintf(name, sizeof(name), "%s", Meter_uiName(this)); - char buffer[50]; - xSnprintf(buffer, sizeof(buffer), "%s%s", name, mode); - ListItem* li = ListItem_new(buffer, 0); - li->moving = moving; - return li; -} - /* ---------- TextMeterMode ---------- */ static void TextMeterMode_draw(Meter* this, int x, int y, int w) { @@ -479,6 +357,132 @@ const MeterMode* const Meter_modes[] = { NULL }; +/* Meter class and methods */ + +const MeterClass Meter_class = { + .super = { + .extends = Class(Object) + } +}; + +Meter* Meter_new(const Machine* host, unsigned int param, const MeterClass* type) { + Meter* this = xCalloc(1, sizeof(Meter)); + Object_setClass(this, type); + this->h = 1; + this->param = param; + this->host = host; + this->curItems = type->maxItems; + this->curAttributes = NULL; + this->values = type->maxItems ? xCalloc(type->maxItems, sizeof(double)) : NULL; + this->total = type->total; + this->caption = xStrdup(type->caption); + if (Meter_initFn(this)) { + Meter_init(this); + } + Meter_setMode(this, type->defaultMode); + return this; +} + +/* Converts 'value' in kibibytes into a human readable string. + Example output strings: "0K", "1023K", "98.7M" and "1.23G" */ +int Meter_humanUnit(char* buffer, double value, size_t size) { + size_t i = 0; + + assert(value >= 0.0); + while (value >= ONE_K) { + if (i >= ARRAYSIZE(unitPrefixes) - 1) { + if (value > 9999.0) { + return xSnprintf(buffer, size, "inf"); + } + break; + } + + value /= ONE_K; + ++i; + } + + int precision = 0; + + if (i > 0) { + // Fraction digits for mebibytes and above + precision = value <= 99.9 ? (value <= 9.99 ? 2 : 1) : 0; + + // Round up if 'value' is in range (99.9, 100) or (9.99, 10) + if (precision < 2) { + double limit = precision == 1 ? 10.0 : 100.0; + if (value < limit) { + value = limit; + } + } + } + + return xSnprintf(buffer, size, "%.*f%c", precision, value, unitPrefixes[i]); +} + +void Meter_delete(Object* cast) { + if (!cast) + return; + + Meter* this = (Meter*) cast; + if (Meter_doneFn(this)) { + Meter_done(this); + } + free(this->drawData.values); + free(this->caption); + free(this->values); + free(this); +} + +void Meter_setCaption(Meter* this, const char* caption) { + free_and_xStrdup(&this->caption, caption); +} + +void Meter_setMode(Meter* this, int modeIndex) { + if (modeIndex > 0 && modeIndex == this->mode) { + return; + } + + if (!modeIndex) { + modeIndex = 1; + } + + assert(modeIndex < LAST_METERMODE); + if (Meter_updateModeFn(this)) { + assert(Meter_drawFn(this)); + this->draw = Meter_drawFn(this); + Meter_updateMode(this, modeIndex); + } else { + assert(modeIndex >= 1); + free(this->drawData.values); + this->drawData.values = NULL; + this->drawData.nValues = 0; + + const MeterMode* mode = Meter_modes[modeIndex]; + this->draw = mode->draw; + this->h = mode->h; + } + this->mode = modeIndex; +} + +ListItem* Meter_toListItem(const Meter* this, bool moving) { + char mode[20]; + if (this->mode) { + xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName); + } else { + mode[0] = '\0'; + } + char name[32]; + if (Meter_getUiNameFn(this)) + Meter_getUiName(this, name, sizeof(name)); + else + xSnprintf(name, sizeof(name), "%s", Meter_uiName(this)); + char buffer[50]; + xSnprintf(buffer, sizeof(buffer), "%s%s", name, mode); + ListItem* li = ListItem_new(buffer, 0); + li->moving = moving; + return li; +} + /* Blank meter */ static void BlankMeter_updateValues(Meter* this) { From 3ec405c461421e119cd90a2d46b9c0fae3bfde73 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 21:51:08 +0800 Subject: [PATCH 07/12] Make 'Meter_modes' private and simplify its structure All client codes that access this global `Meter_modes` array have been replaced in previous commits, thus it's no longer necessary to keep this internal information (draw functions, default heights, etc.) public. It was also a bad idea when the client codes need to avoid accessing `Meter_modes[0]` (which is reserved and contains null information) by themselves. Signed-off-by: Kang-Che Sung --- Meter.c | 67 +++++++++++++++++++++++++++++---------------------------- Meter.h | 8 ------- 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/Meter.c b/Meter.c index fbfc29589..25f559a17 100644 --- a/Meter.c +++ b/Meter.c @@ -26,6 +26,12 @@ in the source distribution for its full text. #define GRAPH_HEIGHT 4 /* Unit: rows (lines) */ +typedef struct MeterMode_ { + Meter_Draw draw; + const char* uiName; + int h; +} MeterMode; + /* Meter drawing modes */ static inline void Meter_displayBuffer(const Meter* this, RichString* out) { @@ -324,37 +330,32 @@ static void LEDMeterMode_draw(Meter* this, int x, int y, int w) { RichString_delete(&out); } -static MeterMode BarMeterMode = { - .uiName = "Bar", - .h = 1, - .draw = BarMeterMode_draw, -}; - -static MeterMode TextMeterMode = { - .uiName = "Text", - .h = 1, - .draw = TextMeterMode_draw, -}; - -static MeterMode GraphMeterMode = { - .uiName = "Graph", - .h = GRAPH_HEIGHT, - .draw = GraphMeterMode_draw, -}; - -static MeterMode LEDMeterMode = { - .uiName = "LED", - .h = 3, - .draw = LEDMeterMode_draw, -}; - -const MeterMode* const Meter_modes[] = { - NULL, - &BarMeterMode, - &TextMeterMode, - &GraphMeterMode, - &LEDMeterMode, - NULL +static const MeterMode Meter_modes[] = { + [0] = { + .uiName = NULL, + .h = 0, + .draw = NULL, + }, + [BAR_METERMODE] = { + .uiName = "Bar", + .h = 1, + .draw = BarMeterMode_draw, + }, + [TEXT_METERMODE] = { + .uiName = "Text", + .h = 1, + .draw = TextMeterMode_draw, + }, + [GRAPH_METERMODE] = { + .uiName = "Graph", + .h = GRAPH_HEIGHT, + .draw = GraphMeterMode_draw, + }, + [LED_METERMODE] = { + .uiName = "LED", + .h = 3, + .draw = LEDMeterMode_draw, + }, }; /* Meter class and methods */ @@ -457,7 +458,7 @@ void Meter_setMode(Meter* this, int modeIndex) { this->drawData.values = NULL; this->drawData.nValues = 0; - const MeterMode* mode = Meter_modes[modeIndex]; + const MeterMode* mode = &Meter_modes[modeIndex]; this->draw = mode->draw; this->h = mode->h; } @@ -467,7 +468,7 @@ void Meter_setMode(Meter* this, int modeIndex) { ListItem* Meter_toListItem(const Meter* this, bool moving) { char mode[20]; if (this->mode) { - xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode]->uiName); + xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode].uiName); } else { mode[0] = '\0'; } diff --git a/Meter.h b/Meter.h index a587e4b5b..1a16d19ae 100644 --- a/Meter.h +++ b/Meter.h @@ -117,12 +117,6 @@ struct Meter_ { void* meterData; }; -typedef struct MeterMode_ { - Meter_Draw draw; - const char* uiName; - int h; -} MeterMode; - typedef enum { /* Meter mode 0 is reserved */ BAR_METERMODE = 1, @@ -155,8 +149,6 @@ void Meter_setMode(Meter* this, int modeIndex); ListItem* Meter_toListItem(const Meter* this, bool moving); -extern const MeterMode* const Meter_modes[]; - extern const MeterClass BlankMeter_class; #endif From 433e473eae544cd6ebe2e10b0309db9e26b774b6 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 22:07:39 +0800 Subject: [PATCH 08/12] New header "MeterMode.h" for MeterModeId definitions This is a prerequisite to using MeterModeId type in more headers, to avoid header dependency hell. --- Makefile.am | 1 + Meter.h | 10 +--------- MeterMode.h | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 MeterMode.h diff --git a/Makefile.am b/Makefile.am index ca2f90ba8..2580252b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -134,6 +134,7 @@ myhtopheaders = \ MemoryMeter.h \ MemorySwapMeter.h \ Meter.h \ + MeterMode.h \ MetersPanel.h \ NetworkIOMeter.h \ Object.h \ diff --git a/Meter.h b/Meter.h index 1a16d19ae..ff402ae34 100644 --- a/Meter.h +++ b/Meter.h @@ -14,6 +14,7 @@ in the source distribution for its full text. #include "ListItem.h" #include "Machine.h" +#include "MeterMode.h" #include "Object.h" @@ -117,15 +118,6 @@ struct Meter_ { void* meterData; }; -typedef enum { - /* Meter mode 0 is reserved */ - BAR_METERMODE = 1, - TEXT_METERMODE, - GRAPH_METERMODE, - LED_METERMODE, - LAST_METERMODE -} MeterModeId; - typedef enum { RATESTATUS_DATA, RATESTATUS_INIT, diff --git a/MeterMode.h b/MeterMode.h new file mode 100644 index 000000000..98e6921ea --- /dev/null +++ b/MeterMode.h @@ -0,0 +1,20 @@ +#ifndef HEADER_MeterMode +#define HEADER_MeterMode +/* +htop - MeterMode.h +(C) 2024 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + + +typedef enum { + /* Meter mode 0 is reserved */ + BAR_METERMODE = 1, + TEXT_METERMODE, + GRAPH_METERMODE, + LED_METERMODE, + LAST_METERMODE +} MeterModeId; + +#endif From 7c776d655c05019ea1235e89359a0b7c5b9d5104 Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 22:18:40 +0800 Subject: [PATCH 09/12] Define MeterModeId to unsigned int and use it throughout All uses of meter drawing "mode" numbers now have the type `MeterModeId`, including the uses in structures and arrays. `MeterModeId` is defined as `unsigned int`, as (currently) it doesn't save any code size by defining it to any smaller type. Signed-off-by: Kang-Che Sung --- CPUMeter.c | 10 +++++----- Header.c | 2 +- MemorySwapMeter.c | 2 +- Meter.c | 2 +- Meter.h | 8 ++++---- MeterMode.h | 6 ++++-- MetersPanel.c | 2 +- Settings.c | 10 +++++----- Settings.h | 3 ++- 9 files changed, 24 insertions(+), 21 deletions(-) diff --git a/CPUMeter.c b/CPUMeter.c index 58f4455de..1077f4e1b 100644 --- a/CPUMeter.c +++ b/CPUMeter.c @@ -253,7 +253,7 @@ static void CPUMeterCommonInit(Meter* this) { } } -static void CPUMeterCommonUpdateMode(Meter* this, int mode, int ncol) { +static void CPUMeterCommonUpdateMode(Meter* this, MeterModeId mode, int ncol) { CPUMeterData* data = this->meterData; Meter** meters = data->meters; this->mode = mode; @@ -278,19 +278,19 @@ static void AllCPUsMeter_done(Meter* this) { free(data); } -static void SingleColCPUsMeter_updateMode(Meter* this, int mode) { +static void SingleColCPUsMeter_updateMode(Meter* this, MeterModeId mode) { CPUMeterCommonUpdateMode(this, mode, 1); } -static void DualColCPUsMeter_updateMode(Meter* this, int mode) { +static void DualColCPUsMeter_updateMode(Meter* this, MeterModeId mode) { CPUMeterCommonUpdateMode(this, mode, 2); } -static void QuadColCPUsMeter_updateMode(Meter* this, int mode) { +static void QuadColCPUsMeter_updateMode(Meter* this, MeterModeId mode) { CPUMeterCommonUpdateMode(this, mode, 4); } -static void OctoColCPUsMeter_updateMode(Meter* this, int mode) { +static void OctoColCPUsMeter_updateMode(Meter* this, MeterModeId mode) { CPUMeterCommonUpdateMode(this, mode, 8); } diff --git a/Header.c b/Header.c index fa0279da1..42f6d204b 100644 --- a/Header.c +++ b/Header.c @@ -150,7 +150,7 @@ void Header_writeBackToSettings(const Header* this) { int len = Vector_size(vec); colSettings->names = len ? xCalloc(len + 1, sizeof(char*)) : NULL; - colSettings->modes = len ? xCalloc(len, sizeof(int)) : NULL; + colSettings->modes = len ? xCalloc(len, sizeof(MeterModeId)) : NULL; colSettings->len = len; for (int i = 0; i < len; i++) { diff --git a/MemorySwapMeter.c b/MemorySwapMeter.c index 2e49817d4..ae5829004 100644 --- a/MemorySwapMeter.c +++ b/MemorySwapMeter.c @@ -68,7 +68,7 @@ static void MemorySwapMeter_init(Meter* this) { } } -static void MemorySwapMeter_updateMode(Meter* this, int mode) { +static void MemorySwapMeter_updateMode(Meter* this, MeterModeId mode) { MemorySwapMeterData* data = this->meterData; this->mode = mode; diff --git a/Meter.c b/Meter.c index 25f559a17..20c0287cd 100644 --- a/Meter.c +++ b/Meter.c @@ -438,7 +438,7 @@ void Meter_setCaption(Meter* this, const char* caption) { free_and_xStrdup(&this->caption, caption); } -void Meter_setMode(Meter* this, int modeIndex) { +void Meter_setMode(Meter* this, MeterModeId modeIndex) { if (modeIndex > 0 && modeIndex == this->mode) { return; } diff --git a/Meter.h b/Meter.h index ff402ae34..0d93759f6 100644 --- a/Meter.h +++ b/Meter.h @@ -49,7 +49,7 @@ typedef struct Meter_ Meter; typedef void(*Meter_Init)(Meter*); typedef void(*Meter_Done)(Meter*); -typedef void(*Meter_UpdateMode)(Meter*, int); +typedef void(*Meter_UpdateMode)(Meter*, MeterModeId); typedef void(*Meter_UpdateValues)(Meter*); typedef void(*Meter_Draw)(Meter*, int, int, int); typedef const char* (*Meter_GetCaption)(const Meter*); @@ -64,7 +64,7 @@ typedef struct MeterClass_ { const Meter_Draw draw; const Meter_GetCaption getCaption; const Meter_GetUiName getUiName; - const int defaultMode; + const MeterModeId defaultMode; const double total; const int* const attributes; const char* const name; /* internal name of the meter, must not contain any space */ @@ -105,7 +105,7 @@ struct Meter_ { const Machine* host; char* caption; - int mode; + MeterModeId mode; unsigned int param; GraphData drawData; int h; @@ -137,7 +137,7 @@ void Meter_delete(Object* cast); void Meter_setCaption(Meter* this, const char* caption); -void Meter_setMode(Meter* this, int modeIndex); +void Meter_setMode(Meter* this, MeterModeId modeIndex); ListItem* Meter_toListItem(const Meter* this, bool moving); diff --git a/MeterMode.h b/MeterMode.h index 98e6921ea..fc5b7785a 100644 --- a/MeterMode.h +++ b/MeterMode.h @@ -8,13 +8,15 @@ in the source distribution for its full text. */ -typedef enum { +enum MeterModeId_ { /* Meter mode 0 is reserved */ BAR_METERMODE = 1, TEXT_METERMODE, GRAPH_METERMODE, LED_METERMODE, LAST_METERMODE -} MeterModeId; +}; + +typedef unsigned int MeterModeId; #endif diff --git a/MetersPanel.c b/MetersPanel.c index 2678fb2fc..2b8049ca2 100644 --- a/MetersPanel.c +++ b/MetersPanel.c @@ -108,7 +108,7 @@ static HandlerResult MetersPanel_eventHandler(Panel* super, int ch) { if (!Vector_size(this->meters)) break; Meter* meter = (Meter*) Vector_get(this->meters, selected); - int mode = meter->mode + 1; + MeterModeId mode = meter->mode + 1; if (mode == LAST_METERMODE) mode = 1; Meter_setMode(meter, mode); diff --git a/Settings.c b/Settings.c index a689b42b7..9b457d86a 100644 --- a/Settings.c +++ b/Settings.c @@ -108,9 +108,9 @@ static void Settings_readMeterModes(Settings* this, const char* line, unsigned i } column = MINIMUM(column, HeaderLayout_getColumns(this->hLayout) - 1); this->hColumns[column].len = len; - int* modes = len ? xCalloc(len, sizeof(int)) : NULL; + MeterModeId* modes = len ? xCalloc(len, sizeof(MeterModeId)) : NULL; for (int i = 0; i < len; i++) { - modes[i] = atoi(ids[i]); + modes[i] = (MeterModeId) atoi(ids[i]); } String_freeArray(ids); this->hColumns[column].modes = modes; @@ -123,7 +123,7 @@ static bool Settings_validateMeters(Settings* this) { for (size_t column = 0; column < colCount; column++) { char** names = this->hColumns[column].names; - const int* modes = this->hColumns[column].modes; + const MeterModeId* modes = this->hColumns[column].modes; const size_t len = this->hColumns[column].len; if (!len) @@ -164,7 +164,7 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount) this->hColumns = xCalloc(HeaderLayout_getColumns(this->hLayout), sizeof(MeterColumnSetting)); for (size_t i = 0; i < 2; i++) { this->hColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char*)); - this->hColumns[i].modes = xCalloc(sizes[i], sizeof(int)); + this->hColumns[i].modes = xCalloc(sizes[i], sizeof(MeterModeId)); this->hColumns[i].len = sizes[i]; } @@ -646,7 +646,7 @@ static void writeMeterModes(const Settings* this, OutputFunc of, if (this->hColumns[column].len) { const char* sep = ""; for (size_t i = 0; i < this->hColumns[column].len; i++) { - of(fp, "%s%d", sep, this->hColumns[column].modes[i]); + of(fp, "%s%u", sep, this->hColumns[column].modes[i]); sep = " "; } } else { diff --git a/Settings.h b/Settings.h index b5bc8efd1..9d9e0dba7 100644 --- a/Settings.h +++ b/Settings.h @@ -13,6 +13,7 @@ in the source distribution for its full text. #include "Hashtable.h" #include "HeaderLayout.h" +#include "MeterMode.h" #include "Row.h" #include "RowField.h" @@ -34,7 +35,7 @@ typedef struct { typedef struct { size_t len; char** names; - int* modes; + MeterModeId* modes; } MeterColumnSetting; typedef struct ScreenSettings_ { From 2b73972ffa27b9a7e10bb8be45501e69a0166c3b Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Tue, 16 Apr 2024 06:03:27 +0800 Subject: [PATCH 10/12] MemorySwapMeter_init() code shrink --- MemorySwapMeter.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MemorySwapMeter.c b/MemorySwapMeter.c index ae5829004..e1e5b1042 100644 --- a/MemorySwapMeter.c +++ b/MemorySwapMeter.c @@ -50,9 +50,7 @@ static void MemorySwapMeter_init(Meter* this) { MemorySwapMeterData* data = this->meterData; if (!data) { - data = this->meterData = xMalloc(sizeof(MemorySwapMeterData)); - data->memoryMeter = NULL; - data->swapMeter = NULL; + data = this->meterData = xCalloc(1, sizeof(MemorySwapMeterData)); } if (!data->memoryMeter) From b62683b378289a56fd30510142bfc52d8f4b3f1c Mon Sep 17 00:00:00 2001 From: Explorer09 Date: Thu, 18 Apr 2024 22:44:44 +0800 Subject: [PATCH 11/12] Adjust some code style for maintainability --- Meter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Meter.c b/Meter.c index 20c0287cd..3dbdfcc66 100644 --- a/Meter.c +++ b/Meter.c @@ -443,7 +443,7 @@ void Meter_setMode(Meter* this, MeterModeId modeIndex) { return; } - if (!modeIndex) { + if (modeIndex == 0) { modeIndex = 1; } @@ -467,7 +467,7 @@ void Meter_setMode(Meter* this, MeterModeId modeIndex) { ListItem* Meter_toListItem(const Meter* this, bool moving) { char mode[20]; - if (this->mode) { + if (this->mode > 0) { xSnprintf(mode, sizeof(mode), " [%s]", Meter_modes[this->mode].uiName); } else { mode[0] = '\0'; From a2ab9ad00a633490bb125d103ad061aaab6de419 Mon Sep 17 00:00:00 2001 From: Benny Baumann Date: Sat, 20 Apr 2024 19:03:35 +0200 Subject: [PATCH 12/12] Use struct member to determine size of allocations --- Header.c | 4 ++-- Settings.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Header.c b/Header.c index 42f6d204b..8a9eae34d 100644 --- a/Header.c +++ b/Header.c @@ -149,8 +149,8 @@ void Header_writeBackToSettings(const Header* this) { const Vector* vec = this->columns[col]; int len = Vector_size(vec); - colSettings->names = len ? xCalloc(len + 1, sizeof(char*)) : NULL; - colSettings->modes = len ? xCalloc(len, sizeof(MeterModeId)) : NULL; + colSettings->names = len ? xCalloc(len + 1, sizeof(*colSettings->names)) : NULL; + colSettings->modes = len ? xCalloc(len, sizeof(*colSettings->modes)) : NULL; colSettings->len = len; for (int i = 0; i < len; i++) { diff --git a/Settings.c b/Settings.c index 9b457d86a..07b7e6a28 100644 --- a/Settings.c +++ b/Settings.c @@ -163,8 +163,8 @@ static void Settings_defaultMeters(Settings* this, unsigned int initialCpuCount) this->hLayout = HF_TWO_50_50; this->hColumns = xCalloc(HeaderLayout_getColumns(this->hLayout), sizeof(MeterColumnSetting)); for (size_t i = 0; i < 2; i++) { - this->hColumns[i].names = xCalloc(sizes[i] + 1, sizeof(char*)); - this->hColumns[i].modes = xCalloc(sizes[i], sizeof(MeterModeId)); + this->hColumns[i].names = xCalloc(sizes[i] + 1, sizeof(*this->hColumns[0].names)); + this->hColumns[i].modes = xCalloc(sizes[i], sizeof(*this->hColumns[0].modes)); this->hColumns[i].len = sizes[i]; }