From d35bf6cda6a6842b244069e2673acea8778381f7 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 16 Nov 2013 02:01:16 +1000 Subject: [PATCH] Add support to GWIN for a routine that can redraw an entire display (subject to the controls being able to redraw). This also removes a few change of visibility bugs in gwin and simplifies code. --- include/gwin/class_gwin.h | 12 ++++- include/gwin/gwin.h | 16 ++++++ src/gwin/gwin.c | 103 ++++++++++++++++---------------------- src/gwin/gwm.c | 77 ++++++++++++++++------------ 4 files changed, 115 insertions(+), 93 deletions(-) diff --git a/include/gwin/class_gwin.h b/include/gwin/class_gwin.h index 62b1752e..ae5ac756 100644 --- a/include/gwin/class_gwin.h +++ b/include/gwin/class_gwin.h @@ -104,6 +104,16 @@ typedef struct gwinVMT { /* @} */ #endif +// These flags are needed whether or not we are running a window manager. +/** + * @brief Flags for redrawing after a visibility change + * @{ + */ +#define GWIN_WMFLG_PRESERVE 0x0001 // @< Preserve whatever existing contents possible if a window can't redraw +#define GWIN_WMFLG_NOBGCLEAR 0x0002 // @< Don't clear the area if the window is not visible +#define GWIN_WMFLG_NOZORDER 0x0004 // @< Don't redraw higher z-order windows that overlap +/* @} */ + #if GWIN_NEED_WINDOWMANAGER || defined(__DOXYGEN__) #if 1 // When we know that wmq is the first element of the GWindowObject structure #define QItem2GWindow(qi) ((GHandle)qi) @@ -125,7 +135,7 @@ typedef struct gwinVMT { void (*DeInit) (void); // @< The window manager has just been removed as the current window manager bool_t (*Add) (GHandle gh, const GWindowInit *pInit); // @< A window has been added void (*Delete) (GHandle gh); // @< A window has been deleted - void (*Visible) (GHandle gh); // @< A window has changed its visibility state + void (*Redraw) (GHandle gh, int visflags); // @< A window needs to be redraw (or undrawn) void (*Redim) (GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h); // @< A window wants to be moved or resized void (*Raise) (GHandle gh); // @< A window wants to be on top void (*MinMax) (GHandle gh, GWindowMinMax minmax); // @< A window wants to be minimized/maximised diff --git a/include/gwin/gwin.h b/include/gwin/gwin.h index fa5ba613..1a2c2c07 100644 --- a/include/gwin/gwin.h +++ b/include/gwin/gwin.h @@ -378,6 +378,22 @@ extern "C" { void gwinRedraw(GHandle gh); #if GWIN_NEED_WINDOWMANAGER + /** + * @brief Redraw a window + * + * @param[in] g The display to redraw. Passing NULL will redraw all displays. + * @param[in] preserve Should the redraw try to preserve existing screen data for those + * windows that can't redraw themselves? + * + * @note This is normally never required as windows and widgets will redraw as required. + * @note Some windows are incapable of redrawing themselves as they don't save + * their drawing state. + * @note This does not clear the background - just redraws the gwin windows (where possible) + * + * @api + */ + void gwinRedrawDisplay(GDisplay *g, bool_t preserve); + /** * @brief Minimize, Maximize or Restore a window * @pre GWIN_NEED_WINDOWMANAGER must be TRUE diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index bb425e0f..c2eb0260 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -37,15 +37,31 @@ static color_t defaultBgColor = Black; * Helper Routines *-----------------------------------------------*/ -#if !GWIN_NEED_WINDOWMANAGER - static void _gwm_vis(GHandle gh) { - if (gh->vmt->Redraw) { +#if GWIN_NEED_WINDOWMANAGER + #define _gwm_redraw(gh, flags) _GWINwm->vmt->Redraw(gh, flags) + #define _gwm_redim(gh,x,y,w,h) _GWINwm->vmt->Redim(gh,x,y,w,h); +#else + static void _gwm_redraw(GHandle gh, int flags) { + if ((gh->flags & GWIN_FLG_VISIBLE)) { + if (gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif + gh->vmt->Redraw(gh); + } else if (!(flags & GWIN_WMFLG_PRESERVE)) + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + if (gh->vmt->AfterClear) + gh->vmt->AfterClear(gh); + } + } else if (!(flags & GWIN_WMFLG_NOBGCLEAR)) { #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gh->vmt->Redraw(gh); - } else - gwinClear(gh); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, defaultBgColor); + } } static void _gwm_redim(GHandle gh, coord_t x, coord_t y, coord_t width, coord_t height) { gh->x = x; gh->y = y; @@ -60,14 +76,7 @@ static color_t defaultBgColor = Black; if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y; // Redraw the window - if ((gh->flags & GWIN_FLG_VISIBLE)) { - if (gh->vmt->Redraw) { - #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); - #endif - gh->vmt->Redraw(gh); - } - } + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } #endif @@ -108,15 +117,15 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit pgw->font = defaultFont; #endif -#if GWIN_NEED_WINDOWMANAGER - if (!_GWINwm->vmt->Add(pgw, pInit)) { - if ((pgw->flags & GWIN_FLG_DYNAMIC)) - gfxFree(pgw); - return 0; - } -#else - _gwm_redim(pgw, pInit->x, pInit->y, pInit->width, pInit->height); -#endif + #if GWIN_NEED_WINDOWMANAGER + if (!_GWINwm->vmt->Add(pgw, pInit)) { + if ((pgw->flags & GWIN_FLG_DYNAMIC)) + gfxFree(pgw); + return 0; + } + #else + _gwm_redim(pgw, pInit->x, pInit->y, pInit->width, pInit->height); + #endif return (GHandle)pgw; } @@ -163,6 +172,9 @@ GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pI } void gwinDestroy(GHandle gh) { + // Make the window invisible + gwinSetVisible(gh, FALSE); + // Remove from the window manager #if GWIN_NEED_WINDOWMANAGER _GWINwm->vmt->Delete(gh); @@ -188,18 +200,12 @@ void gwinSetVisible(GHandle gh, bool_t visible) { if (visible) { if (!(gh->flags & GWIN_FLG_VISIBLE)) { gh->flags |= GWIN_FLG_VISIBLE; - #if GWIN_NEED_WINDOWMANAGER - _GWINwm->vmt->Visible(gh); - #else - _gwm_vis(gh); - #endif + _gwm_redraw(gh, 0); } } else { if ((gh->flags & GWIN_FLG_VISIBLE)) { gh->flags &= ~GWIN_FLG_VISIBLE; - #if GWIN_NEED_WINDOWMANAGER - _GWINwm->vmt->Visible(gh); - #endif + _gwm_redraw(gh, 0); } } } @@ -212,22 +218,12 @@ void gwinSetEnabled(GHandle gh, bool_t enabled) { if (enabled) { if (!(gh->flags & GWIN_FLG_ENABLED)) { gh->flags |= GWIN_FLG_ENABLED; - if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gh->vmt->Redraw(gh); - } + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } } else { if ((gh->flags & GWIN_FLG_ENABLED)) { gh->flags &= ~GWIN_FLG_ENABLED; - if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gh->vmt->Redraw(gh); - } + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } } } @@ -237,28 +233,15 @@ bool_t gwinGetEnabled(GHandle gh) { } void gwinMove(GHandle gh, coord_t x, coord_t y) { - #if GWIN_NEED_WINDOWMANAGER - _GWINwm->vmt->Redim(gh, x, y, gh->width, gh->height); - #else - _gwm_redim(gh, x, y, gh->width, gh->height); - #endif + _gwm_redim(gh, x, y, gh->width, gh->height); } void gwinResize(GHandle gh, coord_t width, coord_t height) { - #if GWIN_NEED_WINDOWMANAGER - _GWINwm->vmt->Redim(gh, gh->x, gh->y, width, height); - #else - _gwm_redim(gh, gh->x, gh->y, width, height); - #endif + _gwm_redim(gh, gh->x, gh->y, width, height); } void gwinRedraw(GHandle gh) { - #if GWIN_NEED_WINDOWMANAGER - gwinRaise(gh); - #else - if ((gh->flags & GWIN_FLG_VISIBLE)) - _gwm_vis(gh); - #endif + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } #if GDISP_NEED_TEXT diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c index d05a8177..1a25897e 100644 --- a/src/gwin/gwm.c +++ b/src/gwin/gwm.c @@ -27,7 +27,7 @@ static void WM_Init(void); static void WM_DeInit(void); static bool_t WM_Add(GHandle gh, const GWindowInit *pInit); static void WM_Delete(GHandle gh); -static void WM_Visible(GHandle gh); +static void WM_Redraw(GHandle gh, int flags); static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h); static void WM_Raise(GHandle gh); static void WM_MinMax(GHandle gh, GWindowMinMax minmax); @@ -37,7 +37,7 @@ static const gwmVMT GNullWindowManagerVMT = { WM_DeInit, WM_Add, WM_Delete, - WM_Visible, + WM_Redraw, WM_Redim, WM_Raise, WM_MinMax, @@ -86,6 +86,19 @@ GWindowMinMax gwinGetMinMax(GHandle gh) { return GWIN_NORMAL; } +void gwinRedrawDisplay(GDisplay *g, bool_t preserve) { + const gfxQueueASyncItem * qi; + GHandle gh; + + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + gh = QItem2GWindow(qi); + if (!g || gh->display == g) + _GWINwm->vmt->Redraw(gh, + preserve ? (GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR|GWIN_WMFLG_NOZORDER) + : (GWIN_WMFLG_NOBGCLEAR|GWIN_WMFLG_NOZORDER)); + } +} + /*----------------------------------------------- * Window Manager Routines *-----------------------------------------------*/ @@ -116,28 +129,38 @@ static bool_t WM_Add(GHandle gh, const GWindowInit *pInit) { } static void WM_Delete(GHandle gh) { - // Make the window invisible and clear the area underneath - if ((gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags &= ~GWIN_FLG_VISIBLE; - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); - } - // Remove it from the queue gfxQueueASyncRemove(&_GWINList, &gh->wmq); } -static void WM_Visible(GHandle gh) { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif +static void WM_Redraw(GHandle gh, int flags) { if ((gh->flags & GWIN_FLG_VISIBLE)) { - if (gh->vmt->Redraw) + if (gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif gh->vmt->Redraw(gh); - else + } else if (!(flags & GWIN_WMFLG_PRESERVE)) { + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + if (gh->vmt->AfterClear) + gh->vmt->AfterClear(gh); + } + // A real window manager would also redraw the borders here - } else + + // A real window manager would then redraw any higher z-order windows + // if (!(flags & GWIN_WMFLG_NOZORDER)) + // ... + + } else if (!(flags & GWIN_WMFLG_NOBGCLEAR)) { + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + } } static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { @@ -157,22 +180,19 @@ static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { return; // Clear the old area - if ((gh->flags & GWIN_FLG_VISIBLE)) + if ((gh->flags & GWIN_FLG_VISIBLE)) { + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + } // Set the new size gh->x = x; gh->y = y; gh->width = w; gh->height = h; // Redraw the window (if possible) - if ((gh->flags & GWIN_FLG_VISIBLE)) { - if (gh->vmt->Redraw) { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gh->vmt->Redraw(gh); - } - } + WM_Redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } static void WM_MinMax(GHandle gh, GWindowMinMax minmax) { @@ -187,14 +207,7 @@ static void WM_Raise(GHandle gh) { gfxQueueASyncPut(&_GWINList, &gh->wmq); // Redraw the window - if ((gh->flags & GWIN_FLG_VISIBLE)) { - if (gh->vmt->Redraw) { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gh->vmt->Redraw(gh); - } - } + WM_Redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } #endif /* GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER */