From f2a43a71be333a1bdf048f58eedaa8dbba46509b Mon Sep 17 00:00:00 2001 From: DeltachangeOG Date: Sat, 24 Jan 2026 22:44:57 -0600 Subject: [PATCH 1/4] Framework for warning display above function bar --- FunctionBar.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ FunctionBar.h | 4 ++++ 2 files changed, 55 insertions(+) diff --git a/FunctionBar.c b/FunctionBar.c index 765fc4f78..11f1650ca 100644 --- a/FunctionBar.c +++ b/FunctionBar.c @@ -8,6 +8,7 @@ in the source distribution for its full text. #include "config.h" // IWYU pragma: keep #include "FunctionBar.h" +#include "Platform.h" #include #include @@ -30,6 +31,13 @@ static const int FunctionBar_EnterEscEvents[] = {13, 27}; static int currentLen = 0; +static char warningBuf[256]; +static bool warningActive; +static bool warningNeedsCleared; +static bool warningDismissOnKeypress; +static uint64_t warningExpiresAtMs; +static const uint32_t warningDefaultTimeoutMs = 1500; + FunctionBar* FunctionBar_newEnterEsc(const char* enter, const char* esc) { const char* functions[FUNCTIONBAR_MAXEVENTS + 1] = {enter, esc, NULL}; return FunctionBar_new(functions, FunctionBar_EnterEscKeys, FunctionBar_EnterEscEvents); @@ -80,6 +88,14 @@ void FunctionBar_delete(FunctionBar* this) { free(this); } +void FunctionBar_clearWarning(void) { + warningActive = false; + warningBuf[0] = '\0'; + warningDismissOnKeypress = false; + warningExpiresAtMs = 0; + warningNeedsCleared = true; +} + void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) { for (size_t i = 0; i < this->size; i++) { if (this->events[i] == event) { @@ -90,12 +106,47 @@ void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) { } } +void FunctionBar_setWarning(const char* msg, uint32_t timeoutMs, bool dismissOnKeypress) { + if (msg == NULL || msg[0] == '\0') { + FunctionBar_clearWarning(); + return; + } + snprintf(warningBuf, sizeof(warningBuf), "%s", msg); + warningActive = true; + warningDismissOnKeypress = dismissOnKeypress; + uint64_t now = 0; + Platform_gettime_monotonic(&now); + if (timeoutMs == 0) { + warningExpiresAtMs = now + warningDefaultTimeoutMs; + } + else { + warningExpiresAtMs = now + timeoutMs; + } +} + int FunctionBar_draw(const FunctionBar* this) { return FunctionBar_drawExtra(this, NULL, -1, false); } int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor) { int cursorX = 0; + if (warningActive) { + uint64_t now = 0; + Platform_gettime_monotonic(&now); + if (now >= warningExpiresAtMs) { + FunctionBar_clearWarning(); + } + } + if (warningNeedsCleared && LINES > 1) { + attrset(CRT_colors[RESET_COLOR]); + mvhline(LINES - 2, 0, ' ', COLS); + warningNeedsCleared = false; + } + if (warningActive && LINES > 1) { + attrset(CRT_colors[FAILED_READ]); + mvhline(LINES - 2, 0, ' ', COLS); + mvaddstr(LINES - 2, 0, warningBuf); + } attrset(CRT_colors[FUNCTION_BAR]); mvhline(LINES - 1, 0, ' ', COLS); int x = 0; diff --git a/FunctionBar.h b/FunctionBar.h index cb9c5bc1b..f37fbe087 100644 --- a/FunctionBar.h +++ b/FunctionBar.h @@ -32,6 +32,10 @@ void FunctionBar_delete(FunctionBar* this); void FunctionBar_setLabel(FunctionBar* this, int event, const char* text); +void FunctionBar_setWarning(const char* msg, uint32_t timeoutMs, bool dismissOnKeypress); + +void FunctionBar_clearWarning(void); + int FunctionBar_draw(const FunctionBar* this); int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor); From 90edaa4d24abd72b326976be40c19151f3ce17ea Mon Sep 17 00:00:00 2001 From: DeltachangeOG Date: Sat, 24 Jan 2026 23:05:07 -0600 Subject: [PATCH 2/4] Dismiss error warning on user input --- FunctionBar.c | 6 ++++++ FunctionBar.h | 2 ++ ScreenManager.c | 2 ++ 3 files changed, 10 insertions(+) diff --git a/FunctionBar.c b/FunctionBar.c index 11f1650ca..927c35933 100644 --- a/FunctionBar.c +++ b/FunctionBar.c @@ -96,6 +96,12 @@ void FunctionBar_clearWarning(void) { warningNeedsCleared = true; } +void FunctionBar_inputEvent(void) { + if (warningDismissOnKeypress) { + FunctionBar_clearWarning(); + } +} + void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) { for (size_t i = 0; i < this->size; i++) { if (this->events[i] == event) { diff --git a/FunctionBar.h b/FunctionBar.h index f37fbe087..8f6cc784e 100644 --- a/FunctionBar.h +++ b/FunctionBar.h @@ -36,6 +36,8 @@ void FunctionBar_setWarning(const char* msg, uint32_t timeoutMs, bool dismissOnK void FunctionBar_clearWarning(void); +void FunctionBar_inputEvent(void); + int FunctionBar_draw(const FunctionBar* this); int FunctionBar_drawExtra(const FunctionBar* this, const char* buffer, int attr, bool setCursor); diff --git a/ScreenManager.c b/ScreenManager.c index ed1243fd8..59084c265 100644 --- a/ScreenManager.c +++ b/ScreenManager.c @@ -339,6 +339,8 @@ void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey, con continue; } + FunctionBar_inputEvent(); + switch (ch) { case KEY_ALT('H'): ch = KEY_LEFT; break; case KEY_ALT('J'): ch = KEY_DOWN; break; From 0bc5677661dabcf5cb26f956ead05eeb195b9efc Mon Sep 17 00:00:00 2001 From: DeltachangeOG Date: Sun, 25 Jan 2026 00:37:00 -0600 Subject: [PATCH 3/4] show FunctionBar warning on sendSignal failure --- Action.c | 15 +++++++++++---- Process.c | 17 +++++++++++++---- Process.h | 5 +++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/Action.c b/Action.c index 1d3bccc51..17a9c1e2d 100644 --- a/Action.c +++ b/Action.c @@ -519,18 +519,25 @@ static Htop_Reaction actionKill(State* st) { static int preSelectedSignal = SIGNALSPANEL_INITSELECTEDSIGNAL; + sendSignalContext ctx; + Panel* signalsPanel = SignalsPanel_new(preSelectedSignal); const ListItem* sgn = (ListItem*) Action_pickFromVector(st, signalsPanel, 14, true); if (sgn && sgn->key != 0) { - preSelectedSignal = sgn->key; + ctx.sgn = sgn->key; + ctx.savedErrno = 0; Panel_setHeader((Panel*)st->mainPanel, "Sending..."); Panel_draw((Panel*)st->mainPanel, false, true, true, State_hideFunctionBar(st)); refresh(); - bool ok = MainPanel_foreachRow(st->mainPanel, Process_rowSendSignal, (Arg) { .i = sgn->key }, NULL); - if (!ok) { + bool ok = MainPanel_foreachRow(st->mainPanel, Process_rowSendSignal, (Arg) { .v = &ctx }, NULL); + (void) ok; + if (ctx.savedErrno != 0) { beep(); + FunctionBar_setWarning(strerror(ctx.savedErrno), 0, true); + } + else { + napms(500); } - napms(500); } Panel_delete((Object*)signalsPanel); diff --git a/Process.c b/Process.c index cd1c08688..6b3a590c6 100644 --- a/Process.c +++ b/Process.c @@ -19,6 +19,7 @@ in the source distribution for its full text. #include #include #include +#include #include "CRT.h" #include "Hashtable.h" @@ -901,14 +902,22 @@ bool Process_rowChangePriorityBy(Row* super, Arg delta) { return Process_setPriority(this, (int)this->nice + delta.i); } -static bool Process_sendSignal(Process* this, Arg sgn) { - return kill(Process_getPid(this), sgn.i) == 0; +static bool Process_sendSignal(Process* this, sendSignalContext* ctx) { + if (kill(Process_getPid(this), ctx->sgn ) != 0) { + int e = errno; + if (e != ESRCH) { + ctx->savedErrno = e; + } + return false; + } + return true; } -bool Process_rowSendSignal(Row* super, Arg sgn) { +bool Process_rowSendSignal(Row* super, Arg arg) { Process* this = (Process*) super; assert(Object_isA((const Object*) this, (const ObjectClass*) &Process_class)); - return Process_sendSignal(this, sgn); + sendSignalContext* ctx = (sendSignalContext*) arg.v; + return Process_sendSignal(this, ctx); } int Process_compare(const void* v1, const void* v2) { diff --git a/Process.h b/Process.h index 38e2711f6..5a2fef30f 100644 --- a/Process.h +++ b/Process.h @@ -200,6 +200,11 @@ typedef struct Process_ { ProcessMergedCommand mergedCommand; } Process; +typedef struct sendSignalContext_ { + int sgn; + int savedErrno; +} sendSignalContext; + typedef struct ProcessFieldData_ { /* Name (displayed in setup menu) */ const char* name; From 12fbcd265a4c7e82751ca0fed23b6d5492f8d4cd Mon Sep 17 00:00:00 2001 From: DeltachangeOG Date: Mon, 26 Jan 2026 11:39:07 -0600 Subject: [PATCH 4/4] Normalize timeoutMs to monotonic time uint64_t --- FunctionBar.c | 2 +- FunctionBar.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FunctionBar.c b/FunctionBar.c index 927c35933..aca1dca9c 100644 --- a/FunctionBar.c +++ b/FunctionBar.c @@ -112,7 +112,7 @@ void FunctionBar_setLabel(FunctionBar* this, int event, const char* text) { } } -void FunctionBar_setWarning(const char* msg, uint32_t timeoutMs, bool dismissOnKeypress) { +void FunctionBar_setWarning(const char* msg, uint64_t timeoutMs, bool dismissOnKeypress) { if (msg == NULL || msg[0] == '\0') { FunctionBar_clearWarning(); return; diff --git a/FunctionBar.h b/FunctionBar.h index 8f6cc784e..82edac50e 100644 --- a/FunctionBar.h +++ b/FunctionBar.h @@ -32,7 +32,7 @@ void FunctionBar_delete(FunctionBar* this); void FunctionBar_setLabel(FunctionBar* this, int event, const char* text); -void FunctionBar_setWarning(const char* msg, uint32_t timeoutMs, bool dismissOnKeypress); +void FunctionBar_setWarning(const char* msg, uint64_t timeoutMs, bool dismissOnKeypress); void FunctionBar_clearWarning(void);