From 34e23320b4c69f5e409f25431603d901abfc4740 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 21 May 2014 13:02:00 +1000 Subject: [PATCH] Significant changes to the window redrawing methodology. Move and Resize should probably work for containers now Still to be tested - nested containers, progressbar timers while redrawing its container, move/resize on containers. --- src/gwin/button.c | 8 +- src/gwin/checkbox.c | 6 +- src/gwin/class_gwin.h | 117 +++---- src/gwin/console.c | 95 ++++-- src/gwin/gcontainer.c | 40 --- src/gwin/gimage.c | 25 +- src/gwin/graph.c | 9 +- src/gwin/gwidget.c | 16 +- src/gwin/gwin.c | 401 ++++------------------- src/gwin/gwm.c | 713 +++++++++++++++++++++++++++++++++++------ src/gwin/list.c | 22 +- src/gwin/progressbar.c | 6 +- src/gwin/radio.c | 4 +- src/gwin/slider.c | 10 +- 14 files changed, 834 insertions(+), 638 deletions(-) diff --git a/src/gwin/button.c b/src/gwin/button.c index af837486..d489ecb0 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -50,14 +50,14 @@ static void SendButtonEvent(GWidgetObject *gw) { static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags |= GBUTTON_FLG_PRESSED; - _gwidgetUpdate((GHandle)gw); + _gwinUpdate((GHandle)gw); } // A mouse up has occurred (it may or may not be over the button) static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags &= ~GBUTTON_FLG_PRESSED; - _gwidgetUpdate((GHandle)gw); + _gwinUpdate((GHandle)gw); #if !GWIN_BUTTON_LAZY_RELEASE // If the mouse up was not over the button then cancel the event @@ -74,14 +74,14 @@ static void SendButtonEvent(GWidgetObject *gw) { static void ToggleOff(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags &= ~GBUTTON_FLG_PRESSED; - _gwidgetUpdate((GHandle)gw); + _gwinUpdate((GHandle)gw); } // A toggle on has occurred static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags |= GBUTTON_FLG_PRESSED; - _gwidgetUpdate((GHandle)gw); + _gwinUpdate((GHandle)gw); // Trigger the event on button down (different than for mouse/touch) SendButtonEvent(gw); } diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index 22e249ad..f162d8fc 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -43,7 +43,7 @@ static void SendCheckboxEvent(GWidgetObject *gw) { static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags ^= GCHECKBOX_FLG_CHECKED; - _gwidgetUpdate((GHandle)gw); + _gwinUpdate((GHandle)gw); SendCheckboxEvent(gw); } #endif @@ -52,7 +52,7 @@ static void SendCheckboxEvent(GWidgetObject *gw) { static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags ^= GCHECKBOX_FLG_CHECKED; - _gwidgetUpdate((GHandle)gw); + _gwinUpdate((GHandle)gw); SendCheckboxEvent(gw); } @@ -125,7 +125,7 @@ void gwinCheckboxCheck(GHandle gh, bool_t isChecked) { if (!(gh->flags & GCHECKBOX_FLG_CHECKED)) return; gh->flags &= ~GCHECKBOX_FLG_CHECKED; } - _gwidgetUpdate(gh); + _gwinUpdate(gh); SendCheckboxEvent((GWidgetObject *)gh); } diff --git a/src/gwin/class_gwin.h b/src/gwin/class_gwin.h index ceac3b3a..0aee1ae8 100644 --- a/src/gwin/class_gwin.h +++ b/src/gwin/class_gwin.h @@ -34,12 +34,14 @@ #define GWIN_FLG_SYSENABLED 0x00000800 // @< The window is enabled after parents are tested #define GWIN_FLG_DYNAMIC 0x00001000 // @< The GWIN structure is allocated #define GWIN_FLG_ALLOCTXT 0x00002000 // @< The text/label is allocated -#define GWIN_FLG_MOUSECAPTURE 0x00004000 // @< The window has captured the mouse +#define GWIN_FLG_NEEDREDRAW 0x00004000 // @< Redraw is needed but has been delayed +#define GWIN_FLG_BGREDRAW 0x00008000 // @< On redraw, if not visible redraw the revealed under-side #define GWIN_FLG_SUPERMASK 0x000F0000 // @< The bit mask to leave just the window superclass type #define GWIN_FLG_WIDGET 0x00010000 // @< This is a widget #define GWIN_FLG_CONTAINER 0x00020000 // @< This is a container #define GWIN_FLG_MINIMIZED 0x00100000 // @< The window is minimized #define GWIN_FLG_MAXIMIZED 0x00200000 // @< The window is maximized +#define GWIN_FLG_MOUSECAPTURE 0x00400000 // @< The window has captured the mouse #define GWIN_FIRST_WM_FLAG 0x01000000 // @< 8 bits free for the window manager to use /** @} */ @@ -131,17 +133,6 @@ 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_KEEPCLIP 0x0004 // @< Don't modify the preset clipping area -#define GWIN_WMFLG_NOZORDER 0x0008 // @< Don't redraw higher z-order windows that overlap -/** @} */ - #if GWIN_NEED_WINDOWMANAGER || defined(__DOXYGEN__) // @note There is only ever one instance of each GWindowManager type typedef struct GWindowManager { @@ -157,7 +148,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 (*Redraw) (GHandle gh, int visflags); // @< A window needs to be redraw (or undrawn) + void (*Redraw) (GHandle gh); // @< A window needs to be redraw (or undrawn) void (*Size) (GHandle gh, coord_t w, coord_t h); // @< A window wants to be resized void (*Move) (GHandle gh, coord_t x, coord_t y); // @< A window wants to be moved void (*Raise) (GHandle gh); // @< A window wants to be on top @@ -190,6 +181,62 @@ extern "C" { */ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint32_t flags); +/** + * @brief Redraw the window after a status change. + * + * @param[in] gh The widget to redraw + * + * @note Mark a window for redraw. + * @note The window will get redrawn at some later time. + * @note This call is designed to be fast and non-blocking + * + * @notapi + */ +void _gwinUpdate(GHandle gh); + +/** + * @brief Flush any pending redraws in the system. + * + * @param[in] doWait Do we wait for the lock? + * + * @note This call will attempt to flush any pending redraws + * in the system. The doWait parameter tells this call + * how to handle someone already holding the drawing lock. + * If doWait is TRUE it waits to obtain the lock. If FALSE + * and the drawing lock is free then the redraw is done + * immediately. If the drawing lock was taken it will postpone the flush + * on the basis that someone else will do it for us later. + * + * @notapi + */ +void _gwinFlushRedraws(bool_t doWait); + +/** + * @brief Obtain a drawing session + * @return TRUE if the drawing session was obtained, FALSE if the window is not visible + * + * @param[in] gh The window + * + * @note This function blocks until a drawing session is available if the window is visible + */ +bool_t _gwinDrawStart(GHandle gh); + +/** + * @brief Release a drawing session + * + * @param[in] gh The window + */ +void _gwinDrawEnd(GHandle gh); + +/** + * @brief Add a window to the window manager and set its position and size + * @return TRUE if successful + * + * @param[in] gh The window + * @param[in] pInit The window init structure + */ +bool_t _gwinWMAdd(GHandle gh, const GWindowInit *pInit); + #if GWIN_NEED_WIDGET || defined(__DOXYGEN__) /** * @brief Initialise (and allocate if necessary) the base Widget object @@ -220,24 +267,12 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit * @param[in] gh The widget to redraw * * @note Do not use this routine to update a widget after a status change. - * Use @p _gwidgetUpdate() instead. The difference is that this routine - * does not set the clip region. This routine should only be used in the + * Use @p _gwinUpdate() instead. This routine should only be used in the * VMT. * * @notapi */ void _gwidgetRedraw(GHandle gh); - - /** - * @brief Redraw the Widget object after a widget status change. - * - * @param[in] gh The widget to redraw - * - * @note Use this routine to update a widget after a status change. - * - * @notapi - */ - void _gwidgetUpdate(GHandle gh); #endif #if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) @@ -270,38 +305,12 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit * @param[in] gh The container to redraw * * @note Do not use this routine to update a container after a status change. - * Use @p _gcontainerUpdate() instead. The difference is that this routine - * does not set the clip region. This routine should only be used in the + * Use @p _gwinUpdate() instead. This routine should only be used in the * VMT. * * @notapi */ - void _gcontainerRedraw(GHandle gh); - - /** - * @brief Redraw the Container object after a container status change. - * - * @param[in] gh The container to redraw - * - * @note Use this routine to update a container after a status change. - * - * @notapi - */ - void _gcontainerUpdate(GHandle gh); - - /** - * @brief Apply the specified action to a window and its children. - * @note The action is applied to the parent first and then its children. - * @note This routine is built to keep stack usage from recursing to a minimum. - * - * @param[in] gh The window to recurse through - * @param[in] fn The function to apply. If it returns TRUE any children it has should also have the function applied - * - * @notapi - */ - void _gwinRecurse(GHandle gh, bool_t (*fn)(GHandle gh)); -#else - #define _gwinRecurse(gh, fn) fn(gh) + #define _gcontainerRedraw _gwidgetRedraw #endif #ifdef __cplusplus diff --git a/src/gwin/console.c b/src/gwin/console.c index fa93c79d..0380fd61 100644 --- a/src/gwin/console.c +++ b/src/gwin/console.c @@ -399,6 +399,18 @@ GHandle gwinGConsoleCreate(GDisplay *g, GConsoleObject *gc, const GWindowInit *p } #endif +/* + * We can get into gwinPutChar() 2 ways - + * 1. when the user calls us, and + * 2. when the redraw uses us to redraw the display. + * When called by option 2 we MUST not try to obtain a draw session + * as we already have one. + * + * We use these macro's below to make sure we do that safely + */ +#define DrawStart(gh) ((gh->flags & GCONSOLE_FLG_NOSTORE) || _gwinDrawStart(gh)) +#define DrawEnd(gh) { if (!(gh->flags & GCONSOLE_FLG_NOSTORE)) _gwinDrawEnd(gh); } + void gwinPutChar(GHandle gh, char c) { #define gcw ((GConsoleObject *)gh) uint8_t width, fy; @@ -406,16 +418,8 @@ void gwinPutChar(GHandle gh, char c) { if (gh->vmt != &consoleVMT || !gh->font) return; - // only render new character if the console is visible - if (!gwinGetVisible(gh)) - return; - fy = gdispGetFontMetric(gh->font, fontHeight); - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - #if GWIN_CONSOLE_ESCSEQ /** * Handle escape sequences @@ -444,7 +448,10 @@ void gwinPutChar(GHandle gh, char c) { case 'J': // Clear the console and reset the cursor clearBuffer(gcw); - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + if (DrawStart(gh)) { + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + DrawEnd(gh); + } gcw->cx = 0; gcw->cy = 0; gcw->startattr = gcw->currattr; @@ -469,8 +476,10 @@ void gwinPutChar(GHandle gh, char c) { case '\n': // clear to the end of the line #if GWIN_CONSOLE_USE_CLEAR_LINES - if (gcw->cx == 0 && gcw->cy+fy < gh->height) + if (gcw->cx == 0 && gcw->cy+fy < gh->height && DrawStart(gh)) { gdispGFillArea(gh->display, gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor); + DrawEnd(gh); + } #endif // update the cursor gcw->cx = 0; @@ -513,14 +522,20 @@ void gwinPutChar(GHandle gh, char c) { if (gcw->buffer) { // Scroll the buffer and then redraw using the buffer scrollBuffer(gcw); - HistoryRedraw(gh); + if (DrawStart(gh)) { + HistoryRedraw(gh); + DrawEnd(gh); + } } else #endif #if GDISP_NEED_SCROLL { // Scroll the console using hardware scrollBuffer(gcw); - gdispGVerticalScroll(gh->display, gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor); + if (DrawStart(gh)) { + gdispGVerticalScroll(gh->display, gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor); + DrawEnd(gh); + } // Set the cursor to the start of the last line gcw->cx = 0; @@ -530,7 +545,10 @@ void gwinPutChar(GHandle gh, char c) { { // Clear the console and reset the cursor clearBuffer(gcw); - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + if (DrawStart(gh)) { + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + DrawEnd(gh); + } gcw->cx = 0; gcw->cy = 0; #if GWIN_CONSOLE_ESCSEQ @@ -540,30 +558,37 @@ void gwinPutChar(GHandle gh, char c) { #endif } - // If we are at the beginning of a new line clear the line - #if GWIN_CONSOLE_USE_CLEAR_LINES - if (gcw->cx == 0) - gdispGFillArea(gh->display, gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor); - #endif - - // Draw the character - #if GWIN_CONSOLE_USE_FILLED_CHARS - gdispGFillChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw), gh->bgcolor); - #else - gdispGDrawChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw)); - #endif + // Save the char putCharInBuffer(gcw, c); - #if GWIN_CONSOLE_ESCSEQ - // Draw the underline - if ((gcw->currattr & ESC_UNDERLINE)) - gdispGDrawLine(gh->display, gh->x + gcw->cx, gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight), - gh->x + gcw->cx + width + gdispGetFontMetric(gh->font, fontCharPadding), gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight), - ESCPrintColor(gcw)); - // Bold (very crude) - if ((gcw->currattr & ESC_BOLD)) - gdispGDrawChar(gh->display, gh->x + gcw->cx + 1, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw)); - #endif + // Draw the character + if (DrawStart(gh)) { + + // If we are at the beginning of a new line clear the line + #if GWIN_CONSOLE_USE_CLEAR_LINES + if (gcw->cx == 0) + gdispGFillArea(gh->display, gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor); + #endif + + #if GWIN_CONSOLE_USE_FILLED_CHARS + gdispGFillChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw), gh->bgcolor); + #else + gdispGDrawChar(gh->display, gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw)); + #endif + + #if GWIN_CONSOLE_ESCSEQ + // Draw the underline + if ((gcw->currattr & ESC_UNDERLINE)) + gdispGDrawLine(gh->display, gh->x + gcw->cx, gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight), + gh->x + gcw->cx + width + gdispGetFontMetric(gh->font, fontCharPadding), gh->y + gcw->cy + fy - gdispGetFontMetric(gh->font, fontDescendersHeight), + ESCPrintColor(gcw)); + // Bold (very crude) + if ((gcw->currattr & ESC_BOLD)) + gdispGDrawChar(gh->display, gh->x + gcw->cx + 1, gh->y + gcw->cy, c, gh->font, ESCPrintColor(gcw)); + #endif + + DrawEnd(gh); + } // Update the cursor gcw->cx += width + gdispGetFontMetric(gh->font, fontCharPadding); diff --git a/src/gwin/gcontainer.c b/src/gwin/gcontainer.c index 998433b4..46e89032 100644 --- a/src/gwin/gcontainer.c +++ b/src/gwin/gcontainer.c @@ -41,46 +41,6 @@ void _gcontainerDestroy(GHandle gh) { _gwidgetDestroy(gh); } -void _gcontainerRedraw(GHandle gh) { - GHandle child; - - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - ((GWidgetObject *)gh)->fnDraw((GWidgetObject *)gh, ((GWidgetObject *)gh)->fnParam); - - for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) - gwinRedraw(child); -} - -void _gcontainerUpdate(GHandle gh) { - GHandle child; - - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - ((GWidgetObject *)gh)->fnDraw((GWidgetObject *)gh, ((GWidgetObject *)gh)->fnParam); - - for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) - gwinRedraw(child); -} - -void _gwinRecurse(GHandle gh, bool_t (*fn)(GHandle gh)) { - if (fn(gh) && (gh->flags & GWIN_FLG_CONTAINER)) { - // Apply to this windows children - for(gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) { - // Only recurse when we have to. Otherwise apply it directly - if ((gh->flags & GWIN_FLG_CONTAINER)) - _gwinRecurse(gh, fn); - else - fn(gh); - } - } -} - GHandle gwinGetFirstChild(GHandle gh) { GHandle child; diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c index a4f477e9..d5ca2c38 100644 --- a/src/gwin/gimage.c +++ b/src/gwin/gimage.c @@ -24,22 +24,8 @@ static void _destroy(GWindowObject *gh) { } #if GWIN_NEED_IMAGE_ANIMATION - static void _redraw(GHandle gh); - static void _timer(void *param) { - #define gh ((GHandle)param) - - // We need to re-test the visibility in case it has been made invisible since the last frame. - if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { - // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw - // but we put it in for safety anyway - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - _redraw(gh); - } - - #undef gh + _gwinUpdate((GHandle)param); } #endif @@ -160,14 +146,7 @@ bool_t gwinImageOpenGFile(GHandle gh, GFILE *f) { if ((gdispImageOpenGFile(&widget(gh)->image, f) & GDISP_IMAGE_ERR_UNRECOVERABLE)) return FALSE; - if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { - // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw - // but we put it in for safety anyway - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - _redraw(gh); - } + _gwinUpdate(gh); return TRUE; } diff --git a/src/gwin/graph.c b/src/gwin/graph.c index 8f7223e1..4fcfad37 100644 --- a/src/gwin/graph.c +++ b/src/gwin/graph.c @@ -208,7 +208,7 @@ void gwinGraphDrawAxis(GHandle gh) { #define gg ((GGraphObject *)gh) coord_t i, xmin, ymin, xmax, ymax; - if (gh->vmt != &graphVMT) + if (gh->vmt != &graphVMT || !_gwinDrawStart(gh)) return; xmin = -gg->xorigin; @@ -262,6 +262,7 @@ void gwinGraphDrawAxis(GHandle gh) { } } + _gwinDrawEnd(gh); #undef gg } @@ -275,7 +276,7 @@ void gwinGraphStartSet(GHandle gh) { void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) { #define gg ((GGraphObject *)gh) - if (gh->vmt != &graphVMT) + if (gh->vmt != &graphVMT || !_gwinDrawStart(gh)) return; if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) { @@ -295,6 +296,7 @@ void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) { // Draw this point. pointto(gg, x, y, &gg->style.point); + _gwinDrawEnd(gh); #undef gg } @@ -303,7 +305,7 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) { unsigned i; const point *p; - if (gh->vmt != &graphVMT) + if (gh->vmt != &graphVMT || !_gwinDrawStart(gh)) return; // Draw the connecting lines @@ -329,6 +331,7 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) { for(p = points, i = 0; i < count; p++, i++) pointto(gg, p->x, p->y, &gg->style.point); + _gwinDrawEnd(gh); #undef gg } diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c index ccfbd26e..8ccb47fc 100644 --- a/src/gwin/gwidget.c +++ b/src/gwin/gwidget.c @@ -292,16 +292,6 @@ void _gwidgetRedraw(GHandle gh) { gw->fnDraw(gw, gw->fnParam); } -void _gwidgetUpdate(GHandle gh) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gw->fnDraw(gw, gw->fnParam); -} - void gwinWidgetClearInit(GWidgetInit *pwi) { char *p; unsigned len; @@ -364,7 +354,7 @@ void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) { gw->text = (const char *)str; } else gw->text = text; - _gwidgetUpdate(gh); + _gwinUpdate(gh); } const char *gwinGetText(GHandle gh) { @@ -380,7 +370,7 @@ void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) { gw->pstyle = pstyle ? pstyle : defaultStyle; gh->bgcolor = pstyle->background; gh->color = pstyle->enabled.text; - _gwidgetUpdate(gh); + _gwinUpdate(gh); } const GWidgetStyle *gwinGetStyle(GHandle gh) { @@ -396,7 +386,7 @@ void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { gw->fnDraw = fn ? fn : wvmt->DefaultDraw; gw->fnParam = param; - _gwidgetUpdate(gh); + _gwinUpdate(gh); } bool_t gwinAttachListener(GListener *pl) { diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index 2e4144a7..e1625b13 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -11,10 +11,6 @@ #include "src/gwin/class_gwin.h" -// Needed if there is no window manager -#define MIN_WIN_WIDTH 1 -#define MIN_WIN_HEIGHT 1 - /*----------------------------------------------- * Data *-----------------------------------------------*/ @@ -37,64 +33,15 @@ static color_t defaultBgColor = Black; * Helper Routines *-----------------------------------------------*/ -#if GWIN_NEED_WINDOWMANAGER - #define _gwm_redraw(gh, flags) _GWINwm->vmt->Redraw(gh, flags) - #define _gwm_move(gh,x,y) _GWINwm->vmt->Move(gh,x,y); - #define _gwm_resize(gh,w,h) _GWINwm->vmt->Size(gh,w,h); -#else - static void _gwm_redraw(GHandle gh, int flags) { - if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { - 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 - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, defaultBgColor); - } - } - static void _gwm_resize(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 > gdispGetWidth()) gh->width = gdispGetWidth() - gh->x; - if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y; - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); - } - static void _gwm_move(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 > gdispGetWidth()-MIN_WIN_WIDTH) gh->x = gdispGetWidth()-MIN_WIN_WIDTH; - if (gh->y > gdispGetHeight()-MIN_WIN_HEIGHT) gh->y = gdispGetHeight()-MIN_WIN_HEIGHT; - if (gh->x+gh->width > gdispGetWidth()) gh->width = gdispGetWidth() - gh->x; - if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y; - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); - } -#endif - /*----------------------------------------------- * Class Routines *-----------------------------------------------*/ void _gwinInit(void) { - #if GWIN_NEED_WINDOWMANAGER - extern void _gwmInit(void); + extern void _gwmInit(void); - _gwmInit(); - #endif + _gwmInit(); #if GWIN_NEED_WIDGET extern void _gwidgetInit(void); @@ -109,6 +56,8 @@ void _gwinInit(void) void _gwinDeinit(void) { + extern void _gwmDeinit(void); + #if GWIN_NEED_CONTAINERS extern void _gcontainerDeinit(void); @@ -119,11 +68,8 @@ void _gwinDeinit(void) _gwidgetDeinit(); #endif - #if GWIN_NEED_WINDOWMANAGER - extern void _gwmDeinit(void); - _gwmDeinit(); - #endif + _gwmDeinit(); } // Internal routine for use by GWIN components only @@ -146,35 +92,11 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit pgw->font = defaultFont; #endif - #if GWIN_NEED_CONTAINERS - if (pInit->parent) { - if (!(pInit->parent->flags & GWIN_FLG_CONTAINER) || pgw->display != pInit->parent->display) { - if ((pgw->flags & GWIN_FLG_DYNAMIC)) - gfxFree(pgw); - return 0; - } - pgw->parent = pInit->parent; - } else - pgw->parent = 0; - #endif - - #if GWIN_NEED_WINDOWMANAGER - if (!_GWINwm->vmt->Add(pgw, pInit)) { - if ((pgw->flags & GWIN_FLG_DYNAMIC)) - gfxFree(pgw); - return 0; - } - #else - pgw->x = pgw->y = pgw->width = pgw->height = 0; - _gwm_move(pgw, pInit->x, pInit->y); - _gwm_resize(pgw, pInit->width, pInit->height); - #endif - - #if GWIN_NEED_CONTAINERS - // Notify the parent it has been added - if (pgw->parent && ((gcontainerVMT *)pgw->parent->vmt)->NotifyAdd) - ((gcontainerVMT *)pgw->parent->vmt)->NotifyAdd(pgw->parent, pgw); - #endif + if (!_gwinWMAdd(pgw, pInit)) { + if ((pgw->flags & GWIN_FLG_DYNAMIC)) + gfxFree(pgw); + return 0; + } return (GHandle)pgw; } @@ -264,126 +186,14 @@ const char *gwinGetClassName(GHandle gh) { return gh->vmt->classname; } -#if GWIN_NEED_CONTAINERS - // These two sub-functions set/clear system visibility recursively. - static bool_t setSysVisFlag(GHandle gh) { - // If we are now visible and our parent is visible - if ((gh->flags & GWIN_FLG_VISIBLE) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))) { - gh->flags |= GWIN_FLG_SYSVISIBLE; - return TRUE; - } - return FALSE; - } - static bool_t clrSysVisFlag(GHandle gh) { - // If we are now not visible but our parent is visible - if (!(gh->flags & GWIN_FLG_VISIBLE) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSVISIBLE))) { - gh->flags &= ~GWIN_FLG_SYSVISIBLE; - return TRUE; - } - return FALSE; - } - void gwinSetVisible(GHandle gh, bool_t visible) { - if (visible) { - if (!(gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags |= GWIN_FLG_VISIBLE; - _gwinRecurse(gh, setSysVisFlag); - _gwm_redraw(gh, 0); - } - } else { - if ((gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags &= ~GWIN_FLG_VISIBLE; - _gwinRecurse(gh, clrSysVisFlag); - _gwm_redraw(gh, 0); - } - } - } -#else - void gwinSetVisible(GHandle gh, bool_t visible) { - if (visible) { - if (!(gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); - _gwm_redraw(gh, 0); - } - } else { - if ((gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); - _gwm_redraw(gh, 0); - } - } - } -#endif - bool_t gwinGetVisible(GHandle gh) { return (gh->flags & GWIN_FLG_SYSVISIBLE) ? TRUE : FALSE; } -#if GWIN_NEED_CONTAINERS - // These two sub-functions set/clear system enable recursively. - static bool_t setSysEnaFlag(GHandle gh) { - // If we are now enabled and our parent is enabled - if ((gh->flags & GWIN_FLG_ENABLED) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) { - gh->flags |= GWIN_FLG_SYSENABLED; - return TRUE; - } - return FALSE; - } - static bool_t clrSysEnaFlag(GHandle gh) { - // If we are now not enabled but our parent is enabled - if (!(gh->flags & GWIN_FLG_ENABLED) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSENABLED))) { - gh->flags &= ~GWIN_FLG_SYSENABLED; - return TRUE; - } - return FALSE; - } - void gwinSetEnabled(GHandle gh, bool_t enabled) { - if (enabled) { - if (!(gh->flags & GWIN_FLG_ENABLED)) { - gh->flags |= GWIN_FLG_ENABLED; - _gwinRecurse(gh, setSysEnaFlag); - if ((gh->flags & GWIN_FLG_SYSVISIBLE)) - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE); - } - } else { - if ((gh->flags & GWIN_FLG_ENABLED)) { - gh->flags &= ~GWIN_FLG_ENABLED; - _gwinRecurse(gh, clrSysEnaFlag); - if ((gh->flags & GWIN_FLG_SYSVISIBLE)) - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE); - } - } - } -#else - void gwinSetEnabled(GHandle gh, bool_t enabled) { - if (enabled) { - if (!(gh->flags & GWIN_FLG_ENABLED)) { - gh->flags |= (GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); - } - } else { - if ((gh->flags & GWIN_FLG_ENABLED)) { - gh->flags &= ~(GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); - } - } - } -#endif - bool_t gwinGetEnabled(GHandle gh) { return (gh->flags & GWIN_FLG_SYSENABLED) ? TRUE : FALSE; } -void gwinMove(GHandle gh, coord_t x, coord_t y) { - _gwm_move(gh, x, y); -} - -void gwinResize(GHandle gh, coord_t width, coord_t height) { - _gwm_resize(gh, width, height); -} - -void gwinRedraw(GHandle gh) { - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); -} - #if GDISP_NEED_TEXT void gwinSetFont(GHandle gh, font_t font) { gh->font = font; @@ -396,247 +206,154 @@ void gwinClear(GHandle gh) { * still call the AfterClear() routine as some widgets will * need this to clear internal buffers or similar */ - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) { - if (gh->vmt->AfterClear) - gh->vmt->AfterClear(gh); - } else { - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - + if (_gwinDrawStart(gh)) { gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); - if (gh->vmt->AfterClear) - gh->vmt->AfterClear(gh); + _gwinDrawEnd(gh); } - - #if GWIN_NEED_CONTAINERS - for (gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) - gwinRedraw(gh); - #endif + if (gh->vmt->AfterClear) + gh->vmt->AfterClear(gh); } void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGDrawPixel(gh->display, gh->x+x, gh->y+y, gh->color); + _gwinDrawEnd(gh); } void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGDrawLine(gh->display, gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color); + _gwinDrawEnd(gh); } void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGDrawBox(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color); + _gwinDrawEnd(gh); } void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGFillArea(gh->display, gh->x+x, gh->y+y, cx, cy, gh->color); + _gwinDrawEnd(gh); } void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGBlitArea(gh->display, gh->x+x, gh->y+y, cx, cy, srcx, srcy, srccx, buffer); + _gwinDrawEnd(gh); } #if GDISP_NEED_CIRCLE void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGDrawCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color); + _gwinDrawEnd(gh); } void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGFillCircle(gh->display, gh->x+x, gh->y+y, radius, gh->color); + _gwinDrawEnd(gh); } #endif #if GDISP_NEED_ELLIPSE void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGDrawEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color); + _gwinDrawEnd(gh); } void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGFillEllipse(gh->display, gh->x+x, gh->y+y, a, b, gh->color); + _gwinDrawEnd(gh); } #endif #if GDISP_NEED_ARC void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGDrawArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color); + _gwinDrawEnd(gh); } void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGFillArc(gh->display, gh->x+x, gh->y+y, radius, startangle, endangle, gh->color); + _gwinDrawEnd(gh); } #endif #if GDISP_NEED_PIXELREAD color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return defaultBgColor; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; return gdispGGetPixelColor(gh->display, gh->x+x, gh->y+y); + _gwinDrawEnd(gh); } #endif #if GDISP_NEED_TEXT void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!gh->font || !_gwinDrawStart(gh)) return; gdispGDrawChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color); + _gwinDrawEnd(gh); } void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!gh->font || !_gwinDrawStart(gh)) return; gdispGFillChar(gh->display, gh->x+x, gh->y+y, c, gh->font, gh->color, gh->bgcolor); + _gwinDrawEnd(gh); } void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!gh->font || !_gwinDrawStart(gh)) return; gdispGDrawString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color); + _gwinDrawEnd(gh); } void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!gh->font || !_gwinDrawStart(gh)) return; gdispGFillString(gh->display, gh->x+x, gh->y+y, str, gh->font, gh->color, gh->bgcolor); + _gwinDrawEnd(gh); } void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!gh->font || !_gwinDrawStart(gh)) return; gdispGDrawStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, justify); + _gwinDrawEnd(gh); } void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!gh->font || !_gwinDrawStart(gh)) return; gdispGFillStringBox(gh->display, gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, gh->bgcolor, justify); + _gwinDrawEnd(gh); } #endif #if GDISP_NEED_CONVEX_POLYGON void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGDrawPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color); + _gwinDrawEnd(gh); } void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + if (!_gwinDrawStart(gh)) return; gdispGFillConvexPoly(gh->display, tx+gh->x, ty+gh->y, pntarray, cnt, gh->color); + _gwinDrawEnd(gh); } #endif #if GDISP_NEED_IMAGE gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return GDISP_IMAGE_ERR_OK; + gdispImageError ret; - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - return gdispGImageDraw(gh->display, img, gh->x+x, gh->y+y, cx, cy, sx, sy); + if (!_gwinDrawStart(gh)) return GDISP_IMAGE_ERR_OK; + ret = gdispGImageDraw(gh->display, img, gh->x+x, gh->y+y, cx, cy, sx, sy); + _gwinDrawEnd(gh); + return ret; } #endif 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, -}; - -static gfxQueueASync _GWINList; +// The default window manager +extern const GWindowManager GNullWindowManager; GWindowManager * _GWINwm; + +static gfxSem gwinsem; +static gfxQueueASync _GWINList; +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 */ diff --git a/src/gwin/list.c b/src/gwin/list.c index 2024d411..c2a857e3 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -102,7 +102,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); } } - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); sendListEvent(gw, item); } @@ -131,14 +131,14 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top -= iheight; if (gw2obj->top < 0) gw2obj->top = 0; - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); } } else if (y >= gw->g.height - 2*ARROW) { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { gw2obj->top += iheight; if (gw2obj->top > gw2obj->cnt * iheight - pgsz) gw2obj->top = gw2obj->cnt * iheight - pgsz; - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); } } else if (y < gw->g.height/2) { if (gw2obj->top > 0) { @@ -146,7 +146,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top -= pgsz; else gw2obj->top = 0; - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); } } else { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { @@ -154,7 +154,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top += pgsz; else gw2obj->top = gw2obj->cnt * iheight - pgsz; - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); } } return; @@ -192,7 +192,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top = 0; gw2obj->last_mouse_y = y; if (oldtop != gw2obj->top) - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); } } #endif @@ -213,7 +213,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); if (qix) { qi2li->flags &=~ GLIST_FLG_SELECTED; qix2li->flags |= GLIST_FLG_SELECTED; - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); } break; } @@ -230,7 +230,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); if (qix) { qi2li->flags &=~ GLIST_FLG_SELECTED; qix2li->flags |= GLIST_FLG_SELECTED; - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); } break; } @@ -383,7 +383,7 @@ int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) { // increment the total amount of entries in the list widget gh2obj->cnt++; - _gwidgetUpdate(gh); + _gwinUpdate(gh); // return the position in the list (-1 because we start with index 0) return gh2obj->cnt-1; @@ -481,7 +481,7 @@ void gwinListDeleteAll(GHandle gh) { gh->flags &= ~GLIST_FLG_HASIMAGES; gh2obj->cnt = 0; gh2obj->top = 0; - _gwidgetUpdate(gh); + _gwinUpdate(gh); } void gwinListItemDelete(GHandle gh, int item) { @@ -502,7 +502,7 @@ void gwinListItemDelete(GHandle gh, int item) { gfxFree((void *)qi); if (gh2obj->top >= item && gh2obj->top) gh2obj->top--; - _gwidgetUpdate(gh); + _gwinUpdate(gh); break; } } diff --git a/src/gwin/progressbar.c b/src/gwin/progressbar.c index c1f9a113..90be6e43 100644 --- a/src/gwin/progressbar.c +++ b/src/gwin/progressbar.c @@ -123,7 +123,7 @@ void gwinProgressbarSetPosition(GHandle gh, int pos) { } ResetDisplayPos(gsw); - _gwidgetUpdate(gh); + _gwinUpdate(gh); #undef gsw } @@ -154,7 +154,7 @@ void gwinProgressbarIncrement(GHandle gh) { gsw->pos = gsw->max; ResetDisplayPos(gsw); - _gwidgetUpdate(gh); + _gwinUpdate(gh); #undef gsw } @@ -173,7 +173,7 @@ void gwinProgressbarDecrement(GHandle gh) { gsw->pos -= gsw->res; ResetDisplayPos(gsw); - _gwidgetUpdate(gh); + _gwinUpdate(gh); #undef gsw } diff --git a/src/gwin/radio.c b/src/gwin/radio.c index 9928e32c..af7b877d 100644 --- a/src/gwin/radio.c +++ b/src/gwin/radio.c @@ -128,10 +128,10 @@ void gwinRadioPress(GHandle gh) { if ((gx = gwinRadioGetActive(((GRadioObject *)gh)->group))) { gx->flags &= ~GRADIO_FLG_PRESSED; - _gwidgetUpdate(gx); + _gwinUpdate(gx); } gh->flags |= GRADIO_FLG_PRESSED; - _gwidgetUpdate(gh); + _gwinUpdate(gh); SendRadioEvent((GWidgetObject *)gh); } diff --git a/src/gwin/slider.c b/src/gwin/slider.c index e066f798..b488f823 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -69,7 +69,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { if (x < 0 || x >= gh->width || y < 0 || y >= gh->height) { // No - restore the slider ResetDisplayPos(gsw); - _gwidgetUpdate(gh); + _gwinUpdate(gh); return; } #endif @@ -92,7 +92,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { } ResetDisplayPos(gsw); - _gwidgetUpdate(gh); + _gwinUpdate(gh); // Generate the event SendSliderEvent(gw); @@ -122,7 +122,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { } // Update the display - _gwidgetUpdate(&gw->g); + _gwinUpdate(&gw->g); #undef gsw } #endif @@ -164,7 +164,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/max + gsw->min); ResetDisplayPos(gsw); - _gwidgetUpdate((GHandle)gw); + _gwinUpdate((GHandle)gw); // Generate the event SendSliderEvent(gw); @@ -267,7 +267,7 @@ void gwinSliderSetPosition(GHandle gh, int pos) { else gsw->pos = pos; } ResetDisplayPos(gsw); - _gwidgetUpdate(gh); + _gwinUpdate(gh); #undef gsw }