GWIN: Make sure invisible windows are redrawn before visible windows.

Redrawing compile options made visible for the user project.
This commit is contained in:
inmarket 2014-05-22 09:35:36 +10:00
parent 1edc0a2d5a
commit bc3ebd6ae9
6 changed files with 123 additions and 78 deletions

View File

@ -4,6 +4,7 @@
*** Changes After 2.1 ***
FEATURE: Added nested containers demo
FEATURE: Revised GWIN redraw strategy
*** Release 2.1 ***

View File

@ -134,6 +134,8 @@
//#define GFX_USE_GWIN FALSE
//#define GWIN_NEED_WINDOWMANAGER FALSE
// #define GWIN_REDRAW_IMMEDIATE FALSE
// #define GWIN_REDRAW_SINGLEOP FALSE
//#define GWIN_NEED_CONSOLE FALSE
// #define GWIN_CONSOLE_USE_HISTORY FALSE

View File

@ -194,6 +194,14 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit
*/
void _gwinUpdate(GHandle gh);
/**
* @brief How to flush the redraws
* @notes REDRAW_WAIT - Wait for a drawing session to be available
* @notes REDRAW_NOWAIT - Do nothing if the drawing session is not available
* @note REDRAW_INSESSION - We are already in a drawing session
*/
typedef enum GRedrawMethod { REDRAW_WAIT, REDRAW_NOWAIT, REDRAW_INSESSION } GRedrawMethod;
/**
* @brief Flush any pending redraws in the system.
*
@ -209,7 +217,7 @@ void _gwinUpdate(GHandle gh);
*
* @notapi
*/
void _gwinFlushRedraws(bool_t doWait);
void _gwinFlushRedraws(GRedrawMethod how);
/**
* @brief Obtain a drawing session

View File

@ -36,8 +36,8 @@
return TRUE;
}
void _gwinFlushRedraws(bool_t doWait) {
(void) doWait;
void _gwinFlushRedraws(GRedrawMethod how) {
(void) how;
// We are always flushed
}
@ -147,9 +147,6 @@
#if GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER
// Do we redraw all windows at once?
#define GWIN_LONG_REDRAW TRUE
#include "src/gwin/class_gwin.h"
/*-----------------------------------------------
@ -158,15 +155,18 @@
// The default window manager
extern const GWindowManager GNullWindowManager;
GWindowManager * _GWINwm;
GWindowManager * _GWINwm;
static gfxSem gwinsem;
static gfxQueueASync _GWINList;
static volatile bool_t RedrawPending;
#if GFX_USE_GTIMER
static GTimer RedrawTimer;
static void RedrawTimerFn(void *param);
static gfxSem gwinsem;
static gfxQueueASync _GWINList;
#if !GWIN_REDRAW_IMMEDIATE
static GTimer RedrawTimer;
static void RedrawTimerFn(void *param);
#endif
static volatile uint8_t RedrawPending;
#define DOREDRAW_INVISIBLES 0x01
#define DOREDRAW_VISIBLES 0x02
/*-----------------------------------------------
* Window Routines
@ -176,7 +176,7 @@ void _gwmInit(void)
{
gfxSemInit(&gwinsem, 1, 1);
gfxQueueASyncInit(&_GWINList);
#if GFX_USE_GTIMER
#if !GWIN_REDRAW_IMMEDIATE
gtimerInit(&RedrawTimer);
gtimerStart(&RedrawTimer, RedrawTimerFn, 0, TRUE, TIME_INFINITE);
#endif
@ -192,25 +192,25 @@ void _gwmDeinit(void)
gwinDestroy(gh);
_GWINwm->vmt->DeInit();
#if GFX_USE_GTIMER
#if !GWIN_REDRAW_IMMEDIATE
gtimerDeinit(&RedrawTimer);
#endif
gfxQueueASyncDeinit(&_GWINList);
gfxSemDestroy(&gwinsem);
}
#if GFX_USE_GTIMER
#if GWIN_REDRAW_IMMEDIATE
#define TriggerRedraw(void) _gwinFlushRedraws(REDRAW_NOWAIT);
#else
#define TriggerRedraw() gtimerJab(&RedrawTimer);
static void RedrawTimerFn(void *param) {
(void) param;
_gwinFlushRedraws(FALSE);
_gwinFlushRedraws(REDRAW_NOWAIT);
}
#else
#define TriggerRedraw(void) _gwinFlushRedraws(FALSE);
#endif
void _gwinFlushRedraws(bool_t doWait) {
void _gwinFlushRedraws(GRedrawMethod how) {
GHandle gh;
// Do we really need to do anything?
@ -218,19 +218,46 @@ void _gwinFlushRedraws(bool_t doWait) {
return;
// Obtain the drawing lock
if (doWait)
if (how == REDRAW_WAIT)
gfxSemWait(&gwinsem, TIME_INFINITE);
else if (!gfxSemWait(&gwinsem, TIME_IMMEDIATE))
else if (how == REDRAW_NOWAIT && !gfxSemWait(&gwinsem, TIME_IMMEDIATE))
// Someone is drawing - They will do the redraw when they are finished
return;
// Look for something to redraw
while(RedrawPending) {
// Catch any new redraw requests from here on
RedrawPending = FALSE;
// Do loss of visibility first
while ((RedrawPending & DOREDRAW_INVISIBLES)) {
RedrawPending &= ~DOREDRAW_INVISIBLES; // Catch new requests
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
if (!(gh->flags & GWIN_FLG_NEEDREDRAW))
if ((gh->flags & (GWIN_FLG_NEEDREDRAW|GWIN_FLG_SYSVISIBLE)) != GWIN_FLG_NEEDREDRAW)
continue;
// Do the redraw
#if GDISP_NEED_CLIP
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
_GWINwm->vmt->Redraw(gh);
gdispGUnsetClip(gh->display);
#else
_GWINwm->vmt->Redraw(gh);
#endif
// Postpone further redraws
#if !GWIN_REDRAW_IMMEDIATE && !GWIN_REDRAW_SINGLEOP
if (how == REDRAW_NOWAIT) {
RedrawPending |= DOREDRAW_INVISIBLES;
TriggerRedraw();
goto releaselock;
}
#endif
}
}
// Do the visible windows next
while ((RedrawPending & DOREDRAW_VISIBLES)) {
RedrawPending &= ~DOREDRAW_VISIBLES; // Catch new requests
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
if ((gh->flags & (GWIN_FLG_NEEDREDRAW|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_NEEDREDRAW|GWIN_FLG_SYSVISIBLE))
continue;
// Do the redraw
@ -243,23 +270,28 @@ void _gwinFlushRedraws(bool_t doWait) {
#endif
// Postpone further redraws (if there are any and the options are set right)
#if GFX_USE_GTIMER && !GWIN_LONG_REDRAW
if (!doWait) {
#if !GWIN_REDRAW_IMMEDIATE && !GWIN_REDRAW_SINGLEOP
if (how == REDRAW_NOWAIT) {
while((gh = gwinGetNextWindow(gh))) {
if ((gh->flags & GWIN_FLG_NEEDREDRAW)) {
gtimerJab(&RedrawTimer);
RedrawPending = TRUE;
if ((gh->flags & (GWIN_FLG_NEEDREDRAW|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_NEEDREDRAW|GWIN_FLG_SYSVISIBLE)) {
RedrawPending |= DOREDRAW_VISIBLES;
TriggerRedraw();
break;
}
}
break;
goto releaselock;
}
#endif
}
}
#if !GWIN_REDRAW_IMMEDIATE && !GWIN_REDRAW_SINGLEOP
releaselock:
#endif
// Release the lock
gfxSemSignal(&gwinsem);
if (how == REDRAW_WAIT || how == REDRAW_NOWAIT)
gfxSemSignal(&gwinsem);
}
void _gwinUpdate(GHandle gh) {
@ -269,7 +301,7 @@ void _gwinUpdate(GHandle gh) {
// Mark for redraw
gh->flags |= GWIN_FLG_NEEDREDRAW;
RedrawPending = TRUE;
RedrawPending |= DOREDRAW_VISIBLES;
// Asynchronous redraw
TriggerRedraw();
@ -304,22 +336,7 @@ void _gwinDrawEnd(GHandle gh) {
#endif
// Look for something to redraw
while(RedrawPending) {
RedrawPending = FALSE;
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
if (!(gh->flags & GWIN_FLG_NEEDREDRAW))
continue;
// Do the redraw
#if GDISP_NEED_CLIP
gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height);
_GWINwm->vmt->Redraw(gh);
gdispGUnsetClip(gh->display);
#else
_GWINwm->vmt->Redraw(gh);
#endif
}
}
_gwinFlushRedraws(REDRAW_INSESSION);
// Release the lock
gfxSemSignal(&gwinsem);
@ -365,10 +382,10 @@ void gwinRedraw(GHandle gh) {
// Mark for redraw
gh->flags |= GWIN_FLG_NEEDREDRAW;
RedrawPending = TRUE;
RedrawPending |= DOREDRAW_VISIBLES;
// Synchronous redraw
_gwinFlushRedraws(TRUE);
_gwinFlushRedraws(REDRAW_WAIT);
}
#if GWIN_NEED_CONTAINERS
@ -386,7 +403,7 @@ void gwinRedraw(GHandle gh) {
}
// Mark for redraw
RedrawPending = TRUE;
RedrawPending |= DOREDRAW_VISIBLES;
TriggerRedraw();
}
} else {
@ -404,7 +421,7 @@ void gwinRedraw(GHandle gh) {
}
// Mark for redraw - no need to redraw children
RedrawPending = TRUE;
RedrawPending |= DOREDRAW_INVISIBLES;
TriggerRedraw();
}
}
@ -414,14 +431,14 @@ void gwinRedraw(GHandle gh) {
if (visible) {
if (!(gh->flags & GWIN_FLG_VISIBLE)) {
gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE|GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
RedrawPending = TRUE;
RedrawPending |= DOREDRAW_VISIBLES;
TriggerRedraw();
}
} else {
if ((gh->flags & GWIN_FLG_VISIBLE)) {
gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE);
gh->flags |= (GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
RedrawPending = TRUE;
RedrawPending |= DOREDRAW_INVISIBLES;
TriggerRedraw();
}
}
@ -441,14 +458,9 @@ void gwinRedraw(GHandle gh) {
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
if ((gh->flags & (GWIN_FLG_SYSENABLED|GWIN_FLG_ENABLED)) == GWIN_FLG_ENABLED && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) {
gh->flags |= GWIN_FLG_SYSENABLED; // Fix it
if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { // Mark for redraw
gh->flags |= GWIN_FLG_NEEDREDRAW;
RedrawPending = TRUE;
}
_gwinUpdate(gh);
}
}
if (RedrawPending)
TriggerRedraw();
}
} else {
gh->flags &= ~GWIN_FLG_ENABLED;
@ -459,14 +471,9 @@ void gwinRedraw(GHandle gh) {
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
if ((gh->flags & GWIN_FLG_SYSENABLED) && (!(gh->flags & GWIN_FLG_ENABLED) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSENABLED)))) {
gh->flags &= ~GWIN_FLG_SYSENABLED; // Fix it
if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { // Mark for redraw
gh->flags |= GWIN_FLG_NEEDREDRAW;
RedrawPending = TRUE;
}
_gwinUpdate(gh);
}
}
if (RedrawPending)
TriggerRedraw();
}
}
}
@ -701,7 +708,7 @@ static void WM_Size(GHandle gh, coord_t w, coord_t h) {
} else {
// We need to make this window invisible and ensure that has been drawn
gwinSetVisible(gh, FALSE);
_gwinFlushRedraws(TRUE);
_gwinFlushRedraws(REDRAW_WAIT);
// Resize
gh->width = w; gh->height = h;
@ -771,7 +778,7 @@ static void WM_Move(GHandle gh, coord_t x, coord_t y) {
if ((gh->flags & GWIN_FLG_SYSVISIBLE)) {
// We need to make this window invisible and ensure that has been drawn
gwinSetVisible(gh, FALSE);
_gwinFlushRedraws(TRUE);
_gwinFlushRedraws(REDRAW_WAIT);
// Do the move
v = gh->x; gh->x = x; x = v;

View File

@ -136,6 +136,33 @@
#ifndef GWIN_FLAT_STYLING
#define GWIN_FLAT_STYLING FALSE
#endif
/**
* @brief Don't use a timer for redrawing windows
* @details Defaults to FALSE
* @note Normally windows and widgets are redrawn on a timer. Setting this
* option causes them to be redrawn immediately. Note that this can
* cause extended blocking times on events and saves little code.
* @note If GWIN_NEED_WINDOWMANAGER is FALSE then this setting is ignored
* as redrawing always occurs immediately.
*/
#ifndef GWIN_REDRAW_IMMEDIATE
#define GWIN_REDRAW_IMMEDIATE FALSE
#endif
/**
* @brief Redraw all windows in a single operation
* @details Defaults to FALSE
* @note Windows are normally redraw one per gtimer cycle.
* Setting this option causes all windows to be redrawn in
* a single gtimer cycle. Note that this can
* cause extended blocking times on the timer thread but may
* speed up redraw slightly.
* @note This is only relevant if GWIN_REDRAW_IMMEDIATE is FALSE.
* Everything always gets redrawn in a single operation if
* GWIN_REDRAW_IMMEDIATE is TRUE.
*/
#ifndef GWIN_REDRAW_SINGLEOP
#define GWIN_REDRAW_SINGLEOP FALSE
#endif
/**
* @brief Buttons should not insist the mouse is over the button on mouse release
* @details Defaults to FALSE

View File

@ -91,6 +91,13 @@
#define GFX_USE_GQUEUE TRUE
#define GQUEUE_NEED_ASYNC TRUE
#endif
#if !GFX_USE_GTIMER
#if GFX_DISPLAY_RULE_WARNINGS
#warning "GWIN: GFX_USE_GTIMER is required if GWIN_NEED_WINDOWMANAGER is TRUE. It has been turned on for you."
#endif
#undef GFX_USE_GTIMER
#define GFX_USE_GTIMER TRUE
#endif
#endif
// Rules for individual objects
@ -116,13 +123,6 @@
#error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE."
#endif
#endif
#if GWIN_NEED_PROGRESSBAR
#if GWIN_PROGRESSBAR_AUTO
#if !GFX_USE_GTIMER
#error "GWIN: GFX_USE_GTIMER is required if GWIN_PROGRESSBAR_AUTO is TRUE."
#endif
#endif
#endif
#endif
#endif /* _GWIN_RULES_H */