/******************************************************************
*
* Local typedefs
*
*******************************************************************
*/
typedef struct {
GUI_RECT ClientRect;
GUI_RECT CurRect;
int Cnt;
int EntranceCnt;
} WM_IVR_CONTEXT;
/******************************************************************
*
* WM_ global data
*
*******************************************************************
*/
U8 WM_IsActive;
U16 WM__CreateFlags;
WM_DELETE_WINDOW_HOOK* WM__pfDeleteWindowHook;
GUI_COLOR WM__BkColor = GUI_INVALID_COLOR;
WM_HWIN WM__hCapture, WM__hWinFocus;
char WM__CaptureReleaseAuto;
WM_tfPollPID* WM_pfPollPID;
/******************************************************************
*
* Static data
*
*******************************************************************
*/
static WM_HWIN NextDrawWin;
static U8 IsInCallback;
static WM_IVR_CONTEXT ClipContext;
static char _IsInited;
/*******************************************************************
*
* Static routines
*
********************************************************************
*/
/*******************************************************************
*
* _ClipAtParentBorders
Iterates over all its ancestors and intersects all rectangles to
find out which part is actually visible.
Reduces the rectangle to the visible area.
*/
void _ClipAtParentBorders(GUI_RECT* pRect, WM_Obj* pWin) {
WM_HWIN hWin;
hWin = pWin->hParent;
while (hWin) {
pWin = WM_H2P(hWin);
GUI__IntersectRect(pRect, &pWin->Rect);
hWin = pWin->hParent;
}
}
/*******************************************************************
*
*
When drawing, we have to start at the bottom window !
*/
static void ResetNextDrawWin(void) {
NextDrawWin = WM_HWIN_NULL;
}
/*******************************************************************
*
* _AddChild
*/
void _AddChild(WM_HWIN hParent, WM_HWIN hChild, int OnTop) {
WM_Obj* pChild;
WM_Obj* pParent;
WM_Obj* pi;
WM_HWIN hi;
if (hParent) {
pParent = WM_H2P(hParent);
pChild = WM_H2P(hChild);
hi = pParent->hFirstChild;
if (hi == 0) { /* No child yet ... Makes things easy ! */
pParent->hFirstChild = hChild;
return; /* Early out ... We are done */
}
if (!OnTop) {
pi = WM_H2P(hi);
if (pi->Status & WM_SF_STAYONTOP) {
pChild->hNext = hi;
pParent->hFirstChild = hChild;
return; /* Early out ... We are done */
}
}
/* put if at the end of the list or after the last non "STAY-ON-TOP" child */
do {
WM_Obj* pNext;
WM_HWIN hNext;
pi = WM_H2P(hi);
if ((hNext = pi->hNext) == 0) {
pi->hNext = hChild;
break;
}
if (!OnTop) {
pNext = WM_H2P(hNext);
if (pNext->Status & WM_SF_STAYONTOP) {
pi->hNext = hChild;
pChild->hNext = hNext;
break;
}
}
hi = hNext;
} while (1);
}
}
/*******************************************************************
*
*
*/
static void _DeleteAllChildren(WM_HWIN hChild) {
while (hChild) {
WM_Obj* pChild = WM_H2P(hChild);
WM_HWIN hNext = pChild->hNext;
WM_DeleteWindow(hChild);
hChild = hNext;
}
}
/*******************************************************************
*
*
*/
static void _DeleteInSiblingList(WM_HWIN hWin) {
WM_Obj* pWin;
WM_Obj* pParent;
WM_Obj* pi;
WM_HWIN hParent;
WM_HWIN hi;
pWin = WM_H2P(hWin);
if (pWin->hParent) {
hParent = pWin->hParent;
pParent = WM_H2P(hParent);
hi = pParent->hFirstChild;
if (hi == hWin) {
pi = WM_H2P(hi);
pParent->hFirstChild = pi->hNext;
} else {
while (hi) {
pi = WM_H2P(hi);
if (pi->hNext == hWin) {
pi->hNext = pWin->hNext;
return;
}
hi = pi->hNext;
}
}
}
}
/*********************************************************************
*
* Module internal routines
*
**********************************************************************
*/
void WM__Client2Screen(const WM_Obj* pWin, GUI_RECT *pRect) {
GUI_MoveRect(pRect, pWin->Rect.x0, pWin->Rect.y0);
}
int WM__IsWindow(WM_HWIN hWin) {
WM_HWIN iWin;
int r = 0;
for (iWin = WM__FirstWin; iWin; iWin = WM_H2P(iWin)->hNextLin) {
if (iWin == hWin) {
r = 1;
break;
}
}
return r;
}
/*******************************************************************
*
*
*/
void WM__RemoveFromLinList(WM_HWIN hWin) {
WM_Obj* piWin;
WM_HWIN hiWin, hNext;
for (hiWin = WM__FirstWin; hiWin; ) {
piWin = WM_H2P(hiWin);
hNext = piWin->hNextLin;
if (hNext == hWin) {
piWin->hNextLin = WM_H2P(hWin)->hNextLin;
break;
}
hiWin = hNext;
}
}
/*******************************************************************
*
*
*/
void _AddToLinList(WM_HWIN hNew) {
WM_Obj* pFirst;
WM_Obj* pNew;
if (WM__FirstWin) {
pFirst = WM_H2P(WM__FirstWin);
pNew = WM_H2P(hNew);
pNew->hNextLin = pFirst->hNextLin;
pFirst->hNextLin = hNew;
} else {
WM__FirstWin = hNew;
}
}
/*********************************************************************
Check if the rectangle has some content (is non-zero)
Returns 0 if the Rectangle has no content, else 1.
*/
int WM__RectIsNZ(const GUI_RECT* pr) {
if (pr->x0 > pr->x1)
return 0;
if (pr->y0 > pr->y1)
return 0;
return 1;
}
/*
********************************************************************
* *
* Sending messages *
* *
********************************************************************
*/
void WM_SendMessage(WM_HWIN hWin, WM_MESSAGE* pMsg) {
WM_Obj* pWin;
WM_LOCK();
if (hWin) {
pWin = WM_H2P(hWin);
/* Do some checking to avoid program crashes due to user
programming errors */
#if GUI_DEBUG_LEVEL > 0
if (!pWin->Status)
goto Done;
#endif
if (pWin->cb != NULL) {
pMsg->hWin = hWin;
IsInCallback = 1;
(*pWin->cb)(pMsg);
IsInCallback = 0;
}
}
#if GUI_DEBUG_LEVEL > 0
Done:
#endif
WM_UNLOCK();
}
/*******************************************************************
*
*
*/
void WM__SendMsgNoData(WM_HWIN hWin, U8 MsgId) {
WM_MESSAGE Msg;
Msg.hWin = hWin;
Msg.MsgId = MsgId;
WM_SendMessage(hWin, &Msg);
}
/* Get client rectangle in windows coordinates. This means that the
upper left corner is always at (0,0). */
void WM__GetClientRectWin(const WM_Obj* pWin, GUI_RECT* pRect) {
pRect->x0 = pRect->y0 = 0;
pRect->x1 = pWin->Rect.x1 - pWin->Rect.x0;
pRect->y1 = pWin->Rect.y1 - pWin->Rect.y0;
}
static void WM__GetInvalidRectAbs(WM_Obj* pWin, GUI_RECT* pRect) {
*pRect = pWin->InvalidRect;
GUI_MoveRect (pRect, pWin->Rect.x0, pWin->Rect.y0);
}
/*
*****************************************************************
* *
* Invalidation functions *
* *
*****************************************************************
*/
/* Invalidate, using window coordinates */
static void WM_InvalidateBWin1(WM_HWIN hWin, const GUI_RECT*pRect) {
GUI_RECT r;
WM_Obj* pWin = WM_H2P(hWin);
WM__GetClientRectWin(pWin, &r);
if (pRect)
GUI__IntersectRect(&r, pRect);
if (WM__RectIsNZ(&r)) {
if (pWin->Status & WM_SF_INVALID) {
GUI_MergeRect(&pWin->InvalidRect, &pWin->InvalidRect, &r);
} else {
pWin->InvalidRect = r;
pWin->Status |= WM_SF_INVALID;
WM__NumInvalidWindows++;
/* Debug code: shows invalid areas */
#if (WM_SHOW_INVALID)
{
GUI_CONTEXT Context = GUI_Context;
WM_SelectWindow(hWin);
GUI_SetBkColor(GUI_GREEN);
GUI_ClearRect(r.x0, r.y0, r.x1, r.y1);
GUI_Context = Context;
}
#endif
}
}
}
/* Invalidate, using desktop coordinates (only this window,
not the ones below !!!)
*/
static void WM_InvalidateBWin1Abs(WM_HWIN hWin, const GUI_RECT*pRect) {
GUI_RECT r = *pRect;
WM_LOCK();
GUI_MoveRect(&r, -WM_H2P(hWin)->Rect.x0, -WM_H2P(hWin)->Rect.y0);
WM_InvalidateBWin1(hWin, &r);
WM_UNLOCK();
}
/*
Invalidate a certain section of the display. One main reason for this is
that a window has been moved or destroyed.
The following windows are affected:
* windows below the window creating the invalidation.
* transparent windows located above
The coordinates given are absolute coordinates (desktop coordinates)
*/
void WM__InvalidateAreaBelow(const GUI_RECT* pRect, WM_HWIN StopWin) {
WM_HWIN iWin, iNext;
GUI_USE_PARA(StopWin); /* tbd: change calls of this function */
/* Iterate over windows below StopWin */
for (iWin = WM__FirstWin; iWin/*!=StopWin*/; iWin = iNext) {
GUI_RECT r = *pRect;
WM_Obj* pWin = WM_H2P(iWin);
iNext = pWin->hNextLin;
if (GUI__IntersectRects(&r, &r, &pWin->Rect)) {
WM_InvalidateBWin1Abs (iWin, &r);
}
};
}
/*
Invalidate any transparent window above the given area
*/
void WM__InvalidateTransAreaAbove(const GUI_RECT* pRect, WM_HWIN StopWin) {
GUI_USE_PARA(pRect);
GUI_USE_PARA(StopWin);
#if 0
WM_HWIN iWin;
/* Iterate over windows below StopWin */
for (iWin = StopWin; iWin!=WM_HWIN_NULL; iWin = WM_H2P(iWin)->Next) {
WM_Obj *pWin = WM_H2P(iWin);
if (pWin->Status & WM_SF_HASTRANS) {
GUI_RECT r = *pRect;
if (GUI__IntersectRects(&r, &r, &WM_H2P(iWin)->Rect)) {
WM_InvalidateBWin1Abs (iWin, &r);
}
}
}
#endif
}
/*
*****************************************************************
* *
* Invalidation functions *
* *
*****************************************************************
*/
/* Invalidate a section of the window. The optional rectangle
contains client coordinates, which are independent of the
position of the window on the logical desktop area.
*/
void WM_InvalidateRect(WM_HWIN hWin, const GUI_RECT*pRect) {
GUI_RECT r;
WM_Obj* pWin;
WM_LOCK();
pWin = WM_H2P(hWin);
WM__GetClientRectWin(pWin, &r);
if (pRect) {
GUI__IntersectRect(&r, pRect);
}
WM_InvalidateBWin1(hWin, &r);
/* Convert into absolute coordinates ... */
GUI_MoveRect (&r, pWin->Rect.x0, pWin->Rect.y0);
/* Make sure windows below are invalidated if this one is transparent */
if (pWin->Status & WM_SF_HASTRANS) {
ResetNextDrawWin();
WM__InvalidateAreaBelow(&r, hWin);
}
/* Invalidate the transparent ones above */
WM__InvalidateTransAreaAbove(&r,hWin);
WM_UNLOCK();
}
void WM_InvalidateWindow(WM_HWIN hWin) {
WM_InvalidateRect(hWin, NULL);
}
/* Invalidate, using desktop coordinates */
void WM_InvalidateBWinAbs(WM_HWIN hWin, const GUI_RECT*pRect) {
GUI_RECT r = *pRect;
WM_LOCK();
GUI_MoveRect(&r, -WM_H2P(hWin)->Rect.x0, -WM_H2P(hWin)->Rect.y0);
WM_InvalidateRect(hWin, &r);
WM_UNLOCK();
}
/*
Invalidate a certain section of the display. One main reason for this is
that the top window has been moved or destroyed.
The coordinates given are absolute coordinates (desktop coordinates)
*/
void WM_InvalidateArea(GUI_RECT* pRect) {
WM_HWIN iWin;
WM_LOCK();
/* Iterate over all windows */
for (iWin=WM__FirstWin; iWin !=0; ) {
WM_Obj* pWin = WM_H2P(iWin);
GUI_RECT r = *pRect;
GUI__IntersectRect(&r, &pWin->Rect);
/* Calculate which area is actually visible by subtracting the
windows which are on top of this one */
WM_InvalidateBWinAbs (iWin, &r);
iWin = pWin->hNextLin;
}
WM_UNLOCK();
}
/*
********************************************************************
* *
* manage windows stack *
* *
********************************************************************
*/
/* Return index (handle) of the window which is bottom of stack.
Note that in the current implementation, this is always
window 0.
*/
WM_HWIN WM_GetDesktopWindow(void) {
return WM__FirstWin;
}
/*
********************************************************************
*
* Create window (as child)
*
********************************************************************
*/
WM_HWIN WM_CreateWindowAsChild(
int x0, int y0, int width, int height
,WM_HWIN hParent, U16 Style, WM_CALLBACK* cb
,int NumExtraBytes)
{
WM_Obj* pWin;
WM_HWIN hWin;
WM_LOCK();
Style |= WM__CreateFlags;
/* Get Parent info */
if (!hParent) {
if (WM__NumWindows) {
hParent = WM_HBKWIN;
}
}
if (hParent) {
GUI_RECT Rect;
// Rect = WM_H2P(hParent)->Rect;
WM_GetInsideRect(hParent, &Rect);
WM__Client2Screen(WM_H2P(hParent), &Rect);
x0 += Rect.x0;
y0 += Rect.y0;
if (width==0)
width = Rect.x1-Rect.x0+1;
if (height==0)
height = Rect.y1-Rect.y0+1;
}
if ((hWin = (WM_HWIN) WM_ALLOC(NumExtraBytes+sizeof(WM_Obj))) == 0) {
GUI_DEBUG_ERROROUT("WM_CreateWindow: No memory to create window");
} else {
WM__NumWindows++;
pWin = WM_H2P(hWin);
memset (pWin, 0, sizeof(WM_Obj)); /* erase this data structure
The explicit zero-init is no longer needed since the entire data structure
is already zeroed. The advantage is that it reduces program size.
*/
pWin->Rect.x0 = x0;
pWin->Rect.y0 = y0;
pWin->Rect.x1 = x0+width-1;
pWin->Rect.y1 = y0+height-1;
pWin->Status = WM_SF_INUSE; /* Mark window as in use */
pWin->cb = cb;
/* Add to linked lists */
pWin->hParent = hParent;
_AddChild(hParent, hWin, Style & WM_CF_STAYONTOP);
_AddToLinList(hWin);
/* Put Window on top (or bottom) of windows stack */
if (Style & WM_CF_ACTIVATE /*| (cb==NULL)*/) {
WM_SelectWindow(hWin); /* This is not needed
if callbacks are being used, but it
does not cost a lot and makes life
easier ... */
}
/* Mark client area as invalid */
WM__SendMsgNoData(hWin, WM_CREATE);
/* Handle the Style flags, one at a time */
if (Style & WM_CF_SHOW) {
WM_ShowWindow(hWin);
}
/* Hide if parent is not visible */
if (hParent) {
WM_Obj* pWinParent = WM_H2P(hParent);
if (!(pWinParent->Status & WM_SF_ISVIS)) {
WM_HideWindow(hWin);
}
}
/* Copy the flags which can simply be accepted */
pWin->Status |= (Style & (WM_SF_MEMDEV|WM_SF_STAYONTOP|WM_SF_HASTRANS));
}
WM_UNLOCK();
return hWin;
}
WM_HWIN WM_CreateWindow(int x0, int y0, int width, int height, U16 Style, WM_CALLBACK* cb, int NumExtraBytes) {
return WM_CreateWindowAsChild(x0,y0,width,height, 0 /* No parent */, Style, cb, NumExtraBytes);
}
/****************************************************************
*
* Delete window
*
*****************************************************************
*/
void WM_DeleteWindow (WM_HWIN Win) {
WM_Obj* pWin;
if (!Win)
return;
WM_LOCK();
if (WM__IsWindow(Win)) {
pWin = WM_H2P(Win);
ResetNextDrawWin(); /* Make sure the window will no longer receive drawing messages */
/* Make sure that focus is set to an existing window */
if (WM__hWinFocus == Win) {
WM__hWinFocus = 0;
}
if (Win == WM__hCapture) {
WM__hCapture = 0;
}
/* Delete all children */
_DeleteAllChildren(pWin->hFirstChild);
_DeleteInSiblingList(Win);
/* Send WM_DELETE message to window in order to inform window itself */
WM__SendMsgNoData(Win, WM_DELETE); /* tell window about it */
/* Inform other modules if necessary */
if (WM__pfDeleteWindowHook) {
(*WM__pfDeleteWindowHook)(Win);
}
/* Remove window from window stack */
if (pWin->Status & WM_SF_INVALID) {
WM__NumInvalidWindows--;
}
WM__RemoveFromLinList(Win);
/* Clear area used by this window */
WM_InvalidateArea(&pWin->Rect);
/* Free window memory */
WM__NumWindows--;
WM_FREE(Win);
/* Select a valid window */
WM_SelectWindow(WM__FirstWin);
} else {
GUI_DEBUG_WARN("WM_DeleteWindow: Invalid handle");
}
WM_UNLOCK();
}
void WM__SetMaxClipRect(const WM_Obj* pWin) {
WM_LOCK();
LCD_SetClipRectEx(&pWin->Rect);
WM_UNLOCK();
}
/****************************************************************
*
* WM_SelectWindow
*
*****************************************************************
Sets the active Window. The active Window is the one that is used for all
drawing (and text) operations.
*/
WM_HWIN WM_SelectWindow(WM_HWIN hWin) {
WM_HWIN hWinPrev;
WM_LOCK();
hWinPrev = GUI_Context.hAWin;
if (hWin == 0) {
hWin = WM__FirstWin;
}
if (!(WM_H2P(hWin)->Status & WM_SF_INUSE)) {
GUI_DEBUG_ERROROUT1("Selecting invalid window", hWin);
hWin=0;
}
/* Select new window */
GUI_Context.hAWin = hWin;
WM__SetMaxClipRect(WM_H2P(hWin));
WM_UNLOCK();
return hWinPrev;
}
WM_HWIN WM_GetActiveWindow(void) {
return GUI_Context.hAWin;
}
/*
********************************************************************
* *
* Show / hide window *
* *
********************************************************************
*/
void WM_ShowWindow (WM_HWIN hWin) {
WM_Obj *pWin;
WM_LOCK();
pWin = WM_H2P(hWin);
/* First check if this is necessary at all */
if ((pWin->Status&WM_SF_ISVIS)) {
WM_UNLOCK();
return;
}
/* Set Visibility flag */
pWin->Status |= WM_SF_ISVIS;
/* Mark content as invalid */
WM_InvalidateWindow(hWin);
WM_UNLOCK();
}
/*
*****************************************************************
* *
* GetOrg *
* *
*****************************************************************
These routines return the offset of the client area in absolute coordinates.
They are used to convert window coordinates into absolute coordinates and are
used in the clipping libraries (CL_).
*/
int WM__GetOrgX(void) {
return WM_H2P(GUI_Context.hAWin)->Rect.x0;
}
int WM__GetOrgY(void) {
return WM_H2P(GUI_Context.hAWin)->Rect.y0;
}
/*********************************************************************
*
* IVR calculation
IVRs are invalid rectangles. When redrawing, only the portion of the
window which is
a) within the window-rectangle
b) not covered by an other window
c) marked as invalid
is actually redrawn. Unfortunately, this section is not always
rectangular. If the window is partially covered by an other window,
it consists of the sum of multiple rectangles. In all drawing
operations, we have to iterate over every one of these rectangles in
order to make sure the window is drawn completly.
Function works as follows:
STEP 1: - Set upper left coordinates to next pixel. If end of line (right border), goto next line -> (r.x0, r.y0)
STEP 2: - Check if we are done, return if we are.
STEP 3: - If we are at the left border, find max. heigtht (r.y1) by iterating over windows above
STEP 4: - Find x0 for the given y0, y1 by iterating over windows above
STEP 5: - If r.x0 out of right border, this stripe is done. Set next stripe and goto STEP 2
STEP 6: - Find r.x1. We have to Iterate over all windows which are above
*/
#if WM_SUPPORT_OBSTRUCT
static int FindNext_IVR(void) {
int hParent;
int iWin;
GUI_RECT r;
U8 Status;
WM_Obj* pWin;
WM_Obj* pAWin;
WM_Obj* pParent;
r = ClipContext.CurRect; /* temps so we do not have to work with pointers too much */
/*
STEP 1:
Set the next position which could be part of the next IVR
This will be the first unhandle pixel in reading order, i.e. next one to the right
or next one down if we are at the right border.
*/
if (ClipContext.Cnt == 0) { /* First IVR starts in upper left */
r.x0 = ClipContext.ClientRect.x0;
r.y0 = ClipContext.ClientRect.y0;
} else {
r.x0 = ClipContext.CurRect.x1+1;
r.y0 = ClipContext.CurRect.y0;
if (r.x0 > ClipContext.ClientRect.x1) {
NextStripe: /* go down to next stripe */
r.x0 = ClipContext.ClientRect.x0;
r.y0 = ClipContext.CurRect.y1+1;
}
}
/*
STEP 2:
Check if we are done completely.
*/
if (r.y0 >ClipContext.ClientRect.y1)
return 0;
/* STEP 3:
Find out the max. height (r.y1) if we are at the left border.
Since we are using the same height for all IVRs at the same y0,
we do this only for the leftmost one.
*/
pAWin = WM_H2P(GUI_Context.hAWin);
if (r.x0 == ClipContext.ClientRect.x0) {
r.y1 = ClipContext.ClientRect.y1;
r.x1 = ClipContext.ClientRect.x1;
/* Iterate over all windows which are above */
/* Check all siblings above (Iterate over Parents and top siblings (hNext) */
for (hParent = GUI_Context.hAWin; hParent; hParent = pParent->hParent) {
pParent = WM_H2P(hParent);
for (iWin= pParent->hNext; iWin !=0; iWin = pWin->hNext) {
Status = (pWin = WM_H2P(iWin))->Status;
/* Check if this window affects us at all */
if ((Status & WM_SF_ISVIS) && (!(Status & WM_SF_HASTRANS)) && GUI_RectsIntersect(&r, &pWin->Rect)) {
if (pWin->Rect.y0 > r.y0) {
ASSIGN_IF_LESS(r.y1, pWin->Rect.y0-1); /* Check upper border of window */
} else {
ASSIGN_IF_LESS(r.y1, pWin->Rect.y1); /* Check lower border of window */
}
}
}
}
/* Check all children */
for (iWin= pAWin->hFirstChild; iWin !=0; iWin = pWin->hNext) {
Status = (pWin = WM_H2P(iWin))->Status;
/* Check if this window affects us at all */
if ((Status & WM_SF_ISVIS) && (!(Status & WM_SF_HASTRANS)) && GUI_RectsIntersect(&r, &pWin->Rect)) {
if (pWin->Rect.y0 > r.y0) {
ASSIGN_IF_LESS(r.y1, pWin->Rect.y0-1); /* Check upper border of window */
} else {
ASSIGN_IF_LESS(r.y1, pWin->Rect.y1); /* Check lower border of window */
}
}
}
}
/*
STEP 4
Find out x0 for the given y0, y1 by iterating over windows above.
if we find one that intersects, adjust x0 to the right.
*/
Find_x0:
r.x1 = r.x0;
/* Iterate over all windows which are above */
/* Check all siblings above */
for (hParent = GUI_Context.hAWin; hParent; hParent = pParent->hParent) {
pParent = WM_H2P(hParent);
for (iWin= pParent->hNext; iWin !=0; iWin = pWin->hNext) {
Status = (pWin = WM_H2P(iWin))->Status;
if ( (Status & WM_SF_ISVIS) && (!(Status & WM_SF_HASTRANS)) && GUI_RectsIntersect(&r, &pWin->Rect)) { /* Check if this window affects us at all */
r.x0 = pWin->Rect.x1+1;
goto Find_x0;
}
}
}
/* Check all children */
for (iWin= pAWin->hFirstChild; iWin !=0; iWin = pWin->hNext) {
Status = (pWin = WM_H2P(iWin))->Status;
if ( (Status & WM_SF_ISVIS) && (!(Status & WM_SF_HASTRANS)) && GUI_RectsIntersect(&r, &pWin->Rect)) { /* Check if this window affects us at all */
r.x0 = pWin->Rect.x1+1;
goto Find_x0;
}
}
/*
STEP 5:
If r.x0 out of right border, this stripe is done. Set next stripe and goto STEP 2
Find out x1 for the given x0, y0, y1
*/
r.x1 = ClipContext.ClientRect.x1;
if (r.x1 < r.x0) {/* horizontal border reached ? */
ClipContext.CurRect = r;
goto NextStripe;
}
/*
STEP 6:
Find r.x1. We have to Iterate over all windows which are above
*/
/* Check all siblings above (Iterate over Parents and top siblings (hNext) */
for (hParent = GUI_Context.hAWin; hParent; hParent = pParent->hParent) {
pParent = WM_H2P(hParent);
for (iWin= pParent->hNext; iWin !=0; iWin = pWin->hNext) {
Status = (pWin = WM_H2P(iWin))->Status;
if ( (Status & WM_SF_ISVIS) && (!(Status & WM_SF_HASTRANS)) && GUI_RectsIntersect(&r, &pWin->Rect)) { /* Check if this window affects us at all */
r.x1 = pWin->Rect.x0-1;
}
}
}
/* Check all children */
for (iWin= pAWin->hFirstChild; iWin !=0; iWin = pWin->hNext) {
Status = (pWin = WM_H2P(iWin))->Status;
if ( (Status & WM_SF_ISVIS) && (!(Status & WM_SF_HASTRANS)) && GUI_RectsIntersect(&r, &pWin->Rect)) { /* Check if this window affects us at all */
r.x1 = pWin->Rect.x0-1;
}
}
/* We are done. Return the rectangle we found in the ClipContext. */
if (ClipContext.Cnt >200) {
return 0; /* error !!! This should not happen !*/
}
ClipContext.CurRect = r;
return 1; /* IVR is valid ! */
}
#else
static int FindNext_IVR(void) {
if (ClipContext.Cnt ==0) {
ClipContext.CurRect = GUI_Context.pAWin->Rect;
return 1; /* IVR is valid ! */
}
return 0; /* Nothing left to draw */
}
#endif
/*********************************************************************
*
* Get next IVR
Sets the next clipping rectangle. If a valid one has
been found (and set), 1 is returned in order to indicate
that the drawing operation needs to be executed.
Returning 0 signals that we have iterated over all
rectangles.
Returns: 0 if no valid rectangle is found
1 if rectangle has been found
*/
int WM__GetNextIVR (void) {
#if GUI_SUPPORT_CURSOR
static char _CursorHidden;
#endif
/* If WM is not active, we have no rectangles to return */
if (WM_IsActive==0)
return 0;
if (ClipContext.EntranceCnt > 1) {
ClipContext.EntranceCnt--;
return 0;
}
#if GUI_SUPPORT_CURSOR
if (_CursorHidden) {
_CursorHidden = 0;
(*GUI_CURSOR_pfTempUnhide) ();
}
#endif
++ClipContext.Cnt;
/* Find next rectangle and use it as ClipRect */
if (!FindNext_IVR()) {
ClipContext.EntranceCnt--; /* This search is over ! */
return 0; /* Could not find an other one ! */
}
/* Hide cursor if necessary */
LCD_SetClipRectEx(&ClipContext.CurRect);
#if GUI_SUPPORT_CURSOR
if (GUI_CURSOR_pfTempHide) {
_CursorHidden = (*GUI_CURSOR_pfTempHide) ( &ClipContext.CurRect);
}
#endif
return 1;
}
/*********************************************************************
*
* Init IVR search
This routine is called from the clipping level
(the WM_ITERATE_START macro) when starting an iteration over the
visible rectangles.
Return value:
0 : There is no valid rectangle (nothing to do ...)
1 : There is a valid rectangle
*/
int WM__InitIVRSearch(const GUI_RECT* pMaxRect) {
GUI_RECT r;
WM_Obj* pAWin;
/* If WM is not active -> nothing to do, leave cliprect alone */
if (WM_IsActive==0)
return 1;
/* If we entered multiple times, leave Cliprect alone */
if (++ClipContext.EntranceCnt > 1)
return 1;
pAWin = WM_H2P(GUI_Context.hAWin);
ClipContext.Cnt = -1;
/* When using callback mechanism, it is legal to reduce drawing
area to the invalid area ! */
if (IsInCallback) {
WM__GetInvalidRectAbs(pAWin, &r);
} else { /* Not using callback mechanism, therefor allow entire rectangle */
if (pAWin->Status & WM_SF_ISVIS) {
r = pAWin->Rect;
} else {
--ClipContext.EntranceCnt;
return 0; /* window is not even visible ! */
}
}
/* If the drawing routine has specified a rectangle, use it to reduce the rectangle */
if (pMaxRect) {
GUI__IntersectRect(&r, pMaxRect);
}
/* If user has reduced the cliprect size, reduce the rectangle */
if (GUI_Context.WM__pUserClipRect) {
GUI_RECT rUser = *(GUI_Context.WM__pUserClipRect);
WM__Client2Screen(pAWin, &rUser);
GUI__IntersectRect(&r, &rUser);
}
/* Iterate over all ancestors and clip at their borders */
_ClipAtParentBorders(&r, pAWin);
/* Store the rectangle and find the first rectangle of the area */
ClipContext.ClientRect = r;
return WM__GetNextIVR();
}
/*
********************************************
* *
* Set default *
* *
********************************************
This routine sets the defaults for WM and the layers below.
It is used before a drawing routine is called in order to
make sure that defaults are set (in case the default settings
had been altered before by the application)
*/
void WM_SetDefault(void) {
GL_SetDefault();
GUI_Context.WM__pUserClipRect = NULL; /* No add. clipping */
}
/*
********************************************
*
* Callback for Paint message
*
********************************************
This callback is used by the window manger in conjunction with banding
memory devices. A pointer to this routine is given to the banding memory device.
This callback in turn will send the paint message to the window.
*/
#if GUI_SUPPORT_MEMDEV
static void cbPaint(void* pMsg) {
WM_SendMessage(((WM_MESSAGE*)pMsg)->hWin, (WM_MESSAGE*) pMsg);
}
#endif
/*
********************************************
* *
* Draw next window *
* *
********************************************
*/
static void _DrawNext(void) {
int UpdateRem = 1;
WM_HWIN iWin = (NextDrawWin == WM_HWIN_NULL) ? WM__FirstWin : NextDrawWin;
GUI_CONTEXT ContextOld;
GUI_SaveContext(&ContextOld);
/* Make sure the next window to redraw is valid */
for (; (iWin!=WM_HWIN_NULL) && UpdateRem; ) {
WM_Obj* pWin = WM_H2P(iWin);
if (pWin->Status & WM_SF_INVALID) {
U8 Status = (pWin->Status &= ~WM_SF_INVALID); /* Clear invalid flag */
WM__NumInvalidWindows--;
/* Send WM_PAINT if window is visible and a callback is defined */
if ((pWin->cb != NULL) && (Status & WM_SF_ISVIS)) {
WM_MESSAGE Msg;
Msg.hWin = iWin;
Msg.MsgId = WM_PAINT;
Msg.Data.p = (GUI_RECT*)&pWin->InvalidRect;
WM_SelectWindow(iWin);
WM_SetDefault();
#if GUI_SUPPORT_MEMDEV
if (Status & WM_SF_MEMDEV) {
GUI_RECT r = pWin->InvalidRect;
GUI_MoveRect (&r, pWin->Rect.x0, pWin->Rect.y0);
GUI_MEMDEV_Draw(&r, cbPaint, &Msg, 0, (Status & WM_SF_HASTRANS) ? GUI_MEMDEV_HASTRANS : 0);
} else
#endif
WM_SendMessage(iWin, &Msg);
UpdateRem--; /* Only the given number of windows at a time ... */
}
}
iWin = pWin->hNextLin;
}
NextDrawWin = iWin; /* Remember the window */
GUI_RestoreContext(&ContextOld);
}
/*
*****************************************************************
* *
* Idle loop *
* *
*****************************************************************
*/
int WM_Exec1(void) {
/* Poll PID if necessary */
if (WM_pfPollPID) {
WM_pfPollPID();
}
if (WM_pfHandlePID) {
if (WM_pfHandlePID())
return 1; /* We have done something ... */
}
if (GUI_PollKeyMsg()) {
return 1; /* We have done something ... */
}
if (WM_IsActive && WM__NumInvalidWindows) {
WM_LOCK();
_DrawNext();
WM_UNLOCK();
return 1; /* We have done something ... */
}
return 0; /* There was nothing to do ... */
}
int WM_Exec(void) {
int r = 0;
while (WM_Exec1()) {
r = 1; /* We have done something */
}
return r;
}
/****************************************************************
* *
* Callback for background window *
* *
*****************************************************************
*/
static WM_RESULT cbBackWin( WM_MESSAGE* pMsg) {
WM_KEY_INFO* pKeyInfo;
switch (pMsg->MsgId) {
case WM_KEY:
pKeyInfo = (WM_KEY_INFO*)pMsg->Data.p;
if (pKeyInfo->PressedCnt == 0) {
GUI_StoreKey(pKeyInfo->Key);
}
break;
case WM_PAINT:
if (WM__BkColor != GUI_INVALID_COLOR) {
GUI_SetBkColor(WM__BkColor);
GUI_Clear();
}
default:
WM_DefaultProc(pMsg);
}
}
/****************************************************************
*
* WM_Activate / WM_Deactivate
*
*****************************************************************
*/
void WM_Activate(void) {
WM_IsActive = 1; /* Running */
}
void WM_Deactivate(void) {
WM_IsActive = 0; /* No clipping performed by WM */
WM__SetMaxClipRect(WM_H2P(WM_HBKWIN));
}
/*
*****************************************************************
* *
* WM_Init *
* *
*****************************************************************
*/
void WM_Init(void) {
if (!_IsInited) {
WM_HWIN hWin;
NextDrawWin = WM__FirstWin = WM_HWIN_NULL;
GUI_Context.WM__pUserClipRect = NULL;
WM__NumWindows = WM__NumInvalidWindows =0;
/* Make sure we have at least one window. This greatly simplifies the
drawing routines as they do not have to check if the window is valid.
*/
hWin = WM_CreateWindow(0, 0, GUI_XMAX, GUI_YMAX, WM_CF_SHOW, cbBackWin, 0);
WM_SelectWindow(hWin);
WM_Activate();
_IsInited =1;
}
}
/*
******************************************************
* *
* Default procedure *
* *
******************************************************
*/
WM_RESULT WM_DefaultProc(WM_MESSAGE* pMsg) {
WM_HWIN hWin = pMsg->hWin;
void *p = pMsg->Data.p;
WM_Obj* pWin = WM_H2P(hWin);
/* Exec message */
switch (pMsg->MsgId) {
case WM_GETCLIENTRECT: /* return client window in window coordinates */
WM__GetClientRectWin(pWin, (GUI_RECT*)p);
break;
case WM_GETORG:
((GUI_POINT*)p)->x = pWin->Rect.x0;
((GUI_POINT*)p)->y = pWin->Rect.y0;
break;
case WM_GET_INSIDE_RECT: /* return client window in absolute (screen) coordinates */
WM__GetClientRectWin(pWin, (GUI_RECT*)p);
break;
case WM_GET_CLIENT_WINDOW: /* return handle to client window. For most windows, there is no seperate client window, so it is the same handle */
pMsg->Data.v = hWin;
return; /* Message handled */
case WM_KEY:
WM_SendToParent(hWin, pMsg);
return; /* Message handled */
case WM_GET_BKCOLOR:
pMsg->Data.Color = GUI_INVALID_COLOR;
return; /* Message handled */
}
/* Message not handled. If it queries something, we return 0 to be on the safe side. */
pMsg->Data.v = 0;
pMsg->Data.p = 0;
}
#else
void WM(void) {} /* avoid empty object files */
#endif /* WM_MAX_WINDOW */