Icons now update to reflect window activity.
This commit is contained in:
parent
10b49868cd
commit
e453b4d35a
6 changed files with 61 additions and 4 deletions
53
dvx/dvxApp.c
53
dvx/dvxApp.c
|
|
@ -8,7 +8,8 @@
|
|||
#include <time.h>
|
||||
#include <dpmi.h>
|
||||
|
||||
#define DBLCLICK_THRESHOLD (CLOCKS_PER_SEC / 2)
|
||||
#define DBLCLICK_THRESHOLD (CLOCKS_PER_SEC / 2)
|
||||
#define ICON_REFRESH_INTERVAL 8
|
||||
|
||||
// ============================================================
|
||||
// Prototypes
|
||||
|
|
@ -23,6 +24,7 @@ static void initColorScheme(AppContextT *ctx);
|
|||
static void initMouse(AppContextT *ctx);
|
||||
static void pollKeyboard(AppContextT *ctx);
|
||||
static void pollMouse(AppContextT *ctx);
|
||||
static void refreshMinimizedIcons(AppContextT *ctx);
|
||||
static void updateCursorShape(AppContextT *ctx);
|
||||
|
||||
|
||||
|
|
@ -495,6 +497,13 @@ bool dvxUpdate(AppContextT *ctx) {
|
|||
pollKeyboard(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) {
|
||||
compositeAndFlush(ctx);
|
||||
} 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
|
||||
// ============================================================
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ typedef struct AppContextT {
|
|||
int32_t lastIconClickId; // window ID of last-clicked minimized icon (-1 = none)
|
||||
clock_t lastCloseClickTime;
|
||||
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;
|
||||
|
||||
// Initialize the application (VESA mode, input, etc.)
|
||||
|
|
@ -53,9 +55,7 @@ void dvxRun(AppContextT *ctx);
|
|||
bool dvxUpdate(AppContextT *ctx);
|
||||
|
||||
// Create a window
|
||||
WindowT *dvxCreateWindow(AppContextT *ctx, const char *title,
|
||||
int32_t x, int32_t y, int32_t w, int32_t h,
|
||||
bool resizable);
|
||||
WindowT *dvxCreateWindow(AppContextT *ctx, const char *title, int32_t x, int32_t y, int32_t w, int32_t h, bool resizable);
|
||||
|
||||
// Destroy a window
|
||||
void dvxDestroyWindow(AppContextT *ctx, WindowT *win);
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ typedef struct WindowT {
|
|||
bool minimized;
|
||||
bool maximized;
|
||||
bool resizable;
|
||||
bool contentDirty; // true when contentBuf has changed since last icon refresh
|
||||
int32_t maxW; // maximum width (-1 = screen width)
|
||||
int32_t maxH; // maximum height (-1 = screen height)
|
||||
int32_t preMaxX; // saved position before maximize
|
||||
|
|
|
|||
|
|
@ -1102,6 +1102,7 @@ void wmMaximize(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, WindowT
|
|||
if (win->onPaint) {
|
||||
RectT fullRect = {0, 0, win->contentW, win->contentH};
|
||||
win->onPaint(win, &fullRect);
|
||||
win->contentDirty = true;
|
||||
}
|
||||
|
||||
// Mark new position dirty
|
||||
|
|
@ -1461,6 +1462,7 @@ void wmResizeMove(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, int32_
|
|||
if (win->onPaint) {
|
||||
RectT fullRect = {0, 0, win->contentW, win->contentH};
|
||||
win->onPaint(win, &fullRect);
|
||||
win->contentDirty = true;
|
||||
}
|
||||
|
||||
stack->dragOffX = mouseX;
|
||||
|
|
@ -1502,6 +1504,7 @@ void wmRestore(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, WindowT *
|
|||
if (win->onPaint) {
|
||||
RectT fullRect = {0, 0, win->contentW, win->contentH};
|
||||
win->onPaint(win, &fullRect);
|
||||
win->contentDirty = true;
|
||||
}
|
||||
|
||||
// Mark restored position dirty
|
||||
|
|
|
|||
|
|
@ -566,5 +566,6 @@ void widgetOnScroll(WindowT *win, ScrollbarOrientE orient, int32_t value) {
|
|||
if (win->onPaint) {
|
||||
RectT fullRect = {0, 0, win->contentW, win->contentH};
|
||||
win->onPaint(win, &fullRect);
|
||||
win->contentDirty = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,6 +333,7 @@ void wgtInvalidate(WidgetT *w) {
|
|||
// Repaint
|
||||
RectT fullRect = {0, 0, w->window->contentW, w->window->contentH};
|
||||
widgetOnPaint(w->window, &fullRect);
|
||||
w->window->contentDirty = true;
|
||||
|
||||
// Dirty the window on screen
|
||||
dvxInvalidateWindow(ctx, w->window);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue