diff options
Diffstat (limited to 'src/gwin/gwm.c')
-rw-r--r-- | src/gwin/gwm.c | 711 |
1 files changed, 612 insertions, 99 deletions
diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c index 1c96d1c9..ffea4afd 100644 --- a/src/gwin/gwm.c +++ b/src/gwin/gwm.c @@ -7,55 +7,165 @@ #include "gfx.h" -// Used by the NULL window manager -#define MIN_WIN_WIDTH 3 -#define MIN_WIN_HEIGHT 3 +#if GFX_USE_GWIN && !GWIN_NEED_WINDOWMANAGER + /** + * A really nasty default implementation for the simplest of systems + */ -/*----------------------------------------------- - * The default window manager (GNullWindowManager) - *-----------------------------------------------*/ + + #include "src/gwin/class_gwin.h" + + // Needed if there is no window manager + #define MIN_WIN_WIDTH 1 + #define MIN_WIN_HEIGHT 1 + + static gfxMutex gmutex; + + void _gwmInit(void) { + gfxMutexInit(&gmutex); + } + + void _gwmDeinit(void) { + gfxMutexDestroy(&gmutex); + } + + bool_t _gwinWMAdd(GHandle gh, const GWindowInit *pInit) { + gh->x = gh->y = gh->width = gh->height = 0; + gwinMove(gh, pInit->x, pInit->y); + gwinResize(gh, pInit->width, pInit->height); + return TRUE; + } + + void _gwinFlushRedraws(bool_t doWait) { + (void) doWait; + + // We are always flushed + } + + + #if GDISP_NEED_CLIP + static void getLock(GHandle gh) { + gfxMutexEnter(&gmutex); + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + } + static void exitLock(GHandle gh) { + gdispGUnsetClip(gh->display); + gfxMutexExit(&gmutex); + } + #else + #define getLock(gh) gfxMutexEnter(&gmutex) + #define exitLock(gh) gfxMutexExit(&gmutex) + #endif + + void _gwinUpdate(GHandle gh) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { + if (gh->vmt->Redraw) { + getLock(gh); + gh->vmt->Redraw(gh); + exitLock(gh); + } else if ((gh->flags & GWIN_FLG_BGREDRAW)) { + getLock(gh); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + exitLock(gh); + if (gh->vmt->AfterClear) + gh->vmt->AfterClear(gh); + } + } else if ((gh->flags & GWIN_FLG_BGREDRAW)) { + getLock(gh); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + exitLock(gh); + } + gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW); + } + + bool_t _gwinDrawStart(GHandle gh) { + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return FALSE; + + getLock(gh); + return TRUE; + } + + void _gwinDrawEnd(GHandle gh) { + (void) gh; + exitLock(gh); + } + + void gwinSetVisible(GHandle gh, bool_t visible) { + if (visible) { + if (!(gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE|GWIN_FLG_BGREDRAW); + _gwinUpdate(gh); + } + } else { + if ((gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); + gh->flags |= GWIN_FLG_BGREDRAW; + _gwinUpdate(gh); + } + } + } + + void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + if (!(gh->flags & GWIN_FLG_ENABLED)) { + gh->flags |= (GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwinUpdate(gh); + } + } else { + if ((gh->flags & GWIN_FLG_ENABLED)) { + gh->flags &= ~(GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwinUpdate(gh); + } + } + } + + void gwinMove(GHandle gh, coord_t x, coord_t y) { + gh->x = x; gh->y = y; + if (gh->x < 0) gh->x = 0; + if (gh->y < 0) gh->y = 0; + if (gh->x > gdispGGetWidth(gh->display)-MIN_WIN_WIDTH) gh->x = gdispGGetWidth(gh->display)-MIN_WIN_WIDTH; + if (gh->y > gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT) gh->y = gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT; + if (gh->x+gh->width > gdispGGetWidth(gh->display)) gh->width = gdispGGetWidth(gh->display) - gh->x; + if (gh->y+gh->height > gdispGGetHeight(gh->display)) gh->height = gdispGGetHeight(gh->display) - gh->y; + _gwinUpdate(gh); + } + + void gwinResize(GHandle gh, coord_t width, coord_t height) { + gh->width = width; gh->height = height; + if (gh->width < MIN_WIN_WIDTH) { gh->width = MIN_WIN_WIDTH; } + if (gh->height < MIN_WIN_HEIGHT) { gh->height = MIN_WIN_HEIGHT; } + if (gh->x+gh->width > gdispGGetWidth(gh->display)) gh->width = gdispGGetWidth(gh->display) - gh->x; + if (gh->y+gh->height > gdispGGetHeight(gh->display)) gh->height = gdispGGetHeight(gh->display) - gh->y; + _gwinUpdate(gh); + } + + void gwinRedraw(GHandle gh) { + _gwinUpdate(gh); + } +#endif #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" /*----------------------------------------------- * Data *-----------------------------------------------*/ -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_Redraw(GHandle gh, int flags); -static void WM_Size(GHandle gh, coord_t w, coord_t h); -static void WM_Move(GHandle gh, coord_t x, coord_t y); -static void WM_Raise(GHandle gh); -static void WM_MinMax(GHandle gh, GWindowMinMax minmax); - -static const gwmVMT GNullWindowManagerVMT = { - WM_Init, - WM_DeInit, - WM_Add, - WM_Delete, - WM_Redraw, - WM_Size, - WM_Move, - WM_Raise, - WM_MinMax, -}; - -static const GWindowManager GNullWindowManager = { - &GNullWindowManagerVMT, -}; +// The default window manager +extern const GWindowManager GNullWindowManager; +GWindowManager * _GWINwm; +static gfxSem gwinsem; static gfxQueueASync _GWINList; -GWindowManager * _GWINwm; +static volatile bool_t RedrawPending; #if GFX_USE_GTIMER static GTimer RedrawTimer; - static GDisplay * RedrawDisplay; - static bool_t RedrawPreserve; - static void _gwinRedrawDisplay(void * param); + static void RedrawTimerFn(void *param); #endif /*----------------------------------------------- @@ -64,18 +174,178 @@ GWindowManager * _GWINwm; void _gwmInit(void) { + gfxSemInit(&gwinsem, 1, 1); gfxQueueASyncInit(&_GWINList); - _GWINwm = (GWindowManager *)&GNullWindowManager; - _GWINwm->vmt->Init(); #if GFX_USE_GTIMER gtimerInit(&RedrawTimer); - gtimerStart(&RedrawTimer, _gwinRedrawDisplay, 0, TRUE, TIME_INFINITE); + gtimerStart(&RedrawTimer, RedrawTimerFn, 0, TRUE, TIME_INFINITE); #endif + _GWINwm = (GWindowManager *)&GNullWindowManager; + _GWINwm->vmt->Init(); } void _gwmDeinit(void) { - /* ToDo */ + GHandle gh; + + while((gh = gwinGetNextWindow(0))) + gwinDestroy(gh); + + _GWINwm->vmt->DeInit(); + #if GFX_USE_GTIMER + gtimerDeinit(&RedrawTimer); + #endif + gfxQueueASyncDeinit(&_GWINList); + gfxSemDestroy(&gwinsem); +} + +#if GFX_USE_GTIMER + #define TriggerRedraw() gtimerJab(&RedrawTimer); + + static void RedrawTimerFn(void *param) { + (void) param; + _gwinFlushRedraws(FALSE); + } +#else + #define TriggerRedraw(void) _gwinFlushRedraws(FALSE); +#endif + +void _gwinFlushRedraws(bool_t doWait) { + GHandle gh; + + // Do we really need to do anything? + if (!RedrawPending) + return; + + // Obtain the drawing lock + if (doWait) + gfxSemWait(&gwinsem, TIME_INFINITE); + else if (!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; + + 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 + + // Postpone further redraws (if there are any and the options are set right) + #if GFX_USE_GTIMER && !GWIN_LONG_REDRAW + if (!doWait) { + while((gh = gwinGetNextWindow(gh))) { + if ((gh->flags & GWIN_FLG_NEEDREDRAW)) { + gtimerJab(&RedrawTimer); + RedrawPending = TRUE; + break; + } + } + break; + } + #endif + } + } + + // Release the lock + gfxSemSignal(&gwinsem); +} + +void _gwinUpdate(GHandle gh) { + // Only redraw if visible + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return; + + // Mark for redraw + gh->flags |= GWIN_FLG_NEEDREDRAW; + RedrawPending = TRUE; + + // Asynchronous redraw + TriggerRedraw(); +} + +bool_t _gwinDrawStart(GHandle gh) { + // This test should occur inside the lock. We do this + // here as well as an early out (more efficient). + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return FALSE; + + // Obtain the drawing lock + gfxSemWait(&gwinsem, TIME_INFINITE); + + // Re-test visibility as we may have waited a while + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) { + _gwinDrawEnd(gh); + return FALSE; + } + + // OK - we are ready to draw. + #if GDISP_NEED_CLIP + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif + return TRUE; +} + +void _gwinDrawEnd(GHandle gh) { + // Ensure there is no clip set + #if GDISP_NEED_CLIP + gdispGUnsetClip(gh->display); + #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 + } + } + + // Release the lock + gfxSemSignal(&gwinsem); +} + +bool_t _gwinWMAdd(GHandle gh, const GWindowInit *pInit) { + #if GWIN_NEED_CONTAINERS + // Save the parent + gh->parent = pInit->parent; + + // Ensure the display is consistent with any parents + if (gh->parent && (!(gh->parent->flags & GWIN_FLG_CONTAINER) || gh->display != gh->parent->display)) + return FALSE; + #endif + + // Add to the window manager + if (!_GWINwm->vmt->Add(gh, pInit)) + return FALSE; + + #if GWIN_NEED_CONTAINERS + // Notify the parent it has been added + if (gh->parent && ((gcontainerVMT *)gh->parent->vmt)->NotifyAdd) + ((gcontainerVMT *)gh->parent->vmt)->NotifyAdd(gh->parent, gh); + #endif + + return TRUE; } void gwinSetWindowManager(struct GWindowManager *gwm) { @@ -88,6 +358,142 @@ void gwinSetWindowManager(struct GWindowManager *gwm) { } } +void gwinRedraw(GHandle gh) { + // Only redraw if visible + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return; + + // Mark for redraw + gh->flags |= GWIN_FLG_NEEDREDRAW; + RedrawPending = TRUE; + + // Synchronous redraw + _gwinFlushRedraws(TRUE); +} + +#if GWIN_NEED_CONTAINERS + void gwinSetVisible(GHandle gh, bool_t visible) { + if (visible) { + // Mark us as visible + gh->flags |= GWIN_FLG_VISIBLE; + + // Do we want to be added to the display + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))) { + // Check each window's visibility is consistent with its parents + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { + if ((gh->flags & (GWIN_FLG_SYSVISIBLE|GWIN_FLG_VISIBLE)) == GWIN_FLG_VISIBLE && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))) + gh->flags |= (GWIN_FLG_SYSVISIBLE|GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW); // Fix it and mark for redraw + } + + // Mark for redraw + RedrawPending = TRUE; + TriggerRedraw(); + } + } else { + // Mark us as not visible + gh->flags &= ~GWIN_FLG_VISIBLE; + + // Do we need to be removed from the display + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { + gh->flags |= (GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW); + + // Check each window's visibility is consistent with its parents + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE) && (!(gh->flags & GWIN_FLG_VISIBLE) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSVISIBLE)))) + gh->flags &= ~GWIN_FLG_SYSVISIBLE; // Fix it + } + + // Mark for redraw - no need to redraw children + RedrawPending = TRUE; + TriggerRedraw(); + } + } + } +#else + void gwinSetVisible(GHandle gh, bool_t visible) { + if (visible) { + if (!(gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE|GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW); + RedrawPending = TRUE; + 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; + TriggerRedraw(); + } + } + } +#endif + +#if GWIN_NEED_CONTAINERS + // These two sub-functions set/clear system enable recursively. + void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + // Mark us as enabled + gh->flags |= GWIN_FLG_ENABLED; + + // Do we change our real enabled state + if (!(gh->flags & GWIN_FLG_SYSENABLED) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) { + // Check each window's enabled state is consistent with its parents + 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; + } + } + } + if (RedrawPending) + TriggerRedraw(); + } + } else { + gh->flags &= ~GWIN_FLG_ENABLED; + + // Do we need to change our real enabled state + if ((gh->flags & GWIN_FLG_SYSENABLED)) { + // Check each window's visibility is consistent with its parents + 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; + } + } + } + if (RedrawPending) + TriggerRedraw(); + } + } + } +#else + void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + if (!(gh->flags & GWIN_FLG_ENABLED)) { + gh->flags |= (GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwinUpdate(gh); + } + } else { + if ((gh->flags & GWIN_FLG_ENABLED)) { + gh->flags &= ~(GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwinUpdate(gh); + } + } + } +#endif + +void gwinMove(GHandle gh, coord_t x, coord_t y) { + _GWINwm->vmt->Move(gh, x, y); +} + +void gwinResize(GHandle gh, coord_t width, coord_t height) { + _GWINwm->vmt->Size(gh, width, height); +} + void gwinSetMinMax(GHandle gh, GWindowMinMax minmax) { _GWINwm->vmt->MinMax(gh, minmax); } @@ -105,31 +511,73 @@ GWindowMinMax gwinGetMinMax(GHandle gh) { } void gwinRedrawDisplay(GDisplay *g, bool_t preserve) { - #if GFX_USE_GTIMER - RedrawDisplay = g; - RedrawPreserve = preserve; - gtimerJab(&RedrawTimer); - } - static void _gwinRedrawDisplay(void * param) { - GDisplay *g = RedrawDisplay; - bool_t preserve = RedrawPreserve; - (void) param; - #endif - - GHandle gh; + GHandle gh; for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { - 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)); + + // Skip if it is for a different display + if (g && gh->display != g) + continue; + + #if GWIN_NEED_CONTAINERS + // Skip if it is not a top level window (parents internally take care of their children) + if (gh->parent) + continue; + #endif + + // Only visible windows are to be redrawn + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + continue; + + if (!preserve) + gh->flags |= GWIN_FLG_BGREDRAW; + + _gwinUpdate(gh); } } +GHandle gwinGetNextWindow(GHandle gh) { + return gh ? (GHandle)gfxQueueASyncNext(&gh->wmq) : (GHandle)gfxQueueASyncPeek(&_GWINList); +} + /*----------------------------------------------- * "Null" Window Manager Routines *-----------------------------------------------*/ +// This is a parent reveal operation +#define GWIN_FLG_PARENTREVEAL (GWIN_FIRST_WM_FLAG << 0) + +// Minimum dimensions +#define MIN_WIN_WIDTH 3 +#define MIN_WIN_HEIGHT 3 + + +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_Redraw(GHandle gh); +static void WM_Size(GHandle gh, coord_t w, coord_t h); +static void WM_Move(GHandle gh, coord_t x, coord_t y); +static void WM_Raise(GHandle gh); +static void WM_MinMax(GHandle gh, GWindowMinMax minmax); + +static const gwmVMT GNullWindowManagerVMT = { + WM_Init, + WM_DeInit, + WM_Add, + WM_Delete, + WM_Redraw, + WM_Size, + WM_Move, + WM_Raise, + WM_MinMax, +}; + +const GWindowManager GNullWindowManager = { + &GNullWindowManagerVMT, +}; + static void WM_Init(void) { // We don't need to do anything here. // A full window manager would move the windows around, add borders etc @@ -163,47 +611,55 @@ static void WM_Delete(GHandle gh) { gfxQueueASyncRemove(&_GWINList, &gh->wmq); } -static void WM_Redraw(GHandle gh, int flags) { +static void WM_Redraw(GHandle gh) { #if GWIN_NEED_CONTAINERS redo_redraw: #endif if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { - if (gh->vmt->Redraw) { - #if GDISP_NEED_CLIP - if (!(flags & GWIN_WMFLG_KEEPCLIP)) - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (gh->vmt->Redraw) gh->vmt->Redraw(gh); - } else if (!(flags & GWIN_WMFLG_PRESERVE)) { - #if GDISP_NEED_CLIP - if (!(flags & GWIN_WMFLG_KEEPCLIP)) - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + else if ((gh->flags & GWIN_FLG_BGREDRAW)) { + // We can't redraw but we want full coverage so just clear the area gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); - if (gh->vmt->AfterClear) + + // Only do an after clear if this is not a parent reveal + if (!(gh->flags & GWIN_FLG_PARENTREVEAL) && gh->vmt->AfterClear) gh->vmt->AfterClear(gh); } - // A real window manager would also redraw the borders here + // A real window manager would also redraw frame borders here for top level windows + // For non-top level windows their parent is responsible for any borders - // A real window manager would then redraw any higher z-order windows - // if (!(flags & GWIN_WMFLG_NOZORDER)) - // ... + // Redraw is done + gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL); - } else if (!(flags & GWIN_WMFLG_NOBGCLEAR)) { - #if GDISP_NEED_CLIP - if (!(flags & GWIN_WMFLG_KEEPCLIP)) - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif #if GWIN_NEED_CONTAINERS - if (gh->parent) { - // Get the parent to redraw the area - gh = gh->parent; - flags |= GWIN_WMFLG_KEEPCLIP; - goto redo_redraw; + // If this is container but not a parent reveal, mark any visible children for redraw + // We redraw our children here as we have overwritten them in redrawing the parent + // as GDISP/GWIN doesn't yet support complex clipping regions. + if ((gh->flags & (GWIN_FLG_CONTAINER|GWIN_FLG_PARENTREVEAL)) == GWIN_FLG_CONTAINER) { + for(gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) + _gwinUpdate(gh); } #endif - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + } else { + if ((gh->flags & GWIN_FLG_BGREDRAW)) { + #if GWIN_NEED_CONTAINERS + if (gh->parent) { + // Child redraw is done + gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL); + + // Get the parent to redraw the area + gh = gh->parent; + gh->flags |= (GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL); + goto redo_redraw; + } + #endif + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + } + + // Redraw is done + gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW|GWIN_FLG_PARENTREVEAL); } } @@ -234,15 +690,49 @@ static void WM_Size(GHandle gh, coord_t w, coord_t h) { if (gh->width == w && gh->height == h) return; - // Clear the old area and then redraw + // Set the new size and redraw if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { - gh->flags &= ~GWIN_FLG_SYSVISIBLE; - WM_Redraw(gh, 0); - gh->width = w; gh->height = h; - gh->flags |= GWIN_FLG_SYSVISIBLE; - WM_Redraw(gh, 0); + if (w >= gh->width && h >= gh->height) { + + // The new size is larger - just redraw + gh->width = w; gh->height = h; + _gwinUpdate(gh); + + } else { + // We need to make this window invisible and ensure that has been drawn + gwinSetVisible(gh, FALSE); + _gwinFlushRedraws(TRUE); + + // Resize + gh->width = w; gh->height = h; + + #if GWIN_NEED_CONTAINERS + // Any children outside the new area need to be moved + if ((gh->flags & GWIN_FLG_CONTAINER)) { + GHandle child; + + // Move to their old relative location. THe WM_Move() will adjust as necessary + for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) + WM_Move(gh, child->x-gh->x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-gh->y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent)); + } + #endif + + // Mark it visible again in its new location + gwinSetVisible(gh, TRUE); + } } else { gh->width = w; gh->height = h; + + #if GWIN_NEED_CONTAINERS + // Any children outside the new area need to be moved + if ((gh->flags & GWIN_FLG_CONTAINER)) { + GHandle child; + + // Move to their old relative location. THe WM_Move() will adjust as necessary + for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) + WM_Move(gh, child->x-gh->x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-gh->y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent)); + } + #endif } } @@ -279,13 +769,40 @@ static void WM_Move(GHandle gh, coord_t x, coord_t y) { // Clear the old area and then redraw if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { - gh->flags &= ~GWIN_FLG_SYSVISIBLE; - WM_Redraw(gh, 0); - gh->x = x; gh->y = y; - gh->flags |= GWIN_FLG_SYSVISIBLE; - WM_Redraw(gh, 0); + // We need to make this window invisible and ensure that has been drawn + gwinSetVisible(gh, FALSE); + _gwinFlushRedraws(TRUE); + + // Do the move + v = gh->x; gh->x = x; x = v; + v = gh->y; gh->y = y; y = v; + + #if GWIN_NEED_CONTAINERS + // Any children need to be moved + if ((gh->flags & GWIN_FLG_CONTAINER)) { + GHandle child; + + // Move to their old relative location. THe WM_Move() will adjust as necessary + for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) + WM_Move(gh, child->x-x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent)); + } + #endif + + gwinSetVisible(gh, TRUE); } else { - gh->x = x; gh->y = y; + v = gh->x; gh->x = x; x = v; + v = gh->y; gh->y = y; y = v; + + #if GWIN_NEED_CONTAINERS + // Any children need to be moved + if ((gh->flags & GWIN_FLG_CONTAINER)) { + GHandle child; + + // Move to their old relative location. THe WM_Move() will adjust as necessary + for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) + WM_Move(gh, child->x-x-((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent), child->y-y-((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent)); + } + #endif } } @@ -302,11 +819,7 @@ static void WM_Raise(GHandle gh) { gfxQueueASyncPut(&_GWINList, &gh->wmq); // Redraw the window - WM_Redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); -} - -GHandle gwinGetNextWindow(GHandle gh) { - return gh ? (GHandle)gfxQueueASyncNext(&gh->wmq) : (GHandle)gfxQueueASyncPeek(&_GWINList); + _gwinUpdate(gh); } #endif /* GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER */ |