📄 wm.c
字号:
/*
*********************************************************************************************************
* uC/GUI
* Universal graphic software for embedded applications
*
* (c) Copyright 2002, Micrium Inc., Weston, FL
* (c) Copyright 2002, SEGGER Microcontroller Systeme GmbH
*
* 礐/GUI is protected by international copyright laws. Knowledge of the
* source code may not be used to write a similar product. This file may
* only be used in accordance with a license and should not be redistributed
* in any way. We appreciate your understanding and fairness.
*
----------------------------------------------------------------------
File : WM.C
Purpose : Windows manager core
----------------------------------------------------------------------
*/
#include <stddef.h> /* needed for definition of NULL */
#include <string.h> /* required for memset */
#define WM_C
#include "WM_Intern_ConfDep.h"
#if GUI_WINSUPPORT /* If 0, WM will not generate any code */
/*********************************************************************
*
* Macros for internal use
*
**********************************************************************
*/
#define ASSIGN_IF_LESS(v0,v1) if (v1<v0) v0=v1
/*********************************************************************
*
* Local typedefs
*
**********************************************************************
*/
typedef struct {
GUI_RECT ClientRect;
GUI_RECT CurRect;
int Cnt;
int EntranceCnt;
} WM_IVR_CONTEXT;
/*********************************************************************
*
* global data
*
**********************************************************************
*/
U8 WM_IsActive;
U16 WM__CreateFlags;
WM_HWIN WM__hCapture;
WM_HWIN WM__hWinFocus;
char WM__CaptureReleaseAuto;
WM_tfPollPID* WM_pfPollPID;
U8 WM__PaintCallbackCnt; /* Public for assertions only */
GUI_PID_STATE WM_PID__StateLast;
#if WM_SUPPORT_TRANSPARENCY
int WM__TransWindowCnt;
WM_HWIN WM__hATransWindow;
#endif
#if WM_SUPPORT_DIAG
void (*WM__pfShowInvalid)(WM_HWIN hWin);
#endif
/*********************************************************************
*
* static data
*
**********************************************************************
*/
static WM_HWIN NextDrawWin;
static WM_IVR_CONTEXT _ClipContext;
static char _IsInited;
/*********************************************************************
*
* Static routines
*
**********************************************************************
*/
/*********************************************************************
*
* _CheckCriticalHandles
*
* Purpose:
* Checks the critical handles and resets the matching one
*/
static void _CheckCriticalHandles(WM_HWIN hWin) {
WM_CRITICAL_HANDLE * pCH;
for (pCH = WM__pFirstCriticalHandle; pCH; pCH = pCH->pNext) {
if (pCH->hWin == hWin) {
pCH->hWin = 0;
}
}
}
/*********************************************************************
*
* _DesktopHandle2Index
*
* Function:
* Convert the given desktop window into the display index.
*
* Return value:
* Desktop index if window handle is valid.
* else: -1
*/
static int _DesktopHandle2Index(WM_HWIN hDesktop) {
#if GUI_NUM_LAYERS > 1
int i;
for (i = 0; i < GUI_NUM_LAYERS; i++) {
if (hDesktop == WM__ahDesktopWin[i]) {
return i;
}
}
#else
if (hDesktop == WM__ahDesktopWin[0]) {
return 0;
}
#endif
return -1;
}
/*********************************************************************
*
* _Invalidate1Abs
*
* Invalidate given window, using absolute coordinates
*/
static void _Invalidate1Abs(WM_HWIN hWin, const GUI_RECT*pRect) {
GUI_RECT r;
WM_Obj* pWin;
int Status;
pWin = WM_H2P(hWin);
Status = pWin->Status;
if ((Status & WM_SF_ISVIS) == 0) {
return; /* Window is not visible... we are done */
}
if ((Status & (WM_SF_HASTRANS | WM_SF_CONST_OUTLINE)) == WM_SF_HASTRANS) {
return; /* Window is transparent; transparency may change... we are done, since background will be invalidated */
}
if (WM__RectIsNZ(pRect) == 0) {
return; /* Nothing to do ... */
}
/* Calc affected area */
GUI__IntersectRects(&r, pRect, &pWin->Rect);
if (WM__RectIsNZ(&r)) {
#if WM_SUPPORT_NOTIFY_VIS_CHANGED
WM__SendMsgNoData(hWin, WM_NOTIFY_VIS_CHANGED); /* Notify window that visibility may have changed */
#endif
if (pWin->Status & WM_SF_INVALID) {
GUI_MergeRect(&pWin->InvalidRect, &pWin->InvalidRect, &r);
} else {
pWin->InvalidRect = r;
pWin->Status |= WM_SF_INVALID;
WM__NumInvalidWindows++;
/* Optional code: Call external routine to notify that drawing is required */
#ifdef GUI_X_REDRAW
{
GUI_RECT r;
r = pWin->Rect;
if (WM__ClipAtParentBorders(&r, hWin)) {
GUI_X_REDRAW(); /* Call hook function to signal an invalidation */
}
}
#endif
GUI_X_SIGNAL_EVENT();
}
/* Debug code: shows invalid areas */
#if (WM_SUPPORT_DIAG)
if (WM__pfShowInvalid) {
(WM__pfShowInvalid)(hWin);
}
#endif
}
}
/*********************************************************************
*
* _GetTopLevelWindow
*/
#if GUI_NUM_LAYERS > 1
static WM_HWIN _GetTopLevelWindow(WM_HWIN hWin) {
WM_Obj* pWin;
WM_HWIN hTop;
while (hTop = hWin, pWin = WM_H2P(hWin), (hWin = pWin->hParent) != 0) {
}
return hTop;
}
#endif
/*********************************************************************
*
* ResetNextDrawWin
When drawing, we have to start at the bottom window !
*/
static void ResetNextDrawWin(void) {
NextDrawWin = WM_HWIN_NULL;
}
/*********************************************************************
*
* _GethDrawWin
*
* Return Window being drawn.
* Normally same as pAWin, except if overlaying transparent window is drawn
*
*/
static WM_HWIN _GethDrawWin(void) {
WM_HWIN h;
#if WM_SUPPORT_TRANSPARENCY
if (WM__hATransWindow) {
h = WM__hATransWindow;
} else
#endif
{
h = GUI_Context.hAWin;
}
return h;
}
/*********************************************************************
*
* _SetClipRectUserIntersect
*/
static void _SetClipRectUserIntersect(const GUI_RECT* prSrc) {
if (GUI_Context.WM__pUserClipRect == NULL) {
LCD_SetClipRectEx(prSrc);
} else {
GUI_RECT r;
r = *GUI_Context.WM__pUserClipRect;
WM__Client2Screen(WM_H2P(_GethDrawWin()), &r); /* Convert User ClipRect into screen coordinates */
/* Set intersection as clip rect */
GUI__IntersectRect(&r, prSrc);
LCD_SetClipRectEx(&r);
}
}
/*********************************************************************
*
* Public routines
*
**********************************************************************
*/
/*********************************************************************
*
* WM__ClipAtParentBorders
*
* Function:
* Iterates over the window itself and all its ancestors.
* Intersects all rectangles to
* find out which part is actually visible.
* Reduces the rectangle to the visible area.
* This routines takes into account both the rectangles of the
* ancestors as well as the WM_SF_ISVIS flag.
*
* Parameters
* hWin Obvious
* pRect Pointer to the rectangle to be clipped. May not be NULL.
* The parameter is IN/OUT.
* Note that the rectangle is clipped only if the return
* value indicates a valid rectangle remains.
*
* Return value:
* 1: Something is or may be visible.
* 0: Nothing is visible (outside of ancestors, no desktop, hidden)
*/
int WM__ClipAtParentBorders(GUI_RECT* pRect, WM_HWIN hWin) {
WM_Obj* pWin;
/* Iterate up the window hierarchy.
If the window is invisible, we are done.
Clip at parent boarders.
We are done with iterating if hWin has no parent.
*/
do {
pWin = WM_H2P(hWin);
if ((pWin->Status & WM_SF_ISVIS) == 0) {
return 0; /* Invisible */
}
GUI__IntersectRect(pRect, &pWin->Rect); /* And clip on borders */
if (pWin->hParent == 0) {
break; /* hWin is now the top level window which has no parent */
}
hWin = pWin->hParent; /* Go one level up (parent)*/
} while (1); /* Only way out is in the loop. Required for efficiency, no bug, even though some compilers may complain. */
/* Now check if the top level window is a desktop window. If it is not,
then the window is not visible.
*/
if (_DesktopHandle2Index(hWin) < 0) {
return 0; /* No desktop - (unattached) - Nothing to draw */
}
return 1; /* Something may be visible */
}
/*********************************************************************
*
* WM__ActivateClipRect
*/
void WM__ActivateClipRect(void) {
if (WM_IsActive) {
_SetClipRectUserIntersect(&_ClipContext.CurRect);
} else { /* Window manager disabled, typically because meory device is active */
GUI_RECT r;
WM_Obj *pAWin;
pAWin = WM_H2P(GUI_Context.hAWin);
r = pAWin->Rect;
#if WM_SUPPORT_TRANSPARENCY
if (WM__hATransWindow) {
WM__ClipAtParentBorders(&r, WM__hATransWindow);
}
#endif
/* Take UserClipRect into account */
_SetClipRectUserIntersect(&r);
}
}
/*********************************************************************
*
* WM__InsertWindowIntoList
*
* Routine describtion
* This routine inserts the window in the list of child windows for
* a particular parent window.
* The window is placed on top of all siblings with the same level.
*/
void WM__InsertWindowIntoList(WM_HWIN hWin, WM_HWIN hParent) {
int OnTop;
WM_HWIN hi;
WM_Obj * pWin;
WM_Obj * pParent;
WM_Obj * pi;
if (hParent) {
pWin = WM_H2P(hWin);
pWin->hNext = 0;
pWin->hParent = hParent;
pParent = WM_H2P(hParent);
OnTop = pWin->Status & WM_CF_STAYONTOP;
hi = pParent->hFirstChild;
/* Put it at beginning of the list if there is no child */
if (hi == 0) { /* No child yet ... Makes things easy ! */
pParent->hFirstChild = hWin;
return; /* Early out ... We are done */
}
/* Put it at beginning of the list if first child is a TOP window and new one is not */
pi = WM_H2P(hi);
if (!OnTop) {
if (pi->Status & WM_SF_STAYONTOP) {
pWin->hNext = hi;
pParent->hFirstChild = hWin;
return; /* Early out ... We are done */
}
}
/* Put it at the end of the list or before the last non "STAY-ON-TOP" child */
do {
WM_Obj* pNext;
WM_HWIN hNext;
if ((hNext = pi->hNext) == 0) { /* End of sibling list ? */
pi->hNext = hWin; /* Then modify this last element to point to new one and we are done */
break;
}
pNext = WM_H2P(hNext);
if (!OnTop) {
if (pNext->Status & WM_SF_STAYONTOP) {
pi->hNext = hWin;
pWin->hNext = hNext;
break;
}
}
pi = pNext;
} while (1);
#if WM_SUPPORT_NOTIFY_VIS_CHANGED
WM__NotifyVisChanged(hWin, &pWin->Rect);
#endif
}
}
/*********************************************************************
*
* WM__RemoveWindowFromList
*/
void WM__RemoveWindowFromList(WM_HWIN hWin) {
WM_HWIN hi, hParent;
WM_Obj * pWin, * pParent, * pi;
pWin = WM_H2P(hWin);
hParent = pWin->hParent;
if (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;
break;
}
hi = pi->hNext;
}
}
}
}
/*********************************************************************
*
* WM__DetachWindow
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -