Icons now update to reflect window activity.

This commit is contained in:
Scott Duensing 2026-03-09 23:23:31 -05:00
parent 10b49868cd
commit e453b4d35a
6 changed files with 61 additions and 4 deletions

View file

@ -9,6 +9,7 @@
#include <dpmi.h> #include <dpmi.h>
#define DBLCLICK_THRESHOLD (CLOCKS_PER_SEC / 2) #define DBLCLICK_THRESHOLD (CLOCKS_PER_SEC / 2)
#define ICON_REFRESH_INTERVAL 8
// ============================================================ // ============================================================
// Prototypes // Prototypes
@ -23,6 +24,7 @@ static void initColorScheme(AppContextT *ctx);
static void initMouse(AppContextT *ctx); static void initMouse(AppContextT *ctx);
static void pollKeyboard(AppContextT *ctx); static void pollKeyboard(AppContextT *ctx);
static void pollMouse(AppContextT *ctx); static void pollMouse(AppContextT *ctx);
static void refreshMinimizedIcons(AppContextT *ctx);
static void updateCursorShape(AppContextT *ctx); static void updateCursorShape(AppContextT *ctx);
@ -495,6 +497,13 @@ bool dvxUpdate(AppContextT *ctx) {
pollKeyboard(ctx); pollKeyboard(ctx);
dispatchEvents(ctx); dispatchEvents(ctx);
// Periodically refresh one minimized window thumbnail (staggered)
ctx->frameCount++;
if (ctx->frameCount % ICON_REFRESH_INTERVAL == 0) {
refreshMinimizedIcons(ctx);
}
if (ctx->dirty.count > 0) { if (ctx->dirty.count > 0) {
compositeAndFlush(ctx); compositeAndFlush(ctx);
} else { } else {
@ -830,6 +839,48 @@ static void pollMouse(AppContextT *ctx) {
} }
// ============================================================
// refreshMinimizedIcons
// ============================================================
//
// Dirty the next minimized window icon whose content has changed
// since the last refresh. Only considers windows without custom
// iconData. Called every ICON_REFRESH_INTERVAL frames to stagger.
static void refreshMinimizedIcons(AppContextT *ctx) {
WindowStackT *ws = &ctx->stack;
DisplayT *d = &ctx->display;
int32_t count = 0;
int32_t iconIdx = 0;
for (int32_t i = 0; i < ws->count; i++) {
WindowT *win = ws->windows[i];
if (!win->visible || !win->minimized) {
continue;
}
if (!win->iconData && win->contentDirty) {
if (count >= ctx->iconRefreshIdx) {
int32_t ix = ICON_SPACING + iconIdx * (ICON_TOTAL_SIZE + ICON_SPACING);
int32_t iy = d->height - ICON_TOTAL_SIZE - ICON_SPACING;
dirtyListAdd(&ctx->dirty, ix, iy, ICON_TOTAL_SIZE, ICON_TOTAL_SIZE);
win->contentDirty = false;
ctx->iconRefreshIdx = count + 1;
return;
}
count++;
}
iconIdx++;
}
// Wrapped past the end — reset for next cycle
ctx->iconRefreshIdx = 0;
}
// ============================================================ // ============================================================
// updateCursorShape // updateCursorShape
// ============================================================ // ============================================================

View file

@ -37,6 +37,8 @@ typedef struct AppContextT {
int32_t lastIconClickId; // window ID of last-clicked minimized icon (-1 = none) int32_t lastIconClickId; // window ID of last-clicked minimized icon (-1 = none)
clock_t lastCloseClickTime; clock_t lastCloseClickTime;
int32_t lastCloseClickId; // window ID of last-clicked close gadget (-1 = none) int32_t lastCloseClickId; // window ID of last-clicked close gadget (-1 = none)
int32_t iconRefreshIdx; // next minimized icon to refresh (staggered)
int32_t frameCount; // frame counter for periodic tasks
} AppContextT; } AppContextT;
// Initialize the application (VESA mode, input, etc.) // Initialize the application (VESA mode, input, etc.)
@ -53,9 +55,7 @@ void dvxRun(AppContextT *ctx);
bool dvxUpdate(AppContextT *ctx); bool dvxUpdate(AppContextT *ctx);
// Create a window // Create a window
WindowT *dvxCreateWindow(AppContextT *ctx, const char *title, WindowT *dvxCreateWindow(AppContextT *ctx, const char *title, int32_t x, int32_t y, int32_t w, int32_t h, bool resizable);
int32_t x, int32_t y, int32_t w, int32_t h,
bool resizable);
// Destroy a window // Destroy a window
void dvxDestroyWindow(AppContextT *ctx, WindowT *win); void dvxDestroyWindow(AppContextT *ctx, WindowT *win);

View file

@ -227,6 +227,7 @@ typedef struct WindowT {
bool minimized; bool minimized;
bool maximized; bool maximized;
bool resizable; bool resizable;
bool contentDirty; // true when contentBuf has changed since last icon refresh
int32_t maxW; // maximum width (-1 = screen width) int32_t maxW; // maximum width (-1 = screen width)
int32_t maxH; // maximum height (-1 = screen height) int32_t maxH; // maximum height (-1 = screen height)
int32_t preMaxX; // saved position before maximize int32_t preMaxX; // saved position before maximize

View file

@ -1102,6 +1102,7 @@ void wmMaximize(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, WindowT
if (win->onPaint) { if (win->onPaint) {
RectT fullRect = {0, 0, win->contentW, win->contentH}; RectT fullRect = {0, 0, win->contentW, win->contentH};
win->onPaint(win, &fullRect); win->onPaint(win, &fullRect);
win->contentDirty = true;
} }
// Mark new position dirty // Mark new position dirty
@ -1461,6 +1462,7 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
if (win->onPaint) { if (win->onPaint) {
RectT fullRect = {0, 0, win->contentW, win->contentH}; RectT fullRect = {0, 0, win->contentW, win->contentH};
win->onPaint(win, &fullRect); win->onPaint(win, &fullRect);
win->contentDirty = true;
} }
stack->dragOffX = mouseX; stack->dragOffX = mouseX;
@ -1502,6 +1504,7 @@ void wmRestore(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, WindowT *
if (win->onPaint) { if (win->onPaint) {
RectT fullRect = {0, 0, win->contentW, win->contentH}; RectT fullRect = {0, 0, win->contentW, win->contentH};
win->onPaint(win, &fullRect); win->onPaint(win, &fullRect);
win->contentDirty = true;
} }
// Mark restored position dirty // Mark restored position dirty

View file

@ -566,5 +566,6 @@ void widgetOnScroll(WindowT *win, ScrollbarOrientE orient, int32_t value) {
if (win->onPaint) { if (win->onPaint) {
RectT fullRect = {0, 0, win->contentW, win->contentH}; RectT fullRect = {0, 0, win->contentW, win->contentH};
win->onPaint(win, &fullRect); win->onPaint(win, &fullRect);
win->contentDirty = true;
} }
} }

View file

@ -333,6 +333,7 @@ void wgtInvalidate(WidgetT *w) {
// Repaint // Repaint
RectT fullRect = {0, 0, w->window->contentW, w->window->contentH}; RectT fullRect = {0, 0, w->window->contentW, w->window->contentH};
widgetOnPaint(w->window, &fullRect); widgetOnPaint(w->window, &fullRect);
w->window->contentDirty = true;
// Dirty the window on screen // Dirty the window on screen
dvxInvalidateWindow(ctx, w->window); dvxInvalidateWindow(ctx, w->window);