From fa8ab9da27e1370f050ce1514a9a151e23a8604e Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Wed, 18 Mar 2026 22:19:43 -0500 Subject: [PATCH] Task Manager display fixed. ListView can now auto-size columns to fit content. --- apps/progman/progman.c | 3 ++- dvx/dvxApp.c | 4 +-- dvx/widgets/widgetCore.c | 2 ++ dvx/widgets/widgetEvent.c | 16 +++++++++++- dvx/widgets/widgetInternal.h | 1 + dvx/widgets/widgetListView.c | 47 ++++++++++++++++++++++++++++++++---- dvxshell/shellApp.c | 1 + dvxshell/shellApp.h | 3 +++ dvxshell/shellMain.c | 9 +++---- 9 files changed, 72 insertions(+), 14 deletions(-) diff --git a/apps/progman/progman.c b/apps/progman/progman.c index f139a53..14969da 100644 --- a/apps/progman/progman.c +++ b/apps/progman/progman.c @@ -254,7 +254,8 @@ static void buildTaskManager(void) { WidgetT *root = wgtInitWindow(sAc, sTmWindow); // ListView with Name (descriptor), File (basename), Type, Status columns. - ListViewColT tmCols[TM_COL_COUNT]; + // Static: wgtListViewSetColumns stores a pointer, not a copy. + static ListViewColT tmCols[TM_COL_COUNT]; tmCols[0].title = "Name"; tmCols[0].width = wgtPercent(35); tmCols[0].align = ListViewAlignLeftE; diff --git a/dvx/dvxApp.c b/dvx/dvxApp.c index 6ac8c77..0bc1fb2 100644 --- a/dvx/dvxApp.c +++ b/dvx/dvxApp.c @@ -2718,7 +2718,7 @@ static void pollAnsiTermWidgetsWalk(AppContextT *ctx, WidgetT *w, WindowT *win) static void pollKeyboard(AppContextT *ctx) { int32_t shiftFlags = platformKeyboardGetModifiers(); ctx->keyModifiers = shiftFlags; - bool shiftHeld = (shiftFlags & 0x03) != 0; // left or right shift + bool shiftHeld = (shiftFlags & KEY_MOD_SHIFT) != 0; PlatformKeyEventT evt; @@ -2937,7 +2937,7 @@ static void pollKeyboard(AppContextT *ctx) { // Alt+Space — open/close system menu // Enhanced INT 16h: Alt+Space returns scancode 0x39, ascii 0x20 // Must check Alt modifier (bit 3) to distinguish from plain Space - if (scancode == 0x39 && ascii == 0x20 && (shiftFlags & 0x08)) { + if (scancode == 0x39 && ascii == 0x20 && (shiftFlags & KEY_MOD_ALT)) { if (ctx->sysMenu.active) { closeSysMenu(ctx); } else if (ctx->stack.focusedIdx >= 0) { diff --git a/dvx/widgets/widgetCore.c b/dvx/widgets/widgetCore.c index 6d0d552..053c781 100644 --- a/dvx/widgets/widgetCore.c +++ b/dvx/widgets/widgetCore.c @@ -49,6 +49,7 @@ WidgetT *sResizeListView = NULL; // ListView undergoing column resize int32_t sResizeCol = -1; // which column is being resized int32_t sResizeStartX = 0; // mouse X at resize start int32_t sResizeOrigW = 0; // column width at resize start +bool sResizeDragging = false; // true once mouse moves during column resize WidgetT *sDragSplitter = NULL; // splitter being dragged int32_t sDragSplitStart = 0; // mouse offset from splitter edge at drag start WidgetT *sDragReorder = NULL; // list/tree widget in drag-reorder mode @@ -202,6 +203,7 @@ void widgetDestroyChildren(WidgetT *w) { if (sResizeListView == child) { sResizeListView = NULL; sResizeCol = -1; + sResizeDragging = false; } if (sDragScrollbar == child) { diff --git a/dvx/widgets/widgetEvent.c b/dvx/widgets/widgetEvent.c index b5e569b..d35f901 100644 --- a/dvx/widgets/widgetEvent.c +++ b/dvx/widgets/widgetEvent.c @@ -313,11 +313,25 @@ void widgetOnMouse(WindowT *win, int32_t x, int32_t y, int32_t buttons) { if (sResizeListView && !(buttons & MOUSE_LEFT)) { sResizeListView = NULL; sResizeCol = -1; + sResizeDragging = false; return; } - // Handle ListView column resize drag + // Handle ListView column resize drag. The drag is deferred: on the + // initial click sResizeDragging is false and no resize happens until + // the mouse actually moves from the click point. This allows double- + // click auto-size to work (the first click sets sResizeListView but + // doesn't start dragging; the release clears it; the second click + // reaches widgetListViewOnMouse where multiClickDetect returns 2). if (sResizeListView && (buttons & MOUSE_LEFT)) { + if (!sResizeDragging) { + if (x == sResizeStartX) { + return; + } + + sResizeDragging = true; + } + int32_t delta = x - sResizeStartX; int32_t newW = sResizeOrigW + delta; diff --git a/dvx/widgets/widgetInternal.h b/dvx/widgets/widgetInternal.h index a0240b3..b4a8e56 100644 --- a/dvx/widgets/widgetInternal.h +++ b/dvx/widgets/widgetInternal.h @@ -188,6 +188,7 @@ extern WidgetT *sResizeListView; // listview whose column is being resized extern int32_t sResizeCol; // which column is being resized extern int32_t sResizeStartX; // mouse X at start of column resize extern int32_t sResizeOrigW; // original column width at start of resize +extern bool sResizeDragging; // true once mouse has moved from click point extern WidgetT *sDragSplitter; // splitter being dragged extern int32_t sDragSplitStart; // mouse position at start of splitter drag extern WidgetT *sDragReorder; // listbox/treeview item being drag-reordered diff --git a/dvx/widgets/widgetListView.c b/dvx/widgets/widgetListView.c index cf79c70..07b5d4f 100644 --- a/dvx/widgets/widgetListView.c +++ b/dvx/widgets/widgetListView.c @@ -893,11 +893,48 @@ void widgetListViewOnMouse(WidgetT *hit, WidgetT *root, int32_t vx, int32_t vy) int32_t border = colX + cw; if (vx >= border - 3 && vx <= border + 3 && c < hit->as.listView->colCount) { - // Start column resize drag - sResizeListView = hit; - sResizeCol = c; - sResizeStartX = vx; - sResizeOrigW = cw; + if (multiClickDetect(vx, vy) >= 2) { + // Double-click on column border: auto-size to fit content + int32_t maxLen = (int32_t)strlen(hit->as.listView->cols[c].title); + + for (int32_t r = 0; r < hit->as.listView->rowCount; r++) { + const char *cell = hit->as.listView->cellData[r * hit->as.listView->colCount + c]; + + if (cell) { + int32_t slen = (int32_t)strlen(cell); + + if (slen > maxLen) { + maxLen = slen; + } + } + } + + int32_t newW = maxLen * font->charWidth + LISTVIEW_COL_PAD; + + if (newW < LISTVIEW_MIN_COL_W) { + newW = LISTVIEW_MIN_COL_W; + } + + hit->as.listView->resolvedColW[c] = newW; + + // Recalculate totalColW + int32_t total = 0; + + for (int32_t tc = 0; tc < hit->as.listView->colCount; tc++) { + total += hit->as.listView->resolvedColW[tc]; + } + + hit->as.listView->totalColW = total; + wgtInvalidatePaint(hit); + } else { + // Start column resize drag (deferred until mouse moves) + sResizeListView = hit; + sResizeCol = c; + sResizeStartX = vx; + sResizeOrigW = cw; + sResizeDragging = false; + } + return; } diff --git a/dvxshell/shellApp.c b/dvxshell/shellApp.c index 780e421..53cb0f3 100644 --- a/dvxshell/shellApp.c +++ b/dvxshell/shellApp.c @@ -415,6 +415,7 @@ int32_t shellLoadApp(AppContextT *ctx, const char *path) { app->state = AppStateRunningE; shellLog("Shell: loaded '%s' (id=%ld, mainLoop=%s, entry=0x%08lx, desc=0x%08lx)", app->name, (long)id, app->hasMainLoop ? "yes" : "no", (unsigned long)entry, (unsigned long)desc); + shellDesktopUpdate(); return id; } diff --git a/dvxshell/shellApp.h b/dvxshell/shellApp.h index 6d07918..37ac185 100644 --- a/dvxshell/shellApp.h +++ b/dvxshell/shellApp.h @@ -178,4 +178,7 @@ void shellExportInit(void); // and is the only consumer. void shellRegisterDesktopUpdate(void (*updateFn)(void)); +// Notify the desktop app that app state has changed (load, reap, crash). +void shellDesktopUpdate(void); + #endif // SHELL_APP_H diff --git a/dvxshell/shellMain.c b/dvxshell/shellMain.c index 7906c16..acffe09 100644 --- a/dvxshell/shellMain.c +++ b/dvxshell/shellMain.c @@ -57,7 +57,6 @@ static void (*sDesktopUpdateFn)(void) = NULL; // ============================================================ static void crashHandler(int sig); -static void desktopUpdate(void); static void idleYield(void *ctx); static void installCrashHandler(void); static void logCrash(int sig); @@ -89,10 +88,10 @@ static void crashHandler(int sig) { // ============================================================ -// desktopUpdate — notify desktop app of state change +// shellDesktopUpdate — notify desktop app of state change // ============================================================ -static void desktopUpdate(void) { +void shellDesktopUpdate(void) { if (sDesktopUpdateFn) { sDesktopUpdateFn(); } @@ -326,7 +325,7 @@ int main(void) { sCurrentAppId = 0; sCrashSignal = 0; - desktopUpdate(); + shellDesktopUpdate(); } // Main loop — runs until dvxQuit() sets sCtx.running = false. @@ -347,7 +346,7 @@ int main(void) { // This is the safe point for cleanup — we're at the top of the // main loop, not inside any callback or compositor operation. if (shellReapApps(&sCtx)) { - desktopUpdate(); + shellDesktopUpdate(); } }