Files
MiniGUI/src/kernel/desktop.c
2023-09-01 08:35:32 +08:00

4754 lines
128 KiB
C

///////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT NOTICE
//
// The following open source license statement does not apply to any
// entity in the Exception List published by FMSoft.
//
// For more information, please visit:
//
// https://www.fmsoft.cn/exception-list
//
//////////////////////////////////////////////////////////////////////////////
/*
* This file is part of MiniGUI, a mature cross-platform windowing
* and Graphics User Interface (GUI) support system for embedded systems
* and smart IoT devices.
*
* Copyright (C) 2002~2022, Beijing FMSoft Technologies Co., Ltd.
* Copyright (C) 1998~2002, WEI Yongming
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Or,
*
* As this program is a library, any link to this program must follow
* GNU General Public License version 3 (GPLv3). If you cannot accept
* GPLv3, you need to be licensed from FMSoft.
*
* If you have got a commercial license of this program, please use it
* under the terms and conditions of the commercial license.
*
* For more information about the commercial license, please refer to
* <http://www.minigui.com/blog/minigui-licensing-policy/>.
*/
/*
** desktop.c: The Desktop module.
**
** Current maintainer: Wei Yongming
**
*/
#include "license.h"
#ifdef _MG_ENABLE_LICENSE
# include "../sysres/license/c_files/00_minigui.dat.c"
#endif
ZORDERINFO* __mg_def_zorder_info;
ZORDERINFO* __mg_zorder_info;
/* pointer to desktop window */
PMAINWIN __mg_dsk_win;
/* handle to desktop window */
HWND __mg_hwnd_desktop;
/* the capture window */
HWND __mg_captured_wnd;
/* handle to the ime window - server only. */
HWND __mg_ime_wnd;
IME_STATUS_INFO __mg_ime_status_info;
/* default window procedures */
#ifdef _MGHAVE_VIRTUAL_WINDOW
WNDPROC __mg_def_proc[4];
#else
WNDPROC __mg_def_proc[3];
#endif
static BLOCKHEAP sg_FreeInvRectList;
#ifndef _MGSCHEMA_COMPOSITING
static BLOCKHEAP sg_FreeClipRectList;
static GCRINFO sg_ScrGCRInfo;
static CLIPRGN sg_UpdateRgn;
#else /* defined _MGSCHEMA_COMPOSITING */
#define DO_COMPSOR_OP(op) \
do { \
CompositorCtxt* ctxt; \
const CompositorOps* ops = ServerSelectCompositor (NULL, &ctxt); \
if (ops && ops->op) { \
ops->op(ctxt); \
} \
} while (0)
#define DO_COMPSOR_OP_ARGS(op, ...) \
do { \
CompositorCtxt* ctxt; \
const CompositorOps* ops = ServerSelectCompositor (NULL, &ctxt); \
if (ops && ops->op) { \
ops->op(ctxt, __VA_ARGS__); \
} \
} while (0)
#endif /* defined _MGSCHEMA_COMPOSITING */
#define ZT_TOOLTIP 0x00000080
#define ZT_GLOBAL 0x00000040
#define ZT_SCREENLOCK 0x00000020
#define ZT_DOCKER 0x00000010
#define ZT_HIGHER 0x00000008
#define ZT_NORMAL 0x00000004
#define ZT_LAUNCHER 0x00000002
#define ZT_ALL 0x000000FF
static const int _zts_for_level [] = {
ZT_TOOLTIP, ZT_GLOBAL, ZT_SCREENLOCK, ZT_DOCKER,
ZT_HIGHER, ZT_NORMAL, ZT_LAUNCHER };
static const int _zof_types_for_level [] = {
ZOF_TYPE_TOOLTIP, ZOF_TYPE_GLOBAL, ZOF_TYPE_SCREENLOCK, ZOF_TYPE_DOCKER,
ZOF_TYPE_HIGHER, ZOF_TYPE_NORMAL, ZOF_TYPE_LAUNCHER };
typedef BOOL (* CB_ONE_ZNODE) (void* context,
const ZORDERINFO* zi, ZORDERNODE* node);
#if 0 /* deprecated code */
PGCRINFO kernel_GetGCRgnInfo (HWND hWnd)
{
return ((PMAINWIN)hWnd)->pGCRInfo;
}
#endif /* deprecated code */
typedef struct _DEF_CONTEXT
{
PBITMAP bg;
int x, y;
} DEF_CONTEXT;
#if defined(_MGRM_PROCESSES)
static DEF_CONTEXT g_def_context;
#endif
static inline ZORDERINFO* get_zorder_info (int cli)
{
#if defined (_MGRM_THREADS) || defined (_MGRM_STANDALONE)
return __mg_zorder_info;
#else
return get_zi_from_client (cli);
#endif
}
#ifndef _MGSCHEMA_COMPOSITING
static BOOL subtract_rgn_by_node (PCLIPRGN region, const ZORDERINFO* zi,
const ZORDERNODE* node)
{
if (node->idx_mask_rect != 0) {
MASKRECT *firstmaskrect=NULL, *maskrect;
int idx, x, y;
RECT tmprc={0};
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
idx = node->idx_mask_rect;
/* clip all mask rect */
while(idx) {
maskrect = firstmaskrect + idx;
x = maskrect->left;
y = maskrect->top;
/* convert to screen coordinate*/
x = x + node->rc.left;
y = y + node->rc.top;
SetRect(&tmprc, x, y,
x+maskrect->right - maskrect->left,
y+maskrect->bottom - maskrect->top);
IntersectRect(&tmprc, &tmprc, &(node->rc));
SubtractClipRect(region, &tmprc);
idx = maskrect->next;
}
}
else
SubtractClipRect(region, &(node->rc));
return TRUE; // !IsEmptyClipRgn(region); We must return TRUE for this callback.
}
#else /* not defined _MGSCHEMA_COMPOSITING */
static int get_znode_mask_bound (int cli, int idx_znode, RECT* rc_bound)
{
ZORDERINFO* zi;
ZORDERNODE* nodes, *node;
zi = get_zorder_info (cli);
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
node = nodes + idx_znode;
if (node->idx_mask_rect != 0) {
MASKRECT *firstmaskrect = NULL, *maskrect;
int idx;
RECT rc;
SetRect (rc_bound, 0, 0, 0, 0);
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
idx = node->idx_mask_rect;
while (idx) {
maskrect = firstmaskrect + idx;
rc.left = maskrect->left + node->rc.left;
rc.top = maskrect->top + node->rc.top;
rc.right = rc.left + (maskrect->right - maskrect->left);
rc.bottom = rc.top + (maskrect->bottom - maskrect->top);
IntersectRect (&rc, &rc, &(node->rc));
UnionRect (rc_bound, rc_bound, &rc);
idx = maskrect->next;
}
}
else
*rc_bound = node->rc;
return 0;
}
#endif /* defined _MGSCHEMA_COMPOSITING */
/* TODO: check round corners here */
static int pt_in_maskrect (const ZORDERINFO* zi,
const ZORDERNODE* nodes, int x, int y)
{
int cx, cy;
RECT tmprc;
MASKRECT *maskrect, *firstmaskrect;
int idx = nodes->idx_mask_rect;
if (idx != 0 && PtInRect (&(nodes->rc), x, y)) {
cx = x - nodes->rc.left;
cy = y - nodes->rc.top;
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
while(idx != 0) {
maskrect = firstmaskrect + idx;
SetRect (&tmprc, maskrect->left, maskrect->top,
maskrect->right, maskrect->bottom);
if (PtInRect (&tmprc, cx, cy))
return TRUE;
idx = maskrect->next;
}
return FALSE;
}
else {
return PtInRect(&(nodes->rc), x, y);
}
}
static int get_znode_at_point (const ZORDERINFO* zi,
const ZORDERNODE* nodes, int x, int y)
{
int level;
int slot = 0;
/* Since 5.0.0 */
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
slot = zi->first_in_levels[level];
for (; slot > 0; slot = nodes[slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
pt_in_maskrect (zi, &nodes[slot], x, y))
goto ret;
}
}
ret:
return slot;
}
static void unchain_znode (unsigned char* usage_bmp,
ZORDERNODE* nodes, int idx_znode)
{
if (nodes [idx_znode].prev) {
nodes [nodes [idx_znode].prev].next = nodes [idx_znode].next;
}
if (nodes [idx_znode].next) {
nodes [nodes [idx_znode].next].prev = nodes [idx_znode].prev;
}
__mg_slot_clear_use (usage_bmp, idx_znode);
nodes [idx_znode].flags = 0;
}
static void release_znode_maskrect (ZORDERNODE* nodes, int idx_znode)
{
int idx, tmp;
MASKRECT *first;
first = GET_MASKRECT(__mg_def_zorder_info);
idx = nodes [idx_znode].idx_mask_rect;
while (idx) {
__mg_slot_clear_use(GET_MASKRECT_USAGEBMP(__mg_def_zorder_info), idx);
(first+idx)->prev = 0;
tmp = (first+idx)->next;
(first+idx)->next = 0;
idx = tmp;
}
nodes[idx_znode].idx_mask_rect = 0;
}
static int do_for_all_znodes (void* context, const ZORDERINFO* zi,
CB_ONE_ZNODE cb, DWORD types)
{
int slot;
int count = 0;
int level;
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
if (types & _zts_for_level[level]) {
slot = zi->first_in_levels[level];
for (; slot > 0; slot = nodes[slot].next) {
if (cb (context, zi, nodes + slot))
count ++;
}
}
}
return count;
}
static void dskScreenToClient (PMAINWIN pWin,
const RECT* rcScreen, RECT* rcClient)
{
PCONTROL pParent;
rcClient->top = rcScreen->top - pWin->ct;
rcClient->left = rcScreen->left - pWin->cl;
rcClient->right = rcScreen->right - pWin->cl;
rcClient->bottom = rcScreen->bottom - pWin->ct;
pParent = (PCONTROL) pWin;
while ((pParent = pParent->pParent)) {
rcClient->top -= pParent->ct;
rcClient->left -= pParent->cl;
rcClient->right -= pParent->cl;
rcClient->bottom -= pParent->ct;
}
}
static void dskScreenToWindow (PMAINWIN pWin,
const RECT* rcScreen, RECT* rcWindow)
{
PCONTROL pParent;
rcWindow->top = rcScreen->top - pWin->top;
rcWindow->left = rcScreen->left - pWin->left;
rcWindow->right = rcScreen->right - pWin->left;
rcWindow->bottom = rcScreen->bottom - pWin->top;
pParent = (PCONTROL) pWin;
while ((pParent = pParent->pParent)) {
rcWindow->top -= pParent->ct;
rcWindow->left -= pParent->cl;
rcWindow->right -= pParent->cl;
rcWindow->bottom -= pParent->ct;
}
}
static void dskClientToScreen (PMAINWIN pWin,
const RECT* rcClient, RECT* rcScreen)
{
PCONTROL pParent;
rcScreen->top = rcClient->top + pWin->ct;
rcScreen->left = rcClient->left + pWin->cl;
rcScreen->right = rcClient->right + pWin->cl;
rcScreen->bottom = rcClient->bottom + pWin->ct;
pParent = (PCONTROL) pWin;
while ((pParent = pParent->pParent)) {
rcScreen->top += pParent->ct;
rcScreen->left += pParent->cl;
rcScreen->right += pParent->cl;
rcScreen->bottom += pParent->ct;
}
}
static void dskGetWindowRectInScreen (PMAINWIN pWin, RECT* prc)
{
PCONTROL pParent;
PCONTROL pCtrl;
pParent = pCtrl = (PCONTROL)pWin;
prc->left = pCtrl->left;
prc->top = pCtrl->top;
prc->right = pCtrl->right;
prc->bottom = pCtrl->bottom;
while ((pParent = pParent->pParent)) {
prc->left += pParent->cl;
prc->top += pParent->ct;
prc->right += pParent->cl;
prc->bottom += pParent->ct;
}
}
void __mg_update_window (HWND hwnd,
int left, int top, int right, int bottom)
{
PMAINWIN pWin = (PMAINWIN)hwnd;
if (pWin &&
((pWin->WinType == TYPE_CONTROL &&
(pWin->dwExStyle & WS_EX_CTRLASMAINWIN)) ||
pWin->WinType != TYPE_CONTROL) && pWin->dwStyle & WS_VISIBLE) {
RECT rcInv;
SetRect(&rcInv, left, top, right, bottom);
_DBG_PRINTF ("Update window (%s): %d, %d, %d, %d\n",
pWin->spCaption, left, top, right, bottom);
if (IsRectEmpty (&rcInv)) {
SendAsyncMessage ((HWND)pWin, MSG_NCPAINT, 0, 0);
InvalidateRect ((HWND)pWin, NULL, TRUE);
}
else {
RECT rcTemp, rcWin;
if (pWin->WinType == TYPE_CONTROL &&
(pWin->dwExStyle & WS_EX_CTRLASMAINWIN)){
dskGetWindowRectInScreen (pWin, &rcWin);
}
else
GetWindowRect(hwnd, &rcWin);
/* XXX: when we move a window fast, there are some dirty rectangles
were not updated. We update whole area of the window for a work
around. */
if (IntersectRect (&rcTemp, &rcWin, &rcInv)) {
dskScreenToWindow (pWin, &rcTemp, &rcInv);
SendAsyncMessage ((HWND)pWin,
MSG_NCPAINT, 0, 0); // (LPARAM)(&rcInv));
dskScreenToClient (pWin, &rcTemp, &rcInv);
InvalidateRect ((HWND)pWin, NULL/*&rcInv*/, TRUE);
}
else {
_DBG_PRINTF ("IGNORED update\n");
}
}
}
}
#ifndef _MGSCHEMA_COMPOSITING
static int update_client_window (ZORDERNODE* znode, const RECT* rc)
{
#if defined(_MGRM_PROCESSES)
if (!mgIsServer)
return -1;
if (znode->cli != 0) {
if (rc) {
MSG msg = {0, MSG_WAKEUP_CLIENT, 0, 0, __mg_tick_counter};
_DBG_PRINTF ("Update window (%s): %d, %d, %d x %d\n",
znode->caption, rc->left, rc->top,
RECTWP(rc), RECTHP(rc));
if (IsRectEmpty (&znode->dirty_rc)) {
SetRect (&znode->dirty_rc,
rc->left, rc->top, rc->right, rc->bottom);
}
else {
GetBoundRect (&znode->dirty_rc, &znode->dirty_rc, rc);
}
mgClients [znode->cli].has_dirty = TRUE;
__mg_send2client (&msg, mgClients + znode->cli);
}
}
else
#endif /* defined _MGRM_PROCESSES */
{
if (rc)
__mg_update_window (znode->hwnd, rc->left, rc->top,
rc->right, rc->bottom);
else
__mg_update_window (znode->hwnd, 0, 0, 0, 0);
}
return 0;
}
static BOOL _cb_update_znode (void* context,
const ZORDERINFO* zi, ZORDERNODE* znode)
{
const RECT* rc = (RECT*)context;
_DBG_PRINTF ("Checking window (%s), visibility: %s, referred: %s\n", znode->caption,
(znode->flags & ZOF_VISIBLE)? "TRUE" : "FALSE",
(znode->flags & ZOF_IF_REFERENCE)? "TRUE" : "FALSE");
if (znode->flags & ZOF_VISIBLE &&
znode->flags & ZOF_IF_REFERENCE) {
_DBG_PRINTF ("Widnow (%s) will be updated\n", znode->caption);
update_client_window (znode, rc);
znode->flags &= ~ZOF_IF_REFERENCE;
return TRUE;
}
return FALSE;
}
static BOOL _cb_intersect_rc (void* context,
const ZORDERINFO* zi, ZORDERNODE* node)
{
RECT* rc = (RECT*)context;
if (node->flags & ZOF_VISIBLE && DoesIntersect (rc, &node->rc)) {
node->age++;
return TRUE;
}
return FALSE;
}
static BOOL _cb_update_rc (void* context,
const ZORDERINFO* zi, ZORDERNODE* node)
{
CLIPRGN* cliprgn = (CLIPRGN*)context;
if (node->flags & ZOF_VISIBLE &&
subtract_rgn_by_node(cliprgn, zi, node)) {
node->age++;
node->flags |= ZOF_IF_REFERENCE;
return TRUE;
}
return FALSE;
}
static BOOL _cb_exclude_rc (void* context,
const ZORDERINFO* zi, ZORDERNODE* node)
{
if (!(node->flags & ZOF_VISIBLE))
return FALSE;
if (node->idx_mask_rect != 0) {
int idx = node->idx_mask_rect;
MASKRECT *first = GET_MASKRECT(__mg_def_zorder_info);
int x, y;
RECT rc;
while (idx != 0) {
x = node->rc.left + (first+idx)->left;
y = node->rc.top + (first+idx)->top;
SetRect(&rc, x, y,
x+(first+idx)->right-(first+idx)->left,
y+(first+idx)->bottom-(first+idx)->top);
ExcludeClipRect (HDC_SCREEN_SYS, &rc);
idx = (first+idx)->next;
}
}
else
ExcludeClipRect (HDC_SCREEN_SYS, &node->rc);
return TRUE;
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
#ifdef _MGSCHEMA_COMPOSITING
static inline void reset_window (PMAINWIN pWin, RECT* rcWin) { }
#else
static void reset_window (PMAINWIN pWin, RECT* rcWin)
{
PGCRINFO pGCRInfo;
RECT rcScr, rcTemp;
pGCRInfo = pWin->pGCRInfo;
rcScr = GetScreenRect();
IntersectRect (&rcTemp, rcWin, &rcScr);
SetClipRgn (&pGCRInfo->crgn, &rcTemp);
}
#endif
#ifdef _MGRM_THREADS
# ifdef __ZI_USE_RWLOCK
static inline void lock_zi_for_change (ZORDERINFO* zi)
{
pthread_rwlock_wrlock(&zi->rwlock);
zi->rwlock_owner = pthread_self();
}
static inline void unlock_zi_for_change (ZORDERINFO* zi)
{
pthread_rwlock_unlock(&zi->rwlock);
zi->rwlock_owner = 0;
}
static inline void lock_zi_for_read (ZORDERINFO* zi)
{
if (zi->rwlock_owner == pthread_self()) {
return;
}
pthread_rwlock_rdlock(&zi->rwlock);
}
static inline void unlock_zi_for_read (ZORDERINFO* zi)
{
if (zi->rwlock_owner == pthread_self()) {
return;
}
pthread_rwlock_unlock(&zi->rwlock);
}
# else /* __ZI_USE_RWLOCK */
static inline void lock_zi_for_change (ZORDERINFO* zi)
{
pthread_mutex_lock(&zi->mutex);
}
static inline void unlock_zi_for_change (ZORDERINFO* zi)
{
pthread_mutex_unlock(&zi->mutex);
}
static inline void lock_zi_for_read (ZORDERINFO* zi)
{
pthread_mutex_lock(&zi->mutex);
}
static inline void unlock_zi_for_read (ZORDERINFO* zi)
{
pthread_mutex_unlock(&zi->mutex);
}
# endif /* notdef __ZI_USE_RWLOCK */
#elif defined(_MGRM_STANDALONE)
static inline void lock_zi_for_change (ZORDERINFO* zi) { }
static inline void unlock_zi_for_change (ZORDERINFO* zi) { }
static inline void lock_zi_for_read (ZORDERINFO* zi) { }
static inline void unlock_zi_for_read (ZORDERINFO* zi) { }
#else /* for procs */
/* NULL. see desktop-procs.c */
#endif /* _MGRM_THREADS */
static int RestrictControlRect(PMAINWIN pWin, RECT *minimal)
{
RECT rcMove;
int off_x = 0, off_y = 0;
PCONTROL pCtrl = gui_Control((HWND)pWin);
PCONTROL pRoot = (PCONTROL)(pWin->pMainWin);
if (pCtrl == NULL)
return FALSE;
do {
PCONTROL pParent = pCtrl;
rcMove.left = pRoot->cl + off_x;
rcMove.top = pRoot->ct + off_y;
rcMove.right = pRoot->cr + off_x;
rcMove.bottom = pRoot->cb + off_y;
dskScreenToClient (pWin, &rcMove, &rcMove);
if (!IntersectRect (minimal, minimal, &rcMove)) {
SetRect (minimal, 0, 0, 0, 0);
return FALSE;
}
off_x += pRoot->cl;
off_y += pRoot->ct;
if (pRoot == pCtrl->pParent)
break;
while (TRUE) {
if (pRoot->children == pParent->pParent->children) {
pRoot = pParent;
break;
}
pParent = pParent->pParent;
}
} while (TRUE);
return TRUE;
}
static int dskScrollMainWindow (PMAINWIN pWin, PSCROLLWINDOWINFO pswi)
{
HDC hdc;
RECT rcClient, rcScreen, rcInvalid;
BOOL inved = FALSE;
#ifdef _MGSCHEMA_COMPOSITING
CLIPRECT crcOne;
#endif
PCLIPRECT pcrc;
PINVRGN pInvRgn;
PCLIPRGN prgn = NULL;
dskClientToScreen (pWin, pswi->rc1, &rcScreen);
//BUGFIX: if the MainWindow is AutoSecondaryDC, the secondaryDC and
//client dc would be diffirent, so we must get the scondaryDC,
//the update to client dc (dongjunjie 2010/7/28)
//hdc = GetClientDC ((HWND)pWin);
hdc = get_effective_dc (pWin, TRUE);
#ifndef _MGSCHEMA_COMPOSITING
pcrc = pWin->pGCRInfo->crgn.head;
#else
crcOne.next = crcOne.prev = NULL;
crcOne.rc.left = pWin->pMainWin->left;
crcOne.rc.top = pWin->pMainWin->top;
crcOne.rc.right = pWin->pMainWin->right;
crcOne.rc.bottom = pWin->pMainWin->bottom;
pcrc = &crcOne;
#endif
while (pcrc) {
RECT rcMove;
if (!IntersectRect (&rcMove, &pcrc->rc, &rcScreen)) {
pcrc = pcrc->next;
continue;
}
dskScreenToClient (pWin, &rcMove, &rcMove);
if (!IntersectRect (&rcMove, &rcMove, pswi->rc1)) {
pcrc = pcrc->next;
continue;
}
if (pWin->dwExStyle & WS_EX_TRANSPARENT) {
/* set invalidate rect. */
InvalidateRect ((HWND)pWin, &rcMove, TRUE);
inved = TRUE;
}
else {
RestrictControlRect (pWin, &rcMove);
SelectClipRect (hdc, &rcMove);
BitBlt (hdc, rcMove.left, rcMove.top,
rcMove.right - rcMove.left,
rcMove.bottom - rcMove.top,
hdc,
pswi->iOffx + rcMove.left, pswi->iOffy + rcMove.top, 0);
}
pcrc = pcrc->next;
}
//ReleaseDC (hdc);
//BUGFIXED: we must update the secondaryDC to clientDC, to ensure
//the secondaryDC and clientDC are same (dongjunjie 2010/07/08)
if (pWin->pMainWin->secondaryDC) {
HDC real_dc = GetClientDC ((HWND)pWin->pMainWin);
__mg_update_secondary_dc(pWin, hdc, real_dc, pswi->rc1, HT_CLIENT);
ReleaseDC (real_dc);
}
release_effective_dc(pWin, hdc);
GetClientRect((HWND)pWin, &rcClient);
pInvRgn = &pWin->InvRgn;
if (!pInvRgn->frozen) {
#ifdef _MGRM_THREADS
pthread_mutex_lock (&pInvRgn->lock);
#endif
/*scroll whole screen, offset invalid region*/
if (EqualRect (pswi->rc1, &rcClient))
OffsetRegion (&(pInvRgn->rgn), pswi->iOffx, pswi->iOffy);
else
OffsetRegionEx (&(pInvRgn->rgn), &rcClient,
pswi->rc1, pswi->iOffx, pswi->iOffy);
#ifdef _MGRM_THREADS
pthread_mutex_unlock (&pInvRgn->lock);
#endif
}
#ifndef _MGSCHEMA_COMPOSITING
prgn = CreateClipRgn ();
lock_zi_for_read (__mg_zorder_info);
CopyRegion (prgn, &pWin->pGCRInfo->crgn);
pcrc = prgn->head;
unlock_zi_for_read (__mg_zorder_info);
#else
pcrc = &crcOne;
#endif
while (pcrc) {
BOOL bNeedInvalidate = FALSE;
RECT rcMove;
if (!IntersectRect (&rcMove, &pcrc->rc, &rcScreen)) {
pcrc = pcrc->next;
continue;
}
dskScreenToClient (pWin, &rcMove, &rcMove);
RestrictControlRect (pWin, &rcMove);
rcInvalid = rcMove;
if (pswi->iOffx < 0) {
rcInvalid.left = rcInvalid.right + pswi->iOffx;
bNeedInvalidate = TRUE;
}
else if (pswi->iOffx > 0) {
rcInvalid.right = rcInvalid.left + pswi->iOffx;
bNeedInvalidate = TRUE;
}
/*
* BUGFIXED: offx and offy would make the two diffrent areas invalidate
* we should invalid both them (dongjunjie) 2010/07/30
*
* content
* ---------------------------
* |//: offX |
* |//: |
* |//: View |
* |//: |
* |//: |
* |/////////////////////////| offY
* ---------------------------
* // - represent area need the Need invalidate
* see the to area must be invalidate
*/
if (bNeedInvalidate) {
InvalidateRect ((HWND)pWin, &rcInvalid, TRUE);
rcInvalid = rcMove; //restore the invalidate area
bNeedInvalidate = FALSE; //resotre the inved value
inved = TRUE;
}
if (pswi->iOffy < 0) {
rcInvalid.top = rcInvalid.bottom + pswi->iOffy;
bNeedInvalidate = TRUE;
}
else if (pswi->iOffy > 0) {
rcInvalid.bottom = rcInvalid.top + pswi->iOffy;
bNeedInvalidate = TRUE;
}
if (bNeedInvalidate) {
InvalidateRect ((HWND)pWin, &rcInvalid, TRUE);
inved = TRUE;
}
pcrc = pcrc->next;
}
if (prgn)
DestroyClipRgn (prgn);
if (inved) {
PostMessage ((HWND)pWin, MSG_PAINT, 0, 0);
}
return 0;
}
#ifndef _MGSCHEMA_COMPOSITING
void __mg_unlock_gcrinfo (PDC pdc)
{
#ifdef _MGRM_THREADS
pthread_mutex_unlock (&pdc->pGCRInfo->lock);
#endif
unlock_zi_for_read (__mg_zorder_info);
return;
}
static BOOL _cb_recalc_gcrinfo (void* context,
const ZORDERINFO* zi, ZORDERNODE* node)
{
PGCRINFO gcrinfo;
if (!(node->flags & ZOF_VISIBLE))
return FALSE;
gcrinfo = (PGCRINFO)context;
return subtract_rgn_by_node(&gcrinfo->crgn, zi, node);
}
void __mg_lock_recalc_gcrinfo (PDC pdc)
{
PGCRINFO gcrinfo;
PMAINWIN mainwin;
ZORDERINFO* zi = __mg_zorder_info;
ZORDERNODE* menu_nodes, *nodes;
int i, slot, idx_znode, level_from, level_to;
unsigned short idx;
CLIPRGN invisible_rgn;
mainwin = (PMAINWIN)(pdc->hwnd);
gcrinfo = mainwin->pGCRInfo;
#ifdef _MGRM_THREADS
pthread_mutex_lock (&pdc->pGCRInfo->lock);
#endif
lock_zi_for_read (zi);
menu_nodes = GET_MENUNODE(zi);
nodes = menu_nodes + DEF_NR_POPUPMENUS;
idx_znode = mainwin->idx_znode;
if (gcrinfo->old_zi_age == nodes [idx_znode].age) {
return;
}
idx = nodes [idx_znode].idx_mask_rect;
reset_window (mainwin, &nodes [idx_znode].rc);
/* when idx=0, this is HDC_SCREEN_SYS */
if (idx != 0) {
InitClipRgn (&invisible_rgn, &sg_FreeClipRectList);
SetClipRgn (&invisible_rgn, &nodes [idx_znode].rc);
subtract_rgn_by_node(&invisible_rgn, zi, &nodes[idx_znode]);
SubtractRegion (&gcrinfo->crgn, &gcrinfo->crgn, &invisible_rgn);
EmptyClipRgn(&invisible_rgn);
}
/* clip by popup menus */
for (i = 0; i < zi->nr_popupmenus; i++) {
SubtractClipRect (&gcrinfo->crgn, &menu_nodes [i].rc);
}
/* Since 5.0.0: check all levels */
slot = 0;
level_from = -1;
level_to = -1;
switch (nodes[idx_znode].flags & ZOF_TYPE_MASK) {
case ZOF_TYPE_TOOLTIP:
slot = zi->first_tooltip;
break;
case ZOF_TYPE_GLOBAL:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_TOOLTIP;
slot = zi->first_global;
break;
case ZOF_TYPE_SCREENLOCK:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_GLOBAL;
slot = zi->first_screenlock;
break;
case ZOF_TYPE_DOCKER:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_SCREENLOCK;
slot = zi->first_docker;
break;
case ZOF_TYPE_HIGHER:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_DOCKER;
slot = zi->first_topmost;
break;
case ZOF_TYPE_NORMAL:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_TOPMOST;
slot = zi->first_normal;
break;
case ZOF_TYPE_LAUNCHER:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_NORMAL;
slot = zi->first_launcher;
break;
case ZOF_TYPE_DESKTOP:
level_from = -1;
level_to = 0;
break;
default:
break;
}
/* subtract by all visible znodes above current level */
if (level_from >= 0) {
for (i = level_from; i <= level_to; i++) {
do_for_all_znodes (gcrinfo, zi,
_cb_recalc_gcrinfo, _zts_for_level[i]);
}
}
else if (level_to == 0) {
do_for_all_znodes (gcrinfo, zi,
_cb_recalc_gcrinfo, ZT_ALL);
}
/* subtract by visible znodes above the znode in current level */
while (slot && slot != idx_znode) {
if (nodes [slot].flags & ZOF_VISIBLE)
subtract_rgn_by_node (&gcrinfo->crgn, zi, &nodes[slot]);
slot = nodes [slot].next;
}
gcrinfo->old_zi_age = nodes [idx_znode].age;
gcrinfo->age++;
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
/*
* Init a window's global clipping region.
*/
#ifdef _MGSCHEMA_COMPOSITING
static inline void dskInitGCRInfo (PMAINWIN pWin) {}
#else
static void dskInitGCRInfo (PMAINWIN pWin)
{
RECT rcWin, rcScr, rcTemp;
dskGetWindowRectInScreen (pWin, &rcWin);
#ifdef _MGRM_THREADS
pthread_mutex_init (&pWin->pGCRInfo->lock, NULL);
#endif
pWin->pGCRInfo->age = 0;
pWin->pGCRInfo->old_zi_age = 0;
InitClipRgn (&pWin->pGCRInfo->crgn, &sg_FreeClipRectList);
rcScr = GetScreenRect();
IntersectRect (&rcTemp, &rcWin, &rcScr);
SetClipRgn (&pWin->pGCRInfo->crgn, &rcTemp);
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
/*
* Init a window's invalid region.
*/
static void dskInitInvRgn (PMAINWIN pWin)
{
#ifdef _MGRM_THREADS
pthread_mutex_init (&pWin->InvRgn.lock, NULL);
#endif
pWin->InvRgn.frozen = 0;
InitClipRgn (&pWin->InvRgn.rgn, &sg_FreeInvRectList);
MAKE_REGION_INFINITE(&pWin->InvRgn.rgn);
}
int __kernel_get_next_znode (const ZORDERINFO* zi, int from)
{
int next = 0;
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
if (from <= 0) {
next = zi->first_tooltip;
if (next == 0)
next = zi->first_global;
if (next == 0)
next = zi->first_screenlock;
if (next == 0)
next = zi->first_docker;
if (next == 0)
next = zi->first_topmost;
if (next == 0)
next = zi->first_normal;
if (next == 0)
next = zi->first_launcher;
return next;
}
next = nodes [from].next;
if (next > 0)
return next;
/* next is still zero. */
switch (nodes [from].flags & ZOF_TYPE_MASK) {
case ZOF_TYPE_TOOLTIP:
next = zi->first_global;
if (next == 0)
next = zi->first_screenlock;
if (next == 0)
next = zi->first_docker;
if (next == 0)
next = zi->first_topmost;
if (next == 0)
next = zi->first_normal;
if (next == 0)
next = zi->first_launcher;
break;
case ZOF_TYPE_GLOBAL:
next = zi->first_screenlock;
if (next == 0)
next = zi->first_docker;
if (next == 0)
next = zi->first_topmost;
if (next == 0)
next = zi->first_normal;
if (next == 0)
next = zi->first_launcher;
break;
case ZOF_TYPE_SCREENLOCK:
next = zi->first_docker;
if (next == 0)
next = zi->first_topmost;
if (next == 0)
next = zi->first_normal;
if (next == 0)
next = zi->first_launcher;
break;
case ZOF_TYPE_DOCKER:
next = zi->first_topmost;
if (next == 0)
next = zi->first_normal;
if (next == 0)
next = zi->first_launcher;
break;
case ZOF_TYPE_HIGHER:
next = zi->first_normal;
if (next == 0)
next = zi->first_launcher;
break;
case ZOF_TYPE_NORMAL:
next = zi->first_launcher;
break;
default:
return -1;
}
return next;
}
int __kernel_get_prev_znode (const ZORDERINFO* zi, int from)
{
int prev = 0;
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
if (from <= 0) {
if (zi->first_launcher) {
prev = zi->first_launcher;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_normal) {
prev = zi->first_normal;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_topmost) {
prev = zi->first_topmost;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_docker) {
prev = zi->first_docker;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_screenlock) {
prev = zi->first_screenlock;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_global) {
prev = zi->first_global;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_tooltip) {
prev = zi->first_tooltip;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
return prev;
}
prev = nodes [from].prev;
if (prev > 0)
return prev;
/* prev is still zero. */
switch (nodes [from].flags & ZOF_TYPE_MASK) {
case ZOF_TYPE_LAUNCHER:
if (zi->first_normal) {
prev = zi->first_normal;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_topmost) {
prev = zi->first_topmost;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_docker) {
prev = zi->first_docker;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_screenlock) {
prev = zi->first_screenlock;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_global) {
prev = zi->first_global;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_tooltip) {
prev = zi->first_tooltip;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
break;
case ZOF_TYPE_NORMAL:
if (zi->first_topmost) {
prev = zi->first_topmost;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_docker) {
prev = zi->first_docker;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_screenlock) {
prev = zi->first_screenlock;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_global) {
prev = zi->first_global;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_tooltip) {
prev = zi->first_tooltip;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
break;
case ZOF_TYPE_HIGHER:
if (zi->first_docker) {
prev = zi->first_docker;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_screenlock) {
prev = zi->first_screenlock;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_global) {
prev = zi->first_global;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_tooltip) {
prev = zi->first_tooltip;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
break;
case ZOF_TYPE_DOCKER:
if (zi->first_screenlock) {
prev = zi->first_screenlock;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_global) {
prev = zi->first_global;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_tooltip) {
prev = zi->first_tooltip;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
break;
case ZOF_TYPE_SCREENLOCK:
if (zi->first_global) {
prev = zi->first_global;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
else if (zi->first_tooltip) {
prev = zi->first_tooltip;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
break;
case ZOF_TYPE_GLOBAL:
if (zi->first_tooltip) {
prev = zi->first_tooltip;
while (nodes [prev].next) {
prev = nodes [prev].next;
}
}
break;
default:
return -1;
}
return prev;
}
static int get_next_activable_mainwin (const ZORDERINFO* zi, int from)
{
int next;
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
do {
next = __kernel_get_next_znode (zi, from);
if (next <= 0)
break;
if (nodes [next].flags & ZOF_TF_MAINWIN
&& (nodes [next].flags & ZOF_VISIBLE)
&& !(nodes [next].flags & ZOF_DISABLED))
return next;
from = next;
} while (1);
return 0;
}
#if 0 /* move to window.c since 5.0.0 */
/*
* Add new hosted main window.
*/
static void dskAddNewHostedMainWindow (PMAINWIN pHosting, PMAINWIN pHosted)
{
PMAINWIN head, prev;
pHosted->pNextHosted = NULL;
head = pHosting->pFirstHosted;
if (head) {
while (head) {
prev = head;
head = head->pNextHosted;
}
prev->pNextHosted = pHosted;
}
else
pHosting->pFirstHosted = pHosted;
return;
}
/*
* Remove a hosted main window.
*/
static void dskRemoveHostedMainWindow (PMAINWIN pHosting, PMAINWIN pHosted)
{
PMAINWIN head, prev;
head = pHosting->pFirstHosted;
if (head == pHosted) {
pHosting->pFirstHosted = head->pNextHosted;
return;
}
while (head) {
prev = head;
head = head->pNextHosted;
if (head == pHosted) {
prev->pNextHosted = head->pNextHosted;
return;
}
}
return;
}
#endif /* moved code */
/*
* Moves a window to topmost.
*
* dskIsTopMost
* dskMove2Top
*/
static void dskSetPrimitiveChildren (PMAINWIN pWin, BOOL bSet)
{
PMAINWIN pParent = (PMAINWIN) pWin->hParent;
if (bSet) {
while (pParent) {
pParent->hPrimitive = (HWND)pWin;
pWin = pParent;
pParent = (PMAINWIN) pWin->hParent;
}
}
else {
while (pParent) {
pParent->hPrimitive = 0;
pWin = pParent;
pParent = (PMAINWIN) pWin->hParent;
}
}
}
static BOOL dskIsTopMost (PMAINWIN pWin)
{
int level;
BOOL ret = FALSE;
lock_zi_for_read (__mg_zorder_info);
/* Since 5.0.0: handle all levels */
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
if (pWin->idx_znode == __mg_zorder_info->first_in_levels[level]) {
ret = TRUE;
break;
}
}
unlock_zi_for_read (__mg_zorder_info);
return ret;
}
#ifdef _MGHAVE_MENU
static PTRACKMENUINFO sg_ptmi;
static HMENU sg_DesktopMenu = 0; /* system global desktop menu handle */
// call back proc of tracking menu.
// defined in Menu module.
int PopupMenuTrackProc (PTRACKMENUINFO ptmi,
int message, WPARAM wParam, LPARAM lParam);
static int srvForceCloseMenu (int cli)
{
ZORDERINFO* zi = get_zorder_info(cli);
int i, ret = 0;
#if defined(_MGRM_PROCESSES)
int cli_trackmenu;
#endif
ZORDERNODE* menu_nodes;
RECT rc_bound;
#ifndef _MGSCHEMA_COMPOSITING
ZORDERNODE* win_nodes;
RECT rc_screen;
#endif
if (zi->cli_trackmenu < 0 || zi->nr_popupmenus == 0)
return 0;
menu_nodes = GET_MENUNODE(zi);
#ifndef _MGSCHEMA_COMPOSITING
win_nodes = menu_nodes + DEF_NR_POPUPMENUS;
#endif
SetRect (&rc_bound, 0, 0, 0, 0);
/* lock zi for change */
lock_zi_for_change (zi);
for (i = 0; i < zi->nr_popupmenus; i++) {
GetBoundRect (&rc_bound, &rc_bound, &menu_nodes [i].rc);
}
#ifndef _MGSCHEMA_COMPOSITING
SetClipRgn (&sg_UpdateRgn, &rc_bound);
/* check influenced window zorder nodes */
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_ALL);
rc_screen = GetScreenRect ();
if (SubtractClipRect (&sg_UpdateRgn, &rc_screen)) {
win_nodes [0].age++;
win_nodes [0].flags |= ZOF_IF_REFERENCE;
}
#else /* defined _MGSCHEMA_COMPOSITING */
for (i = (zi->nr_popupmenus - 1); i >= 0; i--) {
DO_COMPSOR_OP_ARGS (on_hiding_ppp, i);
DeleteMemDC (menu_nodes[i].mem_dc);
}
#endif /* defined _MGSCHEMA_COMPOSITING */
#if defined(_MGRM_PROCESSES)
cli_trackmenu = zi->cli_trackmenu;
#endif
zi->cli_trackmenu = -1;
zi->nr_popupmenus = 0;
/* unlock zi for change */
unlock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
/* update all znode if it's dirty */
do_for_all_znodes (&rc_bound, zi, _cb_update_znode, ZT_ALL);
if (win_nodes [0].flags & ZOF_IF_REFERENCE) {
SendMessage (HWND_DESKTOP,
MSG_ERASEDESKTOP, 0, (LPARAM)&rc_bound);
win_nodes [0].flags &= ~ZOF_IF_REFERENCE;
}
#else /* not defined _MGSCHEMA_COMPOSITING */
DO_COMPSOR_OP_ARGS (on_closed_menu, &rc_bound);
#endif /* defined _MGSCHEMA_COMPOSITING */
/* notify the client to close the menu */
{
#if defined(_MGRM_PROCESSES)
MSG msg = {0, MSG_CLOSEMENU, 0, 0, __mg_tick_counter};
if (cli_trackmenu)
ret = __mg_send2client (&msg, mgClients + cli_trackmenu);
else
#endif
SendMessage (HWND_DESKTOP, MSG_CLOSEMENU, 0, 0);
}
return ret;
}
static int srvStartTrackPopupMenu (int cli, const RECT* rc, HWND ptmi,
Uint32 surf_flags, size_t surf_size, int fd)
{
ZORDERINFO* zi = get_zorder_info(cli);
ZORDERNODE* menu_nodes;
#ifdef _MGSCHEMA_COMPOSITING
HDC memdc = HDC_INVALID;
#else
ZORDERNODE* win_nodes;
RECT rc_screen;
#endif
if (zi->cli_trackmenu >= 0 && zi->cli_trackmenu != cli) {
srvForceCloseMenu (0);
}
if (zi->nr_popupmenus == zi->max_nr_popupmenus)
return -1;
#ifdef _MGSCHEMA_COMPOSITING
{
GAL_Surface* surf;
if (cli == 0) {
surf = GetSurfaceFromDC (((PTRACKMENUINFO)ptmi)->dc);
// prevent to free this surface when deleting memdc for znode.
surf->refcount++;
}
else if (fd >= 0) {
surf = GAL_AttachSharedRGBSurface (NULL, fd,
surf_size, surf_flags, TRUE);
/* Since 5.2.0: keep fd available.
close (fd); */
}
else {
_WRN_PRINTF("not server but fd for shared surface is invalid\n");
return -1;
}
if (surf) {
memdc = CreateMemDCFromSurface (surf);
if (memdc == HDC_INVALID) {
GAL_FreeSurface (surf);
_WRN_PRINTF("failed to create memory dc for znode\n");
return -1;
}
}
else {
_WRN_PRINTF("KERNEL: failed to attach to surface\n");
return -1;
}
}
#endif /* def _MGSCHEMA_COMPOSITING */
menu_nodes = GET_MENUNODE(zi);
/* lock zi for change */
lock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
win_nodes = menu_nodes + DEF_NR_POPUPMENUS;
/* check influenced window zorder nodes */
do_for_all_znodes ((void*)rc, zi, _cb_intersect_rc, ZT_ALL);
rc_screen = GetScreenRect();
if (DoesIntersect (rc, &rc_screen)) {
win_nodes [0].age++;
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
menu_nodes [zi->nr_popupmenus].flags = ZOF_TYPE_POPUPMENU;
menu_nodes [zi->nr_popupmenus].rc = *rc;
menu_nodes [zi->nr_popupmenus].hwnd = ptmi;
#ifdef _MGSCHEMA_COMPOSITING
menu_nodes [zi->nr_popupmenus].changes = 0;
menu_nodes [zi->nr_popupmenus].ct = CT_OPAQUE;
menu_nodes [zi->nr_popupmenus].ct_arg = 0;
menu_nodes [zi->nr_popupmenus].mem_dc = memdc;
menu_nodes [zi->nr_popupmenus].dirty_rcs = NULL;
#endif
menu_nodes [zi->nr_popupmenus].priv_data = NULL;
if (zi->cli_trackmenu == -1)
zi->cli_trackmenu = cli;
zi->nr_popupmenus ++;
#ifdef _MGSCHEMA_COMPOSITING
DO_COMPSOR_OP_ARGS (on_showing_ppp, zi->nr_popupmenus - 1);
#endif /* defined _MGSCHEMA_COMPOSITING */
/* unlock zi for change */
unlock_zi_for_change (zi);
return zi->nr_popupmenus - 1;
}
static int srvEndTrackPopupMenu (int cli, int idx_znode)
{
ZORDERINFO* zi = get_zorder_info(cli);
ZORDERNODE* menu_nodes;
#ifndef _MGSCHEMA_COMPOSITING
ZORDERNODE* win_nodes;
RECT rc, rc_screen;
#endif
if (zi->cli_trackmenu != cli
|| zi->nr_popupmenus != (idx_znode + 1))
return -1;
menu_nodes = GET_MENUNODE(zi);
#ifndef _MGSCHEMA_COMPOSITING
win_nodes = menu_nodes + DEF_NR_POPUPMENUS;
#endif
/* lock zi for change */
lock_zi_for_change (zi);
#ifdef _MGSCHEMA_COMPOSITING
DO_COMPSOR_OP_ARGS (on_hiding_ppp, idx_znode);
DeleteMemDC (menu_nodes [idx_znode].mem_dc);
#else /* not defined _MGSCHEMA_COMPOSITING */
rc = menu_nodes [idx_znode].rc;
SetClipRgn (&sg_UpdateRgn, &rc);
/* check influenced window zorder nodes */
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_ALL);
rc_screen = GetScreenRect();
if (SubtractClipRect (&sg_UpdateRgn, &rc_screen)) {
win_nodes [0].age++;
win_nodes [0].flags |= ZOF_IF_REFERENCE;
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
zi->nr_popupmenus --;
if (zi->nr_popupmenus == 0)
zi->cli_trackmenu = -1;
/* unlock zi for change */
unlock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
/* update all znode if it's dirty */
do_for_all_znodes (&rc, zi, _cb_update_znode, ZT_ALL);
if (win_nodes [0].flags & ZOF_IF_REFERENCE) {
SendMessage (HWND_DESKTOP,
MSG_ERASEDESKTOP, 0, (LPARAM)&rc);
win_nodes [0].flags &= ~ZOF_IF_REFERENCE;
}
#else /* not defined _MGSCHEMA_COMPOSITING */
DO_COMPSOR_OP_ARGS (on_dirty_screen, NULL,
menu_nodes [idx_znode].flags & ZOF_TYPE_FLAG_MASK,
&menu_nodes [idx_znode].rc);
#endif /* defined _MGSCHEMA_COMPOSITING */
return 0;
}
static BOOL dskCloseMenu (void)
{
if (sg_ptmi == NULL)
return FALSE;
SendNotifyMessage (sg_ptmi->hwnd,
MSG_DEACTIVEMENU,
(WPARAM)sg_ptmi->pmb,
(LPARAM)sg_ptmi->pmi);
PopupMenuTrackProc (sg_ptmi, MSG_CLOSEMENU, 0, 0);
sg_ptmi = NULL;
return TRUE;
}
#endif /* defined _MGHAVE_MENU */
int __mg_post_msg_by_znode (const ZORDERINFO* zi, int znode,
int message, WPARAM wParam, LPARAM lParam)
{
int ret = 0;
ZORDERNODE* nodes;
if (znode < 0)
return -1;
nodes = GET_ZORDERNODE(zi);
if (nodes [znode].cli == 0) {
ret = PostMessage (nodes [znode].main_win,
message, wParam, lParam);
}
#if defined (_MGRM_PROCESSES)
else {
MSG msg = {nodes [znode].main_win,
message, wParam, lParam, __mg_tick_counter};
ret = __mg_send2client (&msg, mgClients + nodes [znode].cli);
}
#endif
return ret;
}
static int
post_msg_by_znode_p (const ZORDERINFO* zi, const ZORDERNODE* znode,
int message, WPARAM wParam, LPARAM lParam)
{
int ret = 0;
if (!znode->main_win) {
return 0;
}
if (znode->cli == 0) {
ret = PostMessage (znode->main_win, message, wParam, lParam);
}
#if defined (_MGRM_PROCESSES)
else {
MSG msg = {znode->main_win,
message, wParam, lParam, __mg_tick_counter};
ret = __mg_send2client (&msg, mgClients + znode->cli);
}
#endif
return ret;
}
static HWND dskSetActiveZOrderNode (ZORDERINFO* zi, int cli, int idx_znode)
{
int old_active = 0;
ZORDERNODE* nodes;
HWND old_hwnd = HWND_NULL, new_hwnd = HWND_NULL;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return HWND_INVALID;
}
nodes = GET_ZORDERNODE(zi);
if ((__mg_ime_wnd && __mg_ime_wnd == nodes [idx_znode].main_win) ||
nodes [idx_znode].flags & ZOF_TF_TOOLWIN)
return HWND_INVALID;
#ifdef _MGHAVE_MENU
if (zi->cli_trackmenu >= 0)
srvForceCloseMenu (0);
#endif
/* lock zi for change */
lock_zi_for_change (zi);
if (zi->active_win) {
old_active = zi->active_win;
}
zi->active_win = idx_znode;
/* unlock zi for change */
unlock_zi_for_change (zi);
if (old_active) {
if (nodes [old_active].cli == cli) {
old_hwnd = nodes [old_active].hwnd;
}
else
old_hwnd = HWND_OTHERPROC;
}
if (idx_znode) {
if (nodes [idx_znode].cli == cli) {
new_hwnd = nodes [idx_znode].hwnd;
}
else
new_hwnd = HWND_OTHERPROC;
}
if (old_active && (nodes [old_active].flags & ZOF_VISIBLE)) {
post_msg_by_znode_p (zi, nodes + old_active,
MSG_NCACTIVATE, FALSE, 0);
post_msg_by_znode_p (zi, nodes + old_active,
MSG_ACTIVE, FALSE, 0);
post_msg_by_znode_p (zi, nodes + old_active,
MSG_KILLFOCUS, (WPARAM)new_hwnd, 0);
}
if (idx_znode) {
post_msg_by_znode_p (zi, nodes + idx_znode,
MSG_NCACTIVATE, TRUE, 0);
post_msg_by_znode_p (zi, nodes + idx_znode,
MSG_ACTIVE, TRUE, 0);
post_msg_by_znode_p (zi, nodes + idx_znode,
MSG_SETFOCUS, (WPARAM)old_hwnd, 0);
}
return old_hwnd;
}
#if 0 /* Since 5.0.0, use strdup to duplicate the caption */
static void get_text_char_pos (PLOGFONT log_font, const char *text,
int len, int fit_bytes, int *fit_chars, int *pos_chars)
{
DEVFONT* sbc_devfont = log_font->devfonts[0];
DEVFONT* mbc_devfont = log_font->devfonts[1];
int len_cur_char;
int left_bytes = len;
int char_count = 0, bytes = 0;
while (left_bytes > 0 && bytes < fit_bytes) {
if (pos_chars) {
pos_chars[char_count] = len - left_bytes;
}
if ((mbc_devfont) &&
(len_cur_char = mbc_devfont->charset_ops->len_first_char
((const unsigned char*)text, left_bytes)) > 0) {
char_count ++;
left_bytes -= len_cur_char;
text += len_cur_char;
bytes += len_cur_char;
} else {
if ((len_cur_char = sbc_devfont->charset_ops->len_first_char
((const unsigned char*)text, left_bytes)) > 0) {
char_count ++;
left_bytes -= len_cur_char;
text += len_cur_char;
bytes += len_cur_char;
} else {
break;
}
}
}
if (fit_chars) {
*fit_chars = char_count;
}
}
#endif
/* Since 5.0.0:
Under compositing schema, we do not allocate mask rectangles
for round corners. Instead, we get the region of window znode
in ServerGetWinZNodeRegion.
*/
#ifndef _MGSCHEMA_COMPOSITING
#define do_with_round_rect(src, drc, idx) \
if (idx != 0) { \
if (drc[idx-1].left == src.left && \
RECTW(drc[idx-1]) == RECTW(src)) { \
SetRect(&(drc[idx-1]), \
drc[idx-1].left, \
drc[idx-1].top, \
drc[idx-1].right, \
src.bottom); \
} \
else { \
CopyRect(&(drc[idx]), &src); \
idx++; \
} \
} \
else { \
CopyRect(&(drc[idx]), &src); \
idx++; \
}
static int alloc_mask_rects_for_round_corners (ZORDERNODE* node,
const DWORD flags, const RECT *rc)
{
RECT* roundrc = NULL;
RECT rect;
int max_rect_num = 1, free_slot, rc_idx;
int i, z, r = RADIUS_WINDOW_CORNERS;
unsigned short idx;
MASKRECT *firstmaskrect;
if (flags & ZOF_TW_TROUNDCNS)
max_rect_num += r;
if (flags & ZOF_TW_BROUNDCNS)
max_rect_num += r;
roundrc = calloc (1, max_rect_num * sizeof(RECT));
if (!roundrc)
return -1;
/*generate region of top round corner*/
rc_idx = 0;
if (flags & ZOF_TW_TROUNDCNS) {
for(i = 0; i < r; i++)
{
z = sqrt (2*i*r - i*i);
SetRect (&rect, rc->left+r-z, rc->top+i,
rc->left+RECTWP(rc)-r+z, rc->top+i+1);
do_with_round_rect (rect, roundrc, rc_idx);
}
}
else{
SetRect (&rect, rc->left, rc->top,
rc->left+RECTWP(rc), rc->top+r);
CopyRect (&(roundrc[rc_idx]), &rect);
rc_idx++;
}
SetRect (&rect, rc->left, rc->top+r,
rc->left+RECTWP(rc), rc->top+RECTHP(rc)-r);
do_with_round_rect (rect, roundrc, rc_idx);
/* generate region of bottom round corner*/
if (flags & ZOF_TW_BROUNDCNS) {
for(i = 1; i < r; i++)
{
z = sqrt (r*r-i*i);
SetRect (&rect, rc->left+r-z,
rc->top+RECTHP(rc)-r+i-1,
rc->left+RECTWP(rc)-r+z,
rc->top+RECTHP(rc)-r+i+1);
do_with_round_rect (rect, roundrc, rc_idx);
}
}
else {
SetRect (&rect, rc->left, rc->top+RECTHP(rc)-r,
rc->left+RECTWP(rc), rc->top+RECTHP(rc));
do_with_round_rect (rect, roundrc, rc_idx);
}
/* if have enough mask rect */
if (rc_idx >
__mg_get_nr_idle_slots (GET_MASKRECT_USAGEBMP(__mg_def_zorder_info),
__mg_def_zorder_info->size_maskrect_usage_bmp)) {
free (roundrc);
return -1;
}
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
/* allocate space*/
idx = 0;
for (i = 0; i < rc_idx; i++) {
free_slot = __mg_lookfor_unused_slot (
GET_MASKRECT_USAGEBMP(__mg_def_zorder_info),
__mg_def_zorder_info->size_maskrect_usage_bmp, 1);
if (free_slot == -1) {
_WRN_PRINTF ("KERNEL: __mg_lookfor_unused_slot failed\n");
return -1;
}
(firstmaskrect + free_slot)->prev = idx;
if (idx != 0) {
(firstmaskrect + idx)->next = free_slot;
}
else {
node->idx_mask_rect = free_slot;
}
idx = free_slot;
}
if (idx != 0) {
(firstmaskrect + idx)->prev = 0;
}
/* get value */
idx = node->idx_mask_rect;
i = 0;
while (idx != 0) {
(firstmaskrect + idx)->left = (unsigned short)roundrc[i].left;
(firstmaskrect + idx)->top = (unsigned short)roundrc[i].top;
(firstmaskrect + idx)->right = (unsigned short)roundrc[i].right;
(firstmaskrect + idx)->bottom = (unsigned short)roundrc[i].bottom;
idx = (firstmaskrect + idx)->next;
i++;
}
free (roundrc);
return 0;
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
#ifdef _MGSCHEMA_COMPOSITING
static inline int validate_compositing_type (DWORD flags, int type)
{
if (flags & ZOF_TF_CONTROL) {
return CT_OPAQUE;
}
else if (type < CT_OPAQUE || type > CT_MAX_VALUE)
return CT_OPAQUE;
return type;
}
#endif /* defined _MGSCHEMA_COMPOSITING */
#ifdef _MGRM_PROCESSES
/* copy special znodes to another layer */
void __mg_sync_special_nodes (ZORDERINFO* from, ZORDERINFO* to)
{
unsigned char *from_use_bmp, *to_use_bmp;
ZORDERNODE *from_nodes, *to_nodes;
if (from == to)
return;
lock_zi_for_change (to);
to->nr_globals = from->nr_globals;
to->first_global = from->first_global;
to->nr_screenlocks = from->nr_screenlocks;
to->first_screenlock = from->first_screenlock;
to->nr_dockers = from->nr_dockers;
to->first_docker = from->first_docker;
to->nr_launchers = from->nr_launchers;
to->first_launcher = from->first_launcher;
from_nodes = GET_ZORDERNODE(from);
to_nodes = GET_ZORDERNODE(to);
memcpy (to_nodes, from_nodes, sizeof(ZORDERNODE) * MAX_NR_SPECIAL_ZNODES (from));
/* it seems no need to copy usage bitmap */
from_use_bmp = (unsigned char*)from + sizeof (ZORDERINFO);
to_use_bmp = (unsigned char*)to + sizeof (ZORDERINFO);
memcpy (to_use_bmp, from_use_bmp, LEN_USAGE_BMP_SPECIAL (from));
unlock_zi_for_change (to);
}
#else /* defined _MGRM_PROCESSES */
void __mg_sync_special_nodes (ZORDERINFO* from, ZORDERINFO* to)
{
assert (from == to);
// do nothing
return;
}
#endif /* not defined _MGRM_PROCESSES */
static void update_on_new_visible_znode (void* layer, ZORDERINFO* zi,
int idx_znode, DWORD type)
{
#ifndef _MGSCHEMA_COMPOSITING
ZORDERNODE *nodes;
int level, slot;
nodes = GET_ZORDERNODE(zi);
RECT rc_screen = GetScreenRect();
lock_zi_for_change (zi);
/* check influenced zorder nodes */
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
if (type >= _zof_types_for_level[level]) {
slot = zi->first_in_levels[level];
for (; slot > 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
DoesIntersect (&nodes [idx_znode].rc,
&nodes [slot].rc)) {
nodes [slot].age++;
}
}
}
}
/* for destkop */
if (DoesIntersect (&nodes [idx_znode].rc, &rc_screen)) {
nodes [0].age++;
}
unlock_zi_for_change (zi);
#else /* not defined _MGSCHEMA_COMPOSITING */
DO_COMPSOR_OP_ARGS (on_showing_win, layer, idx_znode);
#endif /* defined _MGSCHEMA_COMPOSITING */
}
static int AllocZOrderNodeEx (ZORDERINFO* zi, int cli, HWND hwnd, HWND main_win,
DWORD flags, const RECT *rc, const char *caption,
HDC mem_dc, int fd, int ct, DWORD ct_arg)
{
DWORD type = flags & ZOF_TYPE_MASK;
int *first = NULL, *nr_nodes = NULL;
int free_slot = -1, old_first;
ZORDERNODE* nodes;
nodes = GET_ZORDERNODE(zi);
/* Since 5.0.0: check special znode type first for MiniGUI-Processes */
#ifdef _MGRM_PROCESSES
switch (type) {
/* Since 5.0.6: tooltips are not special znodes
case ZOF_TYPE_TOOLTIP:
if (zi->first_tooltip > 0 &&
nodes [zi->first_tooltip].cli != cli) {
flags &= ~ZOF_TYPE_MASK;
flags |= ZOF_TYPE_HIGHER;
}
break;
*/
case ZOF_TYPE_GLOBAL:
if (cli != 0) {
flags &= ~ZOF_TYPE_MASK;
flags |= ZOF_TYPE_HIGHER;
}
break;
/* Since 5.0.6: the special znode only allowed for clients on `mginit` layer */
case ZOF_TYPE_SCREENLOCK:
if (zi != __mg_def_zorder_info || (zi->first_screenlock > 0 &&
nodes [zi->first_screenlock].cli != cli)) {
flags &= ~ZOF_TYPE_MASK;
flags |= ZOF_TYPE_HIGHER;
}
break;
case ZOF_TYPE_DOCKER:
if (zi != __mg_def_zorder_info || (zi->first_docker > 0 &&
nodes [zi->first_docker].cli != cli)) {
flags &= ~ZOF_TYPE_MASK;
flags |= ZOF_TYPE_HIGHER;
}
break;
case ZOF_TYPE_LAUNCHER:
if (zi != __mg_def_zorder_info || (zi->first_launcher > 0 &&
nodes [zi->first_launcher].cli != cli)) {
flags &= ~ZOF_TYPE_MASK;
flags |= ZOF_TYPE_NORMAL;
}
break;
}
#endif /* defined _MGRM_PROCESSES */
/* reacquire type */
type = flags & ZOF_TYPE_MASK;
nodes = GET_ZORDERNODE(zi);
switch (type) {
case ZOF_TYPE_TOOLTIP:
if (zi->nr_tooltips < zi->max_nr_tooltips) {
first = &zi->first_tooltip;
nr_nodes = &zi->nr_tooltips;
}
break;
case ZOF_TYPE_GLOBAL:
if (zi->nr_globals < zi->max_nr_globals) {
first = &zi->first_global;
nr_nodes = &zi->nr_globals;
}
break;
case ZOF_TYPE_SCREENLOCK:
if (zi->nr_screenlocks < zi->max_nr_screenlocks) {
first = &zi->first_screenlock;
nr_nodes = &zi->nr_screenlocks;
}
break;
case ZOF_TYPE_DOCKER:
if (zi->nr_dockers < zi->max_nr_dockers) {
first = &zi->first_docker;
nr_nodes = &zi->nr_dockers;
}
break;
case ZOF_TYPE_HIGHER:
if (zi->nr_topmosts < zi->max_nr_topmosts) {
first = &zi->first_topmost;
nr_nodes = &zi->nr_topmosts;
}
break;
case ZOF_TYPE_NORMAL:
if (zi->nr_normals < zi->max_nr_normals) {
first = &zi->first_normal;
nr_nodes = &zi->nr_normals;
}
break;
case ZOF_TYPE_LAUNCHER:
if (zi->nr_launchers < zi->max_nr_launchers) {
first = &zi->first_launcher;
nr_nodes = &zi->nr_launchers;
}
break;
default:
break;
}
if (first == NULL) {
int level = ZOF_TYPE_TO_LEVEL_IDX (type);
_WRN_PRINTF ("no free slot for the new znode: "
"level (%d), max_nr (%d), nr (%d)\n",
level, zi->nr_nodes_in_levels[level],
zi->max_nr_nodes_in_levels[level]);
return -1;
}
#ifdef _MGHAVE_MENU
if (zi->cli_trackmenu >= 0 && flags & ZOF_VISIBLE)
srvForceCloseMenu (0);
#endif
/* lock zi for change */
lock_zi_for_change (zi);
/* Since 5.0.0: tune code to avoid potential errors */
{
int len_bmp_specials = LEN_USAGE_BMP_SPECIAL(zi);
if (IS_TYPE_SPECIAL (type)) {
free_slot = __mg_lookfor_unused_slot (
(BYTE*)(zi + 1), len_bmp_specials, 1);
if (free_slot >= MAX_NR_SPECIAL_ZNODES(zi))
free_slot = -1;
/* Since 5.0.6 */
flags |= ZOF_IF_SPECIAL;
}
else {
free_slot = __mg_lookfor_unused_slot (
(BYTE*)(zi + 1) + len_bmp_specials,
LEN_USAGE_BMP_GENERAL(zi), 1);
if (free_slot >= 0) {
free_slot += len_bmp_specials << 3;
}
assert (free_slot >= MAX_NR_SPECIAL_ZNODES(zi));
if (free_slot >= MAX_NR_ZNODES(zi))
free_slot = -1;
}
}
if (-1 == free_slot) {
/* unlock zorderinfo for change. */
unlock_zi_for_change (zi);
_WRN_PRINTF ("cannot allocate slot for new znode\n");
return -1;
}
if (nr_nodes)
*nr_nodes += 1;
/* Since 5.0.0. Support for always top znode. */
if (*first == 0 || !(nodes [*first].flags & ZOF_IF_ALWAYSTOP)) {
old_first = *first;
nodes [old_first].prev = free_slot;
nodes [free_slot].prev = 0;
nodes [free_slot].next = old_first;
}
else {
int pre_idx = *first;
while (*first) {
if ((nodes [*first].flags & ZOF_IF_ALWAYSTOP)) {
pre_idx = *first;
first = &nodes[*first].next;
}
else
break;
}
old_first = pre_idx;
nodes [free_slot].prev = old_first;
nodes [free_slot].next = nodes [old_first].next;
nodes [nodes [old_first].next].prev = free_slot;
nodes [old_first].next = free_slot;
}
*first = free_slot;
nodes [free_slot].flags = flags;
nodes [free_slot].rc = *rc;
nodes [free_slot].cli = cli;
nodes [free_slot].hwnd = hwnd;
nodes [free_slot].main_win = main_win;
nodes [free_slot].lock_count = 0;
#ifdef _MGSCHEMA_COMPOSITING
nodes [free_slot].changes = 0;
nodes [free_slot].ct = validate_compositing_type (flags, ct);
nodes [free_slot].ct_arg = ct_arg;
nodes [free_slot].mem_dc = mem_dc;
nodes [free_slot].dirty_rcs = NULL;
#else
nodes [free_slot].age = 1;
nodes [free_slot].dirty_rc.left = 0;
nodes [free_slot].dirty_rc.top = 0;
nodes [free_slot].dirty_rc.right = 0;
nodes [free_slot].dirty_rc.bottom = 0;
#endif
nodes [free_slot].idx_mask_rect = 0;
nodes [free_slot].priv_data = NULL;
#ifndef _MGSCHEMA_COMPOSITING
if ((flags & ZOF_TW_TROUNDCNS || flags & ZOF_TW_BROUNDCNS)) {
RECT cli_rect;
SetRect (&cli_rect, 0, 0, RECTW(nodes[free_slot].rc),
RECTH(nodes[free_slot].rc));
alloc_mask_rects_for_round_corners (&nodes[free_slot], flags, &cli_rect);
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
if (caption) {
/* Since 5.0.0, use strdup to duplicate the caption */
nodes[free_slot].caption = strdup (caption);
}
else {
nodes[free_slot].caption = NULL;
}
/* unlock zi for change ... */
unlock_zi_for_change (zi);
#ifdef _MGRM_PROCESSES
if (flags & ZOF_IF_SPECIAL) {
MG_Layer* layer = mgLayers;
while (layer) {
if (layer->zorder_info != zi) {
__mg_sync_special_nodes (zi, layer->zorder_info);
}
if (flags & ZOF_VISIBLE) {
update_on_new_visible_znode (layer, layer->zorder_info, free_slot, type);
}
layer = layer->next;
}
}
else if (flags & ZOF_VISIBLE) {
update_on_new_visible_znode (get_layer_from_client (cli), zi, free_slot, type);
}
#else
if (flags & ZOF_VISIBLE) {
update_on_new_visible_znode (NULL, zi, free_slot, type);
}
#endif
return free_slot;
}
static inline int AllocZOrderNode (int cli, HWND hwnd, HWND main_win,
DWORD flags, const RECT *rc, const char *caption,
HDC mem_dc, int fd, int ct, DWORD ct_arg)
{
return AllocZOrderNodeEx (get_zorder_info(cli), cli, hwnd, main_win,
flags, rc, caption, mem_dc, fd, ct, ct_arg);
}
static void prepare_to_delete_visible_znode (void* layer, ZORDERINFO* zi,
int idx_znode, DWORD type)
{
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
/* please lock zi for change*/
lock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
SetClipRgn (&sg_UpdateRgn, &nodes [idx_znode].rc);
/* check influenced zorder nodes */
if (nodes [idx_znode].flags & ZOF_VISIBLE) {
int slot, level;
RECT rc_screen = GetScreenRect ();
slot = nodes [idx_znode].next;
for (; slot > 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
subtract_rgn_by_node(&sg_UpdateRgn, zi, &nodes[slot])) {
nodes [slot].age++;
nodes [slot].flags |= ZOF_IF_REFERENCE;
}
}
/* Since 5.0.0 */
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
if (type > _zof_types_for_level[level]) {
slot = zi->first_in_levels[level];
for (; slot > 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
subtract_rgn_by_node(&sg_UpdateRgn, zi,
&nodes[slot])) {
nodes [slot].age++;
nodes [slot].flags |= ZOF_IF_REFERENCE;
}
}
}
}
if (SubtractClipRect (&sg_UpdateRgn, &rc_screen)) {
nodes [0].age++;
nodes [0].flags |= ZOF_IF_REFERENCE;
}
}
#else /* defined _MGSCHEMA_COMPOSITING */
if (nodes [idx_znode].flags & ZOF_VISIBLE) {
DO_COMPSOR_OP_ARGS (on_hiding_win, layer, idx_znode);
}
#endif /* defined _MGSCHEMA_COMPOSITING */
/* XXX: get next activable window znode before freeing the current znode */
zi->next_active = get_next_activable_mainwin (zi, idx_znode);
zi->old_active = zi->active_win;
if (idx_znode == zi->active_win)
zi->active_win = 0;
/* unlock zi for change */
unlock_zi_for_change (zi);
}
static void update_after_delete_visible_znode (void* layer, ZORDERINFO* zi, int idx_znode,
RECT *rc, DWORD flags)
{
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
#ifndef _MGSCHEMA_COMPOSITING
/* update all znode if it's dirty */
do_for_all_znodes (rc, zi, _cb_update_znode, ZT_ALL);
#else /* not defined _MGSCHEMA_COMPOSITING */
DO_COMPSOR_OP_ARGS (on_dirty_screen, layer, flags & ZOF_TYPE_FLAG_MASK, rc);
#endif /* defined _MGSCHEMA_COMPOSITING */
/* if active_win is this window, change it */
if (idx_znode == zi->old_active) {
dskSetActiveZOrderNode (zi, nodes [zi->next_active].cli, zi->next_active);
}
}
static int FreeZOrderNodeEx (ZORDERINFO* zi, int idx_znode, HDC* memdc)
{
DWORD flags, type;
RECT rc;
int level, *first = NULL, *nr_nodes = NULL;
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
flags = nodes [idx_znode].flags;
type = flags & ZOF_TYPE_MASK;
rc = nodes [idx_znode].rc;
#ifdef _MGHAVE_MENU
if (zi->cli_trackmenu >= 0 && flags & ZOF_VISIBLE)
srvForceCloseMenu (0);
#endif
/* Since 5.0.0 */
level = ZOF_TYPE_TO_LEVEL_IDX(type);
if (MG_UNLIKELY (level < 0 || level > ZLIDX_LAUNCHER)) {
assert (0);
return -1;
}
#ifdef _MGSCHEMA_COMPOSITING
if (memdc)
*memdc = nodes[idx_znode].mem_dc;
#endif
if (flags & ZOF_VISIBLE) {
#ifdef _MGRM_PROCESSES
if (flags & ZOF_IF_SPECIAL) {
MG_Layer* layer = mgLayers;
while (layer) {
prepare_to_delete_visible_znode (layer, layer->zorder_info,
idx_znode, type);
layer = layer->next;
}
}
else {
prepare_to_delete_visible_znode (get_layer_from_client (nodes[idx_znode].cli),
zi, idx_znode, type);
}
#else
prepare_to_delete_visible_znode (NULL, zi, idx_znode, type);
#endif
}
nodes = GET_ZORDERNODE(zi);
/* release and unchain the znode */
lock_zi_for_change (zi);
nodes [idx_znode].hwnd = HWND_NULL;
nodes [idx_znode].cli = -1;
/* Since 5.0.0, use strdup to duplicate the caption */
if (nodes[idx_znode].caption) {
free (nodes[idx_znode].caption);
nodes[idx_znode].caption = NULL;
}
/* Free mask rects */
if (nodes[idx_znode].idx_mask_rect) {
release_znode_maskrect (nodes, idx_znode);
}
unchain_znode ((unsigned char*)(zi+1), nodes, idx_znode);
first = zi->first_in_levels + level;
nr_nodes = zi->nr_nodes_in_levels + level;
if (*first == idx_znode) {
*first = nodes [idx_znode].next;
}
*nr_nodes -= 1;
unlock_zi_for_change (zi);
#ifdef _MGRM_PROCESSES
if (flags & ZOF_IF_SPECIAL) {
MG_Layer* layer = mgLayers;
while (layer) {
if (layer->zorder_info != zi) {
__mg_sync_special_nodes (zi, layer->zorder_info);
}
if (flags & ZOF_VISIBLE) {
update_after_delete_visible_znode (layer, layer->zorder_info,
idx_znode, &rc, flags);
}
layer = layer->next;
}
}
else if (flags & ZOF_VISIBLE) {
update_after_delete_visible_znode (get_layer_from_client (nodes[idx_znode].cli),
zi, idx_znode, &rc, flags);
}
#else
if (flags & ZOF_VISIBLE) {
update_after_delete_visible_znode (NULL, zi,
idx_znode, &rc, flags);
}
#endif
#ifndef _MGSCHEMA_COMPOSITING
if (flags & ZOF_VISIBLE) {
nodes = GET_ZORDERNODE(__mg_zorder_info);
if (nodes [0].flags & ZOF_IF_REFERENCE) {
SendMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0, (WPARAM)&rc);
nodes [0].flags &= ~ZOF_IF_REFERENCE;
}
}
#endif
return 0;
}
static inline int FreeZOrderNode (int cli, int idx_znode, HDC* memdc)
{
return FreeZOrderNodeEx (get_zorder_info(cli), idx_znode, memdc);
}
static DWORD get_znode_flags_from_style (PMAINWIN pWin)
{
DWORD zt_type = 0;
DWORD ex_styles;
if (pWin->dwStyle & WS_CHILD)
ex_styles = pWin->pMainWin->dwExStyle;
else
ex_styles = pWin->dwExStyle;
#ifdef _MGRM_PROCESSES
if (mgIsServer) {
/* Always be global ones */
zt_type |= ZOF_TYPE_GLOBAL;
} else
#endif
{
/* Since 5.0.0 */
switch (ex_styles & WS_EX_WINTYPE_MASK) {
case WS_EX_WINTYPE_TOOLTIP:
zt_type |= ZOF_TYPE_TOOLTIP;
break;
#ifndef _MGRM_PROCESSES
case WS_EX_WINTYPE_GLOBAL:
zt_type |= ZOF_TYPE_GLOBAL;
break;
#endif
case WS_EX_WINTYPE_SCREENLOCK:
zt_type |= ZOF_TYPE_SCREENLOCK;
break;
case WS_EX_WINTYPE_DOCKER:
zt_type |= ZOF_TYPE_DOCKER;
break;
case WS_EX_WINTYPE_LAUNCHER:
zt_type |= ZOF_TYPE_LAUNCHER;
break;
case WS_EX_WINTYPE_HIGHER:
zt_type |= ZOF_TYPE_HIGHER;
break;
default:
zt_type |= ZOF_TYPE_NORMAL;
break;
}
}
if (pWin->dwStyle & WS_CHILD) {
zt_type |= ZOF_TF_CONTROL;
}
else {
if (pWin->dwExStyle & WS_EX_TOOLWINDOW)
zt_type |= ZOF_TF_TOOLWIN;
else
zt_type |= ZOF_TF_MAINWIN;
/* XXX: Since 5.2.0 */
if (pWin->dwStyle & WS_MINIMIZE) {
zt_type |= ZOF_MINIMIZED;
}
else if (pWin->dwStyle & WS_MAXIMIZE) {
zt_type |= ZOF_MAXIMIZED;
}
if (pWin->dwStyle & WS_ALWAYSTOP)
zt_type |= ZOF_IF_ALWAYSTOP;
}
if (pWin->dwStyle & WS_VISIBLE) {
zt_type |= ZOF_VISIBLE;
}
if (pWin->dwStyle & WS_DISABLED)
zt_type |= ZOF_DISABLED;
if (pWin->dwExStyle & WS_EX_TROUNDCNS)
zt_type |= ZOF_TW_TROUNDCNS;
if (pWin->dwExStyle & WS_EX_BROUNDCNS)
zt_type |= ZOF_TW_BROUNDCNS;
return zt_type;
}
/* TODO: this function should be optimized to avoid allocating space for
invalid (empty) mask rectangles */
static int AllocZOrderMaskRect (int cli, int idx_znode,
int flags, const RECT4MASK *rc, const int nr_rc)
{
MASKRECT *firstmaskrect;
ZORDERNODE* nodes;
ZORDERINFO* zi = get_zorder_info(cli);
int free_slot, i, cur_idx, idx, old_num = 0;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
/* lock zi for change */
lock_zi_for_change (zi);
nodes = GET_ZORDERNODE(zi);
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
/*get mask rect number*/
idx = nodes[idx_znode].idx_mask_rect;
while (idx) {
old_num++;
idx = ((MASKRECT *)(firstmaskrect + idx))->next;
}
if (nr_rc > old_num) {
/* check the number of mask rect if enough */
int idle =
__mg_get_nr_idle_slots (GET_MASKRECT_USAGEBMP(__mg_def_zorder_info),
__mg_def_zorder_info->size_maskrect_usage_bmp);
if (idle < nr_rc - old_num) {
unlock_zi_for_change (zi);
return -1;
}
/*add new space to Znode*/
idx = nodes[idx_znode].idx_mask_rect;
for (i = 0; i < nr_rc - old_num; i++) {
free_slot = __mg_lookfor_unused_slot (
GET_MASKRECT_USAGEBMP(__mg_def_zorder_info),
__mg_def_zorder_info->size_maskrect_usage_bmp, 1);
if (free_slot == -1) {
unlock_zi_for_change (zi);
return -1;
}
(firstmaskrect+free_slot)->next = idx;
if (idx != 0) {
(firstmaskrect+idx)->prev = free_slot;
}
idx = free_slot;
}
if (idx != 0) {
(firstmaskrect+idx)->prev = 0;
}
}
else {
for(i =0; i < old_num-nr_rc; i++) {
idx = nodes[idx_znode].idx_mask_rect;
__mg_slot_clear_use(GET_MASKRECT_USAGEBMP(__mg_def_zorder_info), idx);
idx = ((MASKRECT *)(firstmaskrect+idx))->next;
}
}
nodes[idx_znode].idx_mask_rect = idx;
/* the slot must be larger than zero */
i = 0;
cur_idx = nodes[idx_znode].idx_mask_rect;
while(cur_idx) {
/* there is no slots in the bitmap */
(firstmaskrect+cur_idx)->left = rc[i].left;
(firstmaskrect+cur_idx)->top = rc[i].top;
(firstmaskrect+cur_idx)->right = rc[i].right;
(firstmaskrect+cur_idx)->bottom = rc[i].bottom;
cur_idx = (firstmaskrect+cur_idx)->next;
i++;
}
/* unlock zi for change ... */
unlock_zi_for_change (zi);
return 0;
}
static int FreeZOrderMaskRect (int cli, int idx_znode)
{
ZORDERINFO* zi = get_zorder_info(cli);
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
release_znode_maskrect (nodes, idx_znode);
return 0;
}
#ifndef _MGSCHEMA_COMPOSITING
static int update_client_window_rgn (int cli, HWND hwnd);
#endif
static int dskMove2Top (int cli, int idx_znode);
static int dskShowWindow (int cli, int idx_znode);
static int dskHideWindow (int cli, int idx_znode);
static ZORDERINFO* get_zorder_info (int cli);
#ifdef _MG_ENABLE_SCREENSAVER
static void dskRefreshAllClient (const RECT* invrc)
{
#if defined(_MGRM_PROCESSES)
if (mgIsServer) {
ZORDERINFO* zi = get_zorder_info (0);
SendMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0,
(LPARAM)(invrc));
lock_zi_for_read (zi);
SetClipRgn (&sg_UpdateRgn, invrc);
/* check influenced window zorder nodes */
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_ALL);
/* update all znode if it's dirty */
do_for_all_znodes ((void*)invrc, zi, _cb_update_znode, ZT_ALL);
unlock_zi_for_read (zi);
}
#endif
}
static int dskCreateTopZOrderNode (int cli, const RECT *rc)
{
int idx_znode = 0;
int zt_type = ZOF_VISIBLE | ZOF_TF_MAINWIN;
#if defined(_MGRM_PROCESSES)
if (mgIsServer) {
zt_type |= ZOF_TYPE_GLOBAL;
} else
#endif
zt_type |= ZOF_TYPE_TOOLTIP;
idx_znode = AllocZOrderNode (0, 0,
(HWND)0,
zt_type,
rc, "", HDC_SCREEN_SYS);
dskShowWindow (cli, idx_znode);
return idx_znode;
}
static int dskDestroyTopZOrderNode (int cli, int idx_znode)
{
return FreeZOrderNode (cli, idx_znode, NULL);
}
static int _screensaver_node;
void __mg_screensaver_show(void)
{
dskShowWindow (0, _screensaver_node);
dskMove2Top (0, _screensaver_node);
}
void __mg_screensaver_hide(void)
{
dskHideWindow (0, _screensaver_node);
}
void __mg_screensaver_create(void)
{
/* create screensaver node. */
if (!_screensaver_node) {
RECT rcScr = GetScreenRect();
_screensaver_node = dskCreateTopZOrderNode (0, &rcScr);
dskSetZNodeAlwaysTop (0, _screensaver_node, TRUE);
dskHideWindow (0, _screensaver_node);
}
}
void __mg_screensaver_destroy(void)
{
/* destroy screensaver node. */
if (_screensaver_node) {
dskDestroyTopZOrderNode(0, _screensaver_node);
_screensaver_node = 0;
}
}
#endif /* defined _MG_ENABLE_SCREENSAVER */
static int dskSetZNodeAlwaysTop (int cli, int idx_znode, BOOL fSet)
{
ZORDERINFO* zi = get_zorder_info (cli);
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
/* lock zi for change */
lock_zi_for_change (zi);
if (fSet) {
nodes[idx_znode].flags |= ZOF_IF_ALWAYSTOP;
}
else {
nodes[idx_znode].flags &= ~ZOF_IF_ALWAYSTOP;
}
/* unlock zi for change */
unlock_zi_for_change (zi);
dskMove2Top (cli, idx_znode);
return 0;
}
/* Since 5.0.6 */
static int dskSetZNodeGestureFlags (int cli, int idx_znode, DWORD flags)
{
ZORDERINFO* zi = get_zorder_info (cli);
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
flags &= ZOF_GESTURE_FLAGS_MASK;
lock_zi_for_change (zi);
nodes[idx_znode].flags &= ~ZOF_GESTURE_FLAGS_MASK;
nodes[idx_znode].flags |= flags;
unlock_zi_for_change (zi);
return 0;
}
#ifdef _MGSCHEMA_COMPOSITING
/* Since 5.0.0 */
static int dskSetZNodeCompositing (int cli, int idx_znode, int ct, DWORD ct_arg)
{
ZORDERINFO* zi = get_zorder_info (cli);
DWORD type;
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
type = nodes[idx_znode].flags & ZOF_TYPE_MASK;
if (type == ZOF_TYPE_NULL || type >= ZOF_TYPE_DESKTOP) {
return -1;
}
if ((nodes[idx_znode].ct == ct) && (nodes[idx_znode].ct_arg == ct_arg)) {
return 0;
}
/* lock zi for change */
lock_zi_for_change (zi);
nodes [idx_znode].ct = ct;
nodes [idx_znode].ct_arg = ct_arg;
DO_COMPSOR_OP_ARGS (on_changed_ct,
get_layer_from_client (cli), idx_znode);
/* unlock zi for change */
unlock_zi_for_change (zi);
return 0;
}
#endif /* defined _MGSCHEMA_COMPOSITING */
static int dskMove2Top (int cli, int idx_znode)
{
DWORD type;
ZORDERINFO* zi = get_zorder_info (cli);
int level, *first = NULL;
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
type = nodes [idx_znode].flags & ZOF_TYPE_MASK;
level = ZOF_TYPE_TO_LEVEL_IDX (type);
if (MG_UNLIKELY (level < 0 || level > ZLIDX_LAUNCHER)) {
assert (0);
return -1;
}
first = zi->first_in_levels + level;
assert (*first);
if (*first == idx_znode) // already at top
return 0;
#ifdef _MGHAVE_MENU
if (zi->cli_trackmenu >= 0)
srvForceCloseMenu (0);
#endif
/* lock zi for change */
lock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
EmptyClipRgn (&sg_UpdateRgn);
if (nodes [idx_znode].flags & ZOF_VISIBLE) {
int slot;
RECT rc = nodes [idx_znode].rc;
slot = zi->first_in_levels[level];
for (; slot != idx_znode; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
DoesIntersect (&rc, &nodes [slot].rc)) {
nodes [slot].age++;
AddClipRect(&sg_UpdateRgn, &nodes [slot].rc);
}
}
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
/* unchain it and move to top */
if (nodes [idx_znode].prev) {
nodes [nodes [idx_znode].prev].next = nodes [idx_znode].next;
}
if (nodes [idx_znode].next) {
nodes [nodes [idx_znode].next].prev = nodes [idx_znode].prev;
}
/* Since 5.0.0. Support for always top znode. */
if (!(nodes [*first].flags & ZOF_IF_ALWAYSTOP)) {
nodes [idx_znode].prev = nodes[*first].prev;
nodes [idx_znode].next = *first;
nodes [*first].prev = idx_znode;
*first = idx_znode;
}
else {
int pre_idx = *first;
while (*first) {
if (nodes [*first].flags & ZOF_IF_ALWAYSTOP) {
pre_idx = *first;
first = &nodes[*first].next;
}
else
break;
}
nodes [idx_znode].prev = pre_idx;
nodes [idx_znode].next = nodes [pre_idx].next;
nodes [nodes[pre_idx].next].prev = idx_znode;
nodes [pre_idx].next = idx_znode;
}
#ifndef _MGSCHEMA_COMPOSITING
nodes [idx_znode].age++;
#endif
/* unlock zi for change */
unlock_zi_for_change (zi);
#ifdef _MGRM_PROCESSES
if (nodes[idx_znode].flags & ZOF_IF_SPECIAL) {
MG_Layer* layer = mgLayers;
while (layer) {
if (layer->zorder_info != zi) {
__mg_sync_special_nodes (zi, layer->zorder_info);
}
#ifdef _MGSCHEMA_COMPOSITING
if (nodes [idx_znode].flags & ZOF_VISIBLE) {
DO_COMPSOR_OP_ARGS (on_raised_win, layer, idx_znode);
}
#endif
layer = layer->next;
}
}
#ifdef _MGSCHEMA_COMPOSITING
else if (nodes [idx_znode].flags & ZOF_VISIBLE) {
DO_COMPSOR_OP_ARGS (on_raised_win, get_layer_from_client (cli), idx_znode);
}
#endif
#endif /* defined _MGRM_PROCESSES */
#ifndef _MGSCHEMA_COMPOSITING
if ((nodes [idx_znode].flags & ZOF_VISIBLE) && nodes [idx_znode].hwnd) {
update_client_window_rgn (nodes [idx_znode].cli,
nodes [idx_znode].hwnd);
}
#endif
return 0;
}
static int dskShowWindow (int cli, int idx_znode)
{
DWORD type;
ZORDERINFO* zi = get_zorder_info(cli);
ZORDERNODE* nodes;
int level, *first = NULL;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
type = nodes [idx_znode].flags & ZOF_TYPE_MASK;
level = ZOF_TYPE_TO_LEVEL_IDX (type);
if (MG_UNLIKELY (level < 0 || level > ZLIDX_LAUNCHER)) {
assert (0);
return -1;
}
first = zi->first_in_levels + level;
assert (*first);
if (nodes [idx_znode].flags & ZOF_VISIBLE) {
_WRN_PRINTF ("showing a visible window (%s)\n",
nodes[idx_znode].caption);
return 0;
}
#ifdef _MGHAVE_MENU
if (zi->cli_trackmenu >= 0)
srvForceCloseMenu (0);
#endif
/* lock zi for change */
lock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
{
int slot;
RECT rc = nodes [idx_znode].rc;
RECT rc_screen = GetScreenRect();
if (type > ZOF_TYPE_LAUNCHER) {
do_for_all_znodes (&rc, zi, _cb_intersect_rc, ZT_LAUNCHER);
}
if (type > ZOF_TYPE_NORMAL) {
do_for_all_znodes (&rc, zi, _cb_intersect_rc, ZT_NORMAL);
}
if (type > ZOF_TYPE_HIGHER) {
do_for_all_znodes (&rc, zi, _cb_intersect_rc, ZT_HIGHER);
}
if (type > ZOF_TYPE_DOCKER) {
do_for_all_znodes (&rc, zi, _cb_intersect_rc, ZT_DOCKER);
}
if (type > ZOF_TYPE_SCREENLOCK) {
do_for_all_znodes (&rc, zi, _cb_intersect_rc, ZT_SCREENLOCK);
}
if (type > ZOF_TYPE_GLOBAL) {
do_for_all_znodes (&rc, zi, _cb_intersect_rc, ZT_GLOBAL);
}
if (type > ZOF_TYPE_TOOLTIP) {
// never touch here.
do_for_all_znodes (&rc, zi, _cb_intersect_rc, ZT_TOOLTIP);
}
slot = nodes [idx_znode].next;
for (; slot != 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
DoesIntersect (&rc, &nodes [slot].rc)) {
nodes [slot].age++;
}
}
if (DoesIntersect (&rc, &rc_screen)) {
nodes [0].age++;
}
nodes [idx_znode].age++;
nodes [idx_znode].flags |= ZOF_VISIBLE;
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
nodes [idx_znode].flags |= ZOF_VISIBLE;
/* unlock zi for change ... */
unlock_zi_for_change (zi);
#ifdef _MGRM_PROCESSES
if (nodes[idx_znode].flags & ZOF_IF_SPECIAL) {
MG_Layer* layer = mgLayers;
while (layer) {
if (layer->zorder_info != zi) {
__mg_sync_special_nodes (zi, layer->zorder_info);
}
#ifdef _MGSCHEMA_COMPOSITING
DO_COMPSOR_OP_ARGS (on_showing_win, layer, idx_znode);
#endif
layer = layer->next;
}
}
#ifdef _MGSCHEMA_COMPOSITING
else {
DO_COMPSOR_OP_ARGS (on_showing_win, get_layer_from_client (cli), idx_znode);
}
#endif
#endif /* defined _MGRM_PROCESSES */
return 0;
}
static int dskHideWindow (int cli, int idx_znode)
{
DWORD type;
ZORDERINFO* zi = get_zorder_info(cli);
int level, *first = NULL;
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
type = nodes [idx_znode].flags & ZOF_TYPE_MASK;
level = ZOF_TYPE_TO_LEVEL_IDX (type);
if (MG_UNLIKELY (level < 0 || level > ZLIDX_LAUNCHER)) {
assert (0);
return -1;
}
first = zi->first_in_levels + level;
assert (*first);
if (!(nodes[idx_znode].flags & ZOF_VISIBLE)) {
return 0;
}
#ifdef _MGHAVE_MENU
if (zi->cli_trackmenu >= 0)
srvForceCloseMenu (0);
#endif
/* lock zi for change */
lock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
/* check influenced zorder nodes */
SetClipRgn (&sg_UpdateRgn, &nodes [idx_znode].rc);
if (nodes [idx_znode].flags & ZOF_VISIBLE) {
int slot;
RECT rcScr = GetScreenRect ();
slot = nodes [idx_znode].next;
for (; slot > 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
subtract_rgn_by_node(&sg_UpdateRgn, zi, &nodes[slot])) {
nodes [slot].age++;
nodes [slot].flags |= ZOF_IF_REFERENCE;
}
}
if (type > ZOF_TYPE_GLOBAL) {
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_GLOBAL);
}
if (type > ZOF_TYPE_SCREENLOCK) {
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_SCREENLOCK);
}
if (type > ZOF_TYPE_DOCKER) {
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_DOCKER);
}
if (type > ZOF_TYPE_HIGHER) {
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_HIGHER);
}
if (type > ZOF_TYPE_NORMAL) {
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_NORMAL);
}
if (type > ZOF_TYPE_LAUNCHER) {
do_for_all_znodes (&sg_UpdateRgn, zi, _cb_update_rc, ZT_LAUNCHER);
}
if (SubtractClipRect (&sg_UpdateRgn, &rcScr)) {
nodes [0].age++;
nodes [0].flags |= ZOF_IF_REFERENCE;
}
}
#else /* not defined _MGSCHEMA_COMPOSITING */
DO_COMPSOR_OP_ARGS (on_hiding_win, get_layer_from_client (cli), idx_znode);
#endif /* defined _MGSCHEMA_COMPOSITING */
if (idx_znode && (nodes [idx_znode].flags & ZOF_TF_MAINWIN
&& (nodes [idx_znode].flags & ZOF_VISIBLE))) {
post_msg_by_znode_p (zi, nodes + idx_znode, MSG_NCACTIVATE, FALSE, 0);
post_msg_by_znode_p (zi, nodes + idx_znode, MSG_ACTIVE, FALSE, 0);
post_msg_by_znode_p (zi, nodes + idx_znode, MSG_KILLFOCUS, 0, 0);
}
nodes [idx_znode].flags &= ~ZOF_VISIBLE;
/*
* do not reset the age to zero.
* nodes [idx_znode].age = 0;
*/
/* unlock zi for change */
unlock_zi_for_change (zi);
#ifndef _MGSCHEMA_COMPOSITING
/* update all znode if it's dirty */
do_for_all_znodes (&nodes [idx_znode].rc, zi, _cb_update_znode, ZT_ALL);
if (nodes [0].flags & ZOF_IF_REFERENCE) {
SendMessage (HWND_DESKTOP,
MSG_ERASEDESKTOP, 0, (WPARAM)&nodes [idx_znode].rc);
nodes [0].flags &= ~ZOF_IF_REFERENCE;
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
#ifdef _MGRM_PROCESSES
if (nodes[idx_znode].flags & ZOF_IF_SPECIAL) {
MG_Layer* layer = mgLayers;
while (layer) {
if (layer->zorder_info != zi) {
__mg_sync_special_nodes (zi, layer->zorder_info);
}
#ifdef _MGSCHEMA_COMPOSITING
DO_COMPSOR_OP_ARGS (on_dirty_screen,
layer,
nodes [idx_znode].flags & ZOF_TYPE_FLAG_MASK,
&nodes [idx_znode].rc);
#endif
layer = layer->next;
}
}
#ifdef _MGSCHEMA_COMPOSITING
else {
DO_COMPSOR_OP_ARGS (on_dirty_screen,
get_layer_from_client (cli),
nodes [idx_znode].flags & ZOF_TYPE_FLAG_MASK,
&nodes [idx_znode].rc);
}
#endif
#endif /* defined _MGRM_PROCESSES */
return 0;
}
static int dskMoveWindow (int cli, int idx_znode, HDC memdc, int fd,
const RECT* rcWin)
{
DWORD type;
int level, *first = NULL;
ZORDERNODE* nodes;
#ifndef _MGSCHEMA_COMPOSITING
unsigned short idx;
MASKRECT *firstmaskrect;
int i, slot, nInvCount;
RECT rcInv[4], rcOld, rcInter, tmprc;
CLIPRGN bblt_rgn;
MASKRECT *maskrect;
#else
RECT org_rc;
#endif
ZORDERINFO* zi = get_zorder_info(cli);
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
type = nodes [idx_znode].flags & ZOF_TYPE_MASK;
level = ZOF_TYPE_TO_LEVEL_IDX (type);
if (MG_UNLIKELY (level < 0 || level > ZLIDX_LAUNCHER)) {
assert (0);
return -1;
}
first = zi->first_in_levels + level;
assert (*first);
if (memcmp (&nodes [idx_znode].rc, rcWin, sizeof (RECT)) == 0)
return 0;
#ifndef _MGSCHEMA_COMPOSITING
if ((RECTW(nodes[idx_znode].rc) != RECTWP(rcWin) ||
RECTH(nodes[idx_znode].rc) != RECTHP(rcWin)) &&
(nodes[idx_znode].flags & ZOF_TW_TROUNDCNS ||
nodes[idx_znode].flags & ZOF_TW_BROUNDCNS)) {
RECT cli_rect;
SetRect(&cli_rect, 0, 0, RECTWP(rcWin), RECTHP(rcWin));
lock_zi_for_change(zi);
if (nodes[idx_znode].idx_mask_rect != 0) {
idx = nodes[idx_znode].idx_mask_rect;
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
while (idx) {
__mg_slot_clear_use(GET_MASKRECT_USAGEBMP(__mg_def_zorder_info),
idx);
idx = ((MASKRECT *)(firstmaskrect+idx))->next;
}
}
alloc_mask_rects_for_round_corners (&nodes[idx_znode],
nodes[idx_znode].flags, &cli_rect);
unlock_zi_for_change(zi);
}
#endif /* not defined _MGSCHEMA_COMPOSITING */
#ifndef _MGSCHEMA_COMPOSITING
/* no need force to close the menu when moving a window
under compositing schema */
#ifdef _MGHAVE_MENU
if (nodes [idx_znode].flags & ZOF_VISIBLE && zi->cli_trackmenu >= 0)
srvForceCloseMenu (0);
#endif
nInvCount = SubtractRect (rcInv, &nodes [idx_znode].rc, rcWin);
if (nodes [idx_znode].flags & ZOF_VISIBLE) {
int level_from, level_to;
RECT rcScr = GetScreenRect ();
/* lock zi for change */
lock_zi_for_change (zi);
if (type > ZOF_TYPE_LAUNCHER) {
do_for_all_znodes ((void*)rcWin, zi, _cb_intersect_rc, ZT_LAUNCHER);
}
if (type > ZOF_TYPE_NORMAL) {
do_for_all_znodes ((void*)rcWin, zi, _cb_intersect_rc, ZT_NORMAL);
}
if (type > ZOF_TYPE_HIGHER) {
do_for_all_znodes ((void*)rcWin, zi, _cb_intersect_rc, ZT_HIGHER);
}
if (type > ZOF_TYPE_DOCKER) {
do_for_all_znodes ((void*)rcWin, zi, _cb_intersect_rc, ZT_DOCKER);
}
if (type > ZOF_TYPE_SCREENLOCK) {
do_for_all_znodes ((void*)rcWin, zi, _cb_intersect_rc, ZT_DOCKER);
}
if (type > ZOF_TYPE_GLOBAL) {
do_for_all_znodes ((void*)rcWin, zi, _cb_intersect_rc, ZT_GLOBAL);
}
slot = nodes [idx_znode].next;
for (; slot != 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
DoesIntersect (rcWin, &nodes [slot].rc)) {
nodes [slot].age++;
}
}
if (DoesIntersect (rcWin, &rcScr)) {
nodes [0].age++;
}
/* check influenced zorder nodes */
//SetClipRgn (&sg_UpdateRgn, rcInv + i);
SetClipRgn (&sg_UpdateRgn, &(nodes [idx_znode].rc));
/* znodes below current znode in the same level */
slot = nodes [idx_znode].next;
for (; slot > 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
!(nodes [slot].flags & ZOF_IF_REFERENCE) &&
subtract_rgn_by_node(&sg_UpdateRgn, zi, &nodes[slot])) {
nodes [slot].age++;
nodes [slot].flags |= ZOF_IF_REFERENCE;
}
}
/* znodes below current level */
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
if (type > _zof_types_for_level[level]) {
slot = zi->first_in_levels[level];
for (; slot > 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
!(nodes [slot].flags & ZOF_IF_REFERENCE) &&
subtract_rgn_by_node(&sg_UpdateRgn,
zi, &nodes[slot])) {
nodes [slot].age++;
nodes [slot].flags |= ZOF_IF_REFERENCE;
}
}
}
}
if (!(nodes [0].flags & ZOF_IF_REFERENCE) &&
SubtractClipRect (&sg_UpdateRgn, &rcScr)) {
nodes [0].age++;
nodes [0].flags |= ZOF_IF_REFERENCE;
}
rcOld = nodes [idx_znode].rc;
nodes [idx_znode].rc = *rcWin;
nodes [idx_znode].age++;
#if defined (_MGRM_PROCESSES)
if (cli == 0 || mgClients [cli].layer == SHAREDRES_TOPMOST_LAYER) {
#endif
/* Copy window content to new postion */
InitClipRgn (&bblt_rgn, &sg_FreeClipRectList);
if (nodes[idx_znode].idx_mask_rect == 0){
SelectClipRect (HDC_SCREEN_SYS, rcWin);
}
else {
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
idx = nodes [idx_znode].idx_mask_rect;
while (idx) {
maskrect = firstmaskrect + idx;
SetRect (&tmprc, rcWin->left + maskrect->left,
rcWin->top + maskrect->top,
rcWin->left + maskrect->right,
rcWin->top + maskrect->bottom);
if ( DoesIntersect (&tmprc, &rcScr)) {
IntersectRect (&tmprc, &tmprc, &rcScr);
AddClipRect (&bblt_rgn, &tmprc);
}
idx = maskrect->next;
}
SelectClipRegion(HDC_SCREEN_SYS, &bblt_rgn);
}
/* Since 5.0.0: handle all levels */
slot = 0;
level_from = -1;
level_to = -1;
switch (type) {
case ZOF_TYPE_TOOLTIP:
slot = zi->first_tooltip;
break;
case ZOF_TYPE_GLOBAL:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_TOOLTIP;
slot = zi->first_global;
break;
case ZOF_TYPE_SCREENLOCK:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_GLOBAL;
slot = zi->first_screenlock;
break;
case ZOF_TYPE_DOCKER:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_SCREENLOCK;
slot = zi->first_docker;
break;
case ZOF_TYPE_HIGHER:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_DOCKER;
slot = zi->first_topmost;
break;
case ZOF_TYPE_NORMAL:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_TOPMOST;
slot = zi->first_normal;
break;
case ZOF_TYPE_LAUNCHER:
level_from = ZLIDX_TOOLTIP;
level_to = ZLIDX_NORMAL;
slot = zi->first_launcher;
break;
case ZOF_TYPE_DESKTOP:
level_to = 0;
break;
default:
break;
}
if (level_from >= 0) {
for (level = level_from; level <= level_to; level++) {
do_for_all_znodes (NULL, zi, _cb_exclude_rc,
_zts_for_level[level]);
}
}
else if (level_to == 0) {
do_for_all_znodes (NULL, zi, _cb_exclude_rc, ZT_ALL);
}
while (slot) {
if (slot == idx_znode)
break;
/* houhh 20090730, if slot window is no regular.*/
if (nodes [slot].flags & ZOF_VISIBLE) {
if (nodes[slot].idx_mask_rect == 0) {
ExcludeClipRect (HDC_SCREEN_SYS, &nodes [slot].rc);
}
else {
RECT rc;
GetWindowRect(nodes [slot].hwnd, &rc);
firstmaskrect = GET_MASKRECT(__mg_def_zorder_info);
idx = nodes [slot].idx_mask_rect;
while (idx) {
maskrect = firstmaskrect + idx;
SetRect (&tmprc, rc.left + maskrect->left,
rc.top + maskrect->top,
rc.left + maskrect->right,
rc.top + maskrect->bottom);
if ( DoesIntersect (&tmprc, &rcScr)) {
IntersectRect (&tmprc, &tmprc, &rcScr);
ExcludeClipRect (HDC_SCREEN_SYS, &tmprc);
}
idx = maskrect->next;
}
}
}
slot = nodes [slot].next;
}
BitBlt (HDC_SCREEN_SYS, rcOld.left, rcOld.top,
MIN (RECTWP (rcWin), RECTW (rcOld)),
MIN (RECTHP (rcWin), RECTH (rcOld)),
HDC_SCREEN_SYS, rcWin->left, rcWin->top, 0);
SyncUpdateDC (HDC_SCREEN_SYS);
/* Restore the clip region of HDC_SCREEN_SYS */
SelectClipRect (HDC_SCREEN_SYS, &rcScr);
EmptyClipRgn(&bblt_rgn);
#if defined (_MGRM_PROCESSES)
}
#endif
do_for_all_znodes (&rcOld, zi, _cb_update_znode, ZT_ALL);
/* unlock zi for change ... */
unlock_zi_for_change (zi);
if (nodes [0].flags & ZOF_IF_REFERENCE) {
SendMessage (HWND_DESKTOP,
MSG_ERASEDESKTOP, 0, (LPARAM)&rcOld);
nodes [0].flags &= ~ZOF_IF_REFERENCE;
}
/* check the invalid rectangles of the being moved window */
EmptyClipRgn (&sg_UpdateRgn);
nInvCount = SubtractRect (rcInv, &rcOld, &rcScr);
for (i = 0; i < nInvCount; i++) {
AddClipRect (&sg_UpdateRgn, rcInv + i);
}
/* Since 5.0.0: handle levels above the current level */
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
if (type < _zof_types_for_level[level]) {
slot = zi->first_in_levels[level];
for (; slot > 0; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
IntersectRect (&rcInter, &rcOld, &nodes [slot].rc))
AddClipRect (&sg_UpdateRgn, &rcInter);
}
}
}
/* handle znodes above the current znode */
slot = *first;
for (; slot != idx_znode; slot = nodes [slot].next) {
if (nodes [slot].flags & ZOF_VISIBLE &&
IntersectRect (&rcInter, &rcOld, &nodes [slot].rc))
AddClipRect(&sg_UpdateRgn, &rcInter);
}
OffsetRegion (&sg_UpdateRgn,
rcWin->left - rcOld.left,
rcWin->top - rcOld.top);
update_client_window_rgn (nodes [idx_znode].cli,
nodes [idx_znode].hwnd);
}
else {
lock_zi_for_change (zi);
nodes [idx_znode].rc = *rcWin;
nodes [idx_znode].age++;
unlock_zi_for_change (zi);
}
#else /* not defined _MGSCHEMA_COMPOSITING */
{
lock_zi_for_change (zi);
org_rc = nodes [idx_znode].rc;
nodes [idx_znode].rc = *rcWin;
if (memdc != HDC_INVALID) {
DeleteMemDC (nodes [idx_znode].mem_dc);
nodes [idx_znode].mem_dc = memdc;
}
unlock_zi_for_change (zi);
}
#endif /* defined _MGSCHEMA_COMPOSITING */
#ifdef _MGRM_PROCESSES
if (nodes[idx_znode].flags & ZOF_IF_SPECIAL) {
MG_Layer* layer = mgLayers;
while (layer) {
if (layer->zorder_info != zi) {
__mg_sync_special_nodes (zi, layer->zorder_info);
}
#ifdef _MGSCHEMA_COMPOSITING
DO_COMPSOR_OP_ARGS (on_moved_win, layer, idx_znode, &org_rc);
#endif
layer = layer->next;
}
}
#ifdef _MGSCHEMA_COMPOSITING
else {
DO_COMPSOR_OP_ARGS (on_moved_win,
get_layer_from_client (cli), idx_znode, &org_rc);
}
#endif
#endif /* defined _MGRM_PROCESSES */
return 0;
}
static int dskEnableZOrderNode (int cli, int idx_znode, int flags)
{
ZORDERINFO* zi = get_zorder_info(cli);
ZORDERNODE* nodes;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
nodes = GET_ZORDERNODE(zi);
/* lock zi for change */
lock_zi_for_change (zi);
if (flags) /* enable window */
nodes [idx_znode].flags &= ~ZOF_DISABLED;
else
nodes [idx_znode].flags |= ZOF_DISABLED;
/* unlock zi for change */
unlock_zi_for_change (zi);
return 0;
}
/*======================== customize desktop =========================*/
#ifndef _MGSCHEMA_COMPOSITING
static void
def_paint_desktop (void* context, HDC dc_desktop, const RECT* inv_rc)
{
PBITMAP bg_bmp = NULL;
int pic_x = 0, pic_y = 0;
RECT rcScr = GetScreenRect ();
if(context)
{
bg_bmp = ((DEF_CONTEXT *)context)->bg;
pic_x = ((DEF_CONTEXT *)context)->x;
pic_y = ((DEF_CONTEXT *)context)->y;
}
SetBrushColor (dc_desktop,
GetWindowElementPixelEx (HWND_DESKTOP, HDC_SCREEN, WE_BGC_DESKTOP));
if (inv_rc) {
SelectClipRect (dc_desktop, inv_rc);
FillBox (dc_desktop, inv_rc->left, inv_rc->top,
RECTWP (inv_rc), RECTHP (inv_rc));
}
else {
SelectClipRect (dc_desktop, &rcScr);
FillBox(dc_desktop, rcScr.left, rcScr.top,
rcScr.right, rcScr.bottom);
}
if (bg_bmp) {
FillBoxWithBitmap (dc_desktop, pic_x, pic_y,
bg_bmp->bmWidth, bg_bmp->bmHeight, bg_bmp);
}
SyncUpdateDC (dc_desktop);
}
#endif /* !_MGSCHEMA_COMPOSITING */
static inline void def_keyboard_handler (void* context,
int message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case MSG_DT_KEYLONGPRESS:
case MSG_DT_KEYALWAYSPRESS:
case MSG_DT_KEYDOWN:
case MSG_DT_CHAR:
case MSG_DT_KEYUP:
case MSG_DT_SYSKEYDOWN:
case MSG_DT_SYSCHAR:
case MSG_DT_SYSKEYUP:
break;
}
}
#define IDC_DTI_ABOUT (IDM_DTI_FIRST)
static void def_customize_desktop_menu (void* context,
HMENU hmnu, int start_pos)
{
#if defined(_MGMISC_ABOUTDLG) && defined(_MGHAVE_MENU)
MENUITEMINFO mii;
memset (&mii, 0, sizeof(MENUITEMINFO));
mii.type = MFT_STRING;
mii.id = IDC_DTI_ABOUT;
mii.typedata = (DWORD)GetSysText(IDS_MGST_ABOUTMG);
mii.hsubmenu = 0;
InsertMenuItem (hmnu, start_pos, TRUE, &mii);
#endif
}
static void def_mouse_handler(void* context, int message,
WPARAM wParam, LPARAM lParam)
{
#ifdef _MGHAVE_MENU
int x, y;
switch (message) {
case MSG_DT_LBUTTONDOWN:
case MSG_DT_LBUTTONUP:
case MSG_DT_LBUTTONDBLCLK:
case MSG_DT_MOUSEMOVE:
case MSG_DT_RBUTTONDOWN:
case MSG_DT_RBUTTONDBLCLK:
break;
case MSG_DT_RBUTTONUP: {
x = LOSWORD (lParam);
y = HISWORD (lParam);
TrackPopupMenu (sg_DesktopMenu, TPM_DEFAULT, x, y, HWND_DESKTOP);
break;
}
default:
break;
}
#endif
}
static void def_desktop_menucmd_handler (void* context, int id)
{
#ifdef _MGMISC_ABOUTDLG
if (id == IDC_DTI_ABOUT) {
#ifdef _MGRM_THREADS
OpenAboutDialog ();
#else
OpenAboutDialog (HWND_DESKTOP);
#endif
}
#endif
}
static void def_deinit(void* context)
{
if (context) {
if (((DEF_CONTEXT *)context)->bg)
UnloadBitmap (((DEF_CONTEXT *)context)->bg);
#if defined(_MGRM_THREADS) || defined(_MGRM_STANDALONE)
free(context);
#endif
}
return;
}
static int dskGetBgPicturePos (void)
{
char szValue [21];
if (GetMgEtcValue (__mg_def_renderer->name,
SYSBMP_BGPICPOS, szValue, 20) < 0) {
strcpy (szValue, "center");
}
if (!strcmp (szValue, "none"))
return -1;
if (!strcmp (szValue, "center"))
return 0;
if (!strcmp (szValue, "upleft"))
return 1;
if (!strcmp (szValue, "downleft"))
return 2;
if (!strcmp (szValue, "upright"))
return 3;
if (!strcmp (szValue, "downright"))
return 4;
if (!strcmp (szValue, "upcenter"))
return 5;
if (!strcmp (szValue, "downcenter"))
return 6;
if (!strcmp (szValue, "vcenterleft"))
return 7;
if (!strcmp (szValue, "vcenterright"))
return 8;
return -1;
}
static PBITMAP dskLoadBgPicture (HDC hdc)
{
return (PBITMAP)GetSystemBitmapEx2 (hdc, __mg_def_renderer->name,
SYSBMP_BGPICTURE);
}
static void dskGetBgPictureXY (int pos, int w, int h, int* x, int* y)
{
switch (pos) {
case 0: // center
*x = (g_rcScr.right - w) >> 1;
*y = (g_rcScr.bottom - h) >> 1;
break;
case 1: // upleft
*x = 0;
*y = 0;
break;
case 2: // downleft
*x = 0;
*y = g_rcScr.bottom - h;
break;
case 3: // upright
*x = g_rcScr.right - w;
*y = 0;
break;
case 4: // downright
*x = g_rcScr.right - w;
*y = g_rcScr.bottom - h;
break;
case 5: // upcenter
*x = (g_rcScr.right - w) >> 1;
*y = 0;
break;
case 6: // downcenter
*x = (g_rcScr.right - w) >> 1;
*y = g_rcScr.bottom - h;
break;
case 7: // vcenterleft
*x = 0;
*y = (g_rcScr.bottom - h) >> 1;
break;
case 8: // vcenterright
*x = g_rcScr.right - w;
*y = (g_rcScr.bottom - h) >> 1;
break;
default:
*x = 0;
*y = 0;
break;
}
}
static void* def_init (HDC dc_desktop)
{
PBITMAP bg_bmp = NULL;
int pic_x = 0, pic_y = 0;
DEF_CONTEXT *con;
int pos;
#if defined (_MGRM_THREADS) || defined (_MGRM_STANDALONE)
con = malloc(sizeof(DEF_CONTEXT));
#else
con = &g_def_context;
#endif
pos = dskGetBgPicturePos ();
if (pos < 0)
bg_bmp = NULL;
else
bg_bmp = dskLoadBgPicture (dc_desktop);
if (bg_bmp)
dskGetBgPictureXY (pos,
bg_bmp->bmWidth, bg_bmp->bmHeight, &pic_x, &pic_y);
con->bg = bg_bmp;
con->x = pic_x;
con->y = pic_y;
return (void *)con;
}
static DESKTOPOPS def_dsk_ops =
{
def_init,
def_deinit,
#ifdef _MGSCHEMA_COMPOSITING
NULL,
#else
def_paint_desktop,
#endif
def_keyboard_handler,
def_mouse_handler,
def_customize_desktop_menu,
def_desktop_menucmd_handler,
};
static DESKTOPOPS *dsk_ops = &def_dsk_ops;
static void *dt_context;
DESKTOPOPS* GUIAPI SetCustomDesktopOperationSet (DESKTOPOPS* usr_dsk_ops)
{
DESKTOPOPS *tmp_ops = NULL;
if (usr_dsk_ops == NULL) {
return dsk_ops;
}
if (dsk_ops->deinit) {
dsk_ops->deinit (dt_context);
}
tmp_ops = dsk_ops;
dsk_ops = usr_dsk_ops;
/* Since 5.0.0 */
SendMessage (HWND_DESKTOP, MSG_REINITDESKOPS, 0, 0);
return tmp_ops;
}
static BOOL _cb_bcast_msg (void* context,
const ZORDERINFO* zi, ZORDERNODE* node)
{
PMAINWIN pWin;
PMSG pMsg = (PMSG)context;
#if defined(_MGRM_PROCESSES)
if (node->cli == __mg_client_id) {
#endif
pWin = (PMAINWIN)node->hwnd;
if (pWin && pWin->WinType != TYPE_CONTROL) {
PostMessage ((HWND)pWin, pMsg->message, pMsg->wParam, pMsg->lParam);
return TRUE;
}
#if defined(_MGRM_PROCESSES)
}
#endif
return FALSE;
}
static int dskBroadcastMessage (PMSG pMsg)
{
int count = 0;
lock_zi_for_read (__mg_zorder_info);
count = do_for_all_znodes (pMsg, __mg_zorder_info, _cb_bcast_msg, ZT_ALL);
unlock_zi_for_read (__mg_zorder_info);
return count;
}
static int dskSetIMEStatus (int iIMEStatusCode, int Value)
{
if (__mg_ime_wnd == 0)
return ERR_IME_NOIMEWND;
switch (iIMEStatusCode) {
case IME_STATUS_REGISTERED:
return 0;
case IME_STATUS_ENABLED:
__mg_ime_status_info.bEnabled = Value;
SendNotifyMessage (__mg_ime_wnd,
Value == 1? MSG_IME_OPEN : MSG_IME_CLOSE,
0, 0);
return 0;
case IME_STATUS_AUTOTRACK:
__mg_ime_status_info.bAutoTrack = Value;
return 0;
case IME_STATUS_LANGUAGE:
case IME_STATUS_ENCODING:
return SendMessage (__mg_ime_wnd,
MSG_IME_SETSTATUS, iIMEStatusCode, Value);
default:
if (iIMEStatusCode >= IME_STATUS_USER_MIN
&& iIMEStatusCode <= IME_STATUS_USER_MAX)
return SendMessage (__mg_ime_wnd,
MSG_IME_SETSTATUS, iIMEStatusCode, Value);
}
return ERR_NO_MATCH;
}
static int dskGetIMEStatus (int iIMEStatusCode)
{
if (__mg_ime_wnd == 0) {
if (iIMEStatusCode == IME_STATUS_REGISTERED)
return 0;
else
return ERR_IME_NOIMEWND;
}
switch (iIMEStatusCode) {
case IME_STATUS_REGISTERED:
return 1;
case IME_STATUS_ENABLED:
return __mg_ime_status_info.bEnabled;
case IME_STATUS_AUTOTRACK:
return __mg_ime_status_info.bAutoTrack;
case IME_STATUS_LANGUAGE:
case IME_STATUS_ENCODING:
case IME_STATUS_VERSION:
return SendMessage (__mg_ime_wnd,
MSG_IME_GETSTATUS, iIMEStatusCode, 0);
default:
if (iIMEStatusCode >= IME_STATUS_USER_MIN
&& iIMEStatusCode <= IME_STATUS_USER_MAX)
return SendMessage (__mg_ime_wnd,
MSG_IME_GETSTATUS, iIMEStatusCode, 0);
}
return ERR_NO_MATCH;
}
static int dskSetIMETargetInfo (const IME_TARGET_INFO *info)
{
if (__mg_ime_wnd == 0)
return ERR_IME_NOIMEWND;
memcpy (&__mg_ime_status_info.TargetInfo, info, sizeof (IME_TARGET_INFO));
if (__mg_ime_status_info.bAutoTrack) {
int ret;
ret = dskGetIMEStatus (IME_STATUS_VERSION);
if (ret) {
PostMessage (__mg_ime_wnd, MSG_IME_SET_TARGET_INFO,
0, (LPARAM)&__mg_ime_status_info.TargetInfo);
} else {
PostMessage (__mg_ime_wnd, MSG_IME_SETPOS,
0, (LPARAM)&__mg_ime_status_info.TargetInfo.ptCaret);
}
}
return ERR_OK;
}
static int dskGetIMETargetInfo (IME_TARGET_INFO *info)
{
if (__mg_ime_wnd == 0)
return ERR_IME_NOIMEWND;
*info = __mg_ime_status_info.TargetInfo;
return ERR_OK;
}
int __kernel_get_window_region (HWND pWin, CLIPRGN* region)
{
RECT rc;
MASKRECT *maskrect;
ZORDERNODE* nodes;
ZORDERINFO* zi;
int idx_znode, idx, nr_mask_rects;
#if defined(_MGRM_THREADS) || defined(_MGRM_STANDALONE)
zi = get_zorder_info (0);
#else
zi = get_zorder_info (__mg_client_id);
#endif
idx_znode = ((PMAINWIN)pWin)->idx_znode;
if (IS_INVALID_ZIDX (zi, idx_znode)) {
return -1;
}
EmptyClipRgn (region);
/* lock zi for read */
lock_zi_for_read (zi);
nr_mask_rects = 0;
nodes = GET_ZORDERNODE(zi);
maskrect = GET_MASKRECT(__mg_def_zorder_info);
idx = nodes[idx_znode].idx_mask_rect;
while (idx) {
rc.left = maskrect->left;
rc.top = maskrect->top;
rc.right = maskrect->left;
rc.bottom = maskrect->bottom;
if (!AddClipRect (region, &rc)) {
nr_mask_rects = -1;
goto __mg_err_ret;
}
idx = maskrect->next;
nr_mask_rects ++;
}
if (nr_mask_rects == 0) {
rc = nodes [idx_znode].rc;
/* VW: 2020-02-02: bad call to `OffsetRect (&rc, rc.left, rc.top);` */
OffsetRect (&rc, -rc.left, -rc.top);
if (!SetClipRgn (region, &rc))
nr_mask_rects = -1;
}
__mg_err_ret:
/* unlock zi for read */
unlock_zi_for_read (zi);
return nr_mask_rects;
}
/*********************** Hook support ****************************************/
static HOOKINFO keyhook;
static HOOKINFO mousehook;
static HOOKINFO extrahook;
static MSGHOOK dskRegisterHookFunc (int event_type, HOOKINFO* info)
{
MSGHOOK old_hook = NULL;
switch (event_type) {
case HOOK_EVENT_KEY:
old_hook = keyhook.hook;
keyhook.context = info->context;
keyhook.hook = info->hook;
break;
case HOOK_EVENT_MOUSE:
old_hook = mousehook.hook;
mousehook.context = info->context;
mousehook.hook = info->hook;
break;
case HOOK_EVENT_EXTRA:
old_hook = extrahook.hook;
extrahook.context = info->context;
extrahook.hook = info->hook;
break;
default:
break;
}
return old_hook;
}
#if 0 /* deprecated code since 5.0.0 */
static int dskHandleKeyHooks (HWND dst_wnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
int ret = HOOK_GOON;
if (keyhook.hook) {
ret = keyhook.hook (keyhook.context, dst_wnd, message, wParam, lParam);
}
return ret;
}
static int dskHandleMouseHooks (HWND dst_wnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
int ret = HOOK_GOON;
if (mousehook.hook) {
ret = mousehook.hook (mousehook.context, dst_wnd,
message, wParam, lParam);
}
return ret;
}
#endif /* deprecated code since 5.0.0 */
/* Since 5.0.0; return non zero to STOP handling the message */
static inline int
dskPreKeyMessageHandler (UINT message, WPARAM wparam, LPARAM lparam)
{
if (__mg_check_hook_wins (HOOK_EVENT_KEY, message, wparam, lparam))
return HOOK_STOP;
return HOOK_GOON;
}
/* Since 5.0.0; return non zero to STOP handling the message */
static inline int
dskPreMouseMessageHandler (UINT message, WPARAM wparam, LPARAM lparam)
{
if (__mg_check_hook_wins (HOOK_EVENT_MOUSE, message, wparam, lparam))
return HOOK_STOP;
return HOOK_GOON;
}
/* Since 5.0.0; return non zero to STOP handling the message */
static inline int
dskPreExtraMessageHandler (UINT message, WPARAM wparam, LPARAM lparam)
{
if (__mg_check_hook_wins (HOOK_EVENT_EXTRA, message, wparam, lparam))
return HOOK_STOP;
return HOOK_GOON;
}
#include "list.h"
typedef struct _HOOKWININFO {
struct list_head list;
HWND hwnd;
int flags;
int cli;
} HOOKWININFO;
static struct list_head hook_win_list = { &hook_win_list, &hook_win_list };
static int dskRegisterHookWin (int cli, HWND hwnd, DWORD flags)
{
struct list_head *info;
HOOKWININFO *new_hook_info;
list_for_each (info, &hook_win_list) {
HOOKWININFO *hook_info = (HOOKWININFO*)info;
if (hook_info->cli == cli && hook_info->hwnd == hwnd) {
return -1;
}
}
if ((new_hook_info = mg_slice_new (HOOKWININFO)) == NULL)
return -1;
new_hook_info->cli = cli;
new_hook_info->hwnd = hwnd;
new_hook_info->flags = (int)flags;
list_add_tail (&new_hook_info->list, &hook_win_list);
return 0;
}
static int dskUnregisterHookWin (int cli, HWND hwnd)
{
struct list_head *info;
HOOKWININFO *hook_info_got = NULL;
list_for_each (info, &hook_win_list) {
HOOKWININFO *hook_info = (HOOKWININFO*)info;
if (hook_info->cli == cli && hook_info->hwnd == hwnd) {
hook_info_got = hook_info;
break;
}
}
if (hook_info_got == NULL)
return -1;
list_del (&hook_info_got->list);
mg_slice_delete (HOOKWININFO, hook_info_got);
return 0;
}
/* this should be called before queuing the event messages to DESKTOP */
int __mg_check_hook_func (int event_type, const MSG* msg)
{
HOOKINFO* info = NULL;
switch (event_type) {
case HOOK_EVENT_KEY:
info = &keyhook;
break;
case HOOK_EVENT_MOUSE:
info = &mousehook;
break;
case HOOK_EVENT_EXTRA:
info = &extrahook;
break;
default:
break;
}
if (info && info->hook) {
return info->hook (info->context, msg->hwnd,
msg->message, msg->wParam, msg->lParam);
}
return HOOK_GOON;
}
/* this should be called in the context of DESKTOP thread */
int __mg_check_hook_wins (int event_type,
UINT uMsg, WPARAM wParam, LPARAM lParam)
{
struct list_head *info;
int op = HOOK_GOON;
#ifdef _MGRM_PROCESSES
if (!mgIsServer) {
return HOOK_GOON;
}
#endif
list_for_each (info, &hook_win_list) {
HOOKWININFO *hook_info = (HOOKWININFO*)info;
if ((hook_info->flags & HOOK_EVENT_MASK) == event_type) {
op = hook_info->flags & HOOK_OP_MASK;
#ifdef _MGRM_PROCESSES
if (hook_info->cli != 0) {
MSG msg = { hook_info->hwnd, uMsg, wParam, lParam };
__mg_send2client (&msg, mgClients + hook_info->cli);
}
else {
PostMessage (hook_info->hwnd, uMsg, wParam, lParam);
}
#else
PostMessage (hook_info->hwnd, uMsg, wParam, lParam);
#endif
if (op == HOOK_STOP)
break;
}
}
return op;
}
/* Since 5.0.0; free all if cli < 0 */
int __mg_free_hook_wins (int cli)
{
int nr = 0;
struct list_head *info, *tmp;
list_for_each_safe (info, tmp, &hook_win_list) {
HOOKWININFO *hook_info = (HOOKWININFO*)info;
if (cli < 0 || hook_info->cli == cli) {
list_del (&hook_info->list);
mg_slice_delete (HOOKWININFO, hook_info);
nr++;
}
}
return nr;
}
#ifdef _MGHAVE_VIRTUAL_WINDOW
static struct list_head msg_queue_list = { &msg_queue_list, &msg_queue_list };
static inline int dskRegisterMsgQueue (MSGQUEUE* msg_queue)
{
list_add_tail (&msg_queue->list, &msg_queue_list);
return 0;
}
static int dskUnregisterMsgQueue (MSGQUEUE* msg_queue)
{
struct list_head *l;
MSGQUEUE *msg_queue_got = NULL;
list_for_each (l, &msg_queue_list) {
if (msg_queue == (MSGQUEUE*)l) {
msg_queue_got = (MSGQUEUE*)l;
break;
}
}
if (msg_queue_got == NULL)
return -1;
list_del (&msg_queue->list);
return 0;
}
#include "debug.h"
int __mg_join_all_message_threads (void)
{
int nr = 0;
struct list_head *l, *tmp;
void* res;
pthread_t th = pthread_self();
list_for_each (l, &msg_queue_list) {
MSGQUEUE *msg_queue = (MSGQUEUE*)l;
#ifndef NDEBUG
dump_message_queue (msg_queue, __func__);
#endif
pthread_cancel (msg_queue->th);
}
list_for_each_safe (l, tmp, &msg_queue_list) {
MSGQUEUE *msg_queue = (MSGQUEUE*)l;
if (th == msg_queue->th) {
continue;
}
pthread_join (msg_queue->th, &res);
if (res == PTHREAD_CANCELED) {
list_del (&msg_queue->list);
mg_DestroyMsgQueue (msg_queue);
free (msg_queue);
nr++;
}
}
return nr;
}
static inline int post_quit_to_all_message_threads (BOOL no_self)
{
int nr = 0;
struct list_head *l;
pthread_t th = pthread_self();
list_for_each (l, &msg_queue_list) {
MSGQUEUE *msg_queue = (MSGQUEUE*)l;
dump_message_queue (msg_queue, __func__);
if (no_self && th == msg_queue->th) {
continue;
}
msg_queue->dwState |= QS_QUIT;
POST_MSGQ (msg_queue);
nr++;
}
return nr;
}
#endif /* defined _MGHAVE_VIRTUAL_WINDOW */
/* Since 5.0.0 */
static int dskCalculateDefaultPosition (int cli, CALCPOSINFO* info)
{
ZORDERINFO* zi;
ZORDERNODE* nodes;
DWORD zt_type = ZOF_TYPE_NULL;
int level, first;
zi = get_zorder_info (cli);
nodes = GET_ZORDERNODE(zi);
#ifdef _MGRM_PROCESSES
if (cli == 0)
zt_type = ZOF_TYPE_GLOBAL;
else
#endif
switch (info->ex_style & WS_EX_WINTYPE_MASK) {
case WS_EX_WINTYPE_TOOLTIP:
zt_type = ZOF_TYPE_TOOLTIP;
break;
#ifdef _MGRM_PROCESSES
case WS_EX_WINTYPE_GLOBAL:
zt_type = ZOF_TYPE_GLOBAL;
break;
#endif
case WS_EX_WINTYPE_SCREENLOCK:
zt_type = ZOF_TYPE_SCREENLOCK;
break;
case WS_EX_WINTYPE_DOCKER:
zt_type = ZOF_TYPE_DOCKER;
break;
case WS_EX_WINTYPE_LAUNCHER:
zt_type = ZOF_TYPE_LAUNCHER;
break;
case WS_EX_WINTYPE_HIGHER:
zt_type = ZOF_TYPE_HIGHER;
break;
default:
zt_type = ZOF_TYPE_NORMAL;
break;
}
#ifdef _MGRM_PROCESSES
/* check the special types */
switch (zt_type) {
/* Since 5.0.6: tooltips are not special znodes
case ZOF_TYPE_TOOLTIP:
if (zi->first_tooltip > 0 &&
nodes [zi->first_tooltip].cli != cli) {
zt_type = ZOF_TYPE_HIGHER;
}
break;
*/
case ZOF_TYPE_GLOBAL:
if (cli != 0) {
zt_type = ZOF_TYPE_HIGHER;
}
break;
case ZOF_TYPE_SCREENLOCK:
if (zi->first_screenlock > 0 &&
nodes [zi->first_screenlock].cli != cli) {
zt_type = ZOF_TYPE_HIGHER;
}
break;
case ZOF_TYPE_DOCKER:
if (zi->first_docker > 0 &&
nodes [zi->first_docker].cli != cli) {
zt_type = ZOF_TYPE_HIGHER;
}
break;
case ZOF_TYPE_LAUNCHER:
if (zi->first_launcher > 0 &&
nodes [zi->first_launcher].cli != cli) {
zt_type = ZOF_TYPE_NORMAL;
}
break;
}
#endif /* defined _MGRM_PROCESSES */
level = ZOF_TYPE_TO_LEVEL_IDX (zt_type);
first = zi->first_in_levels[level];
#ifdef _MGSCHEMA_COMPOSITING /* not defined _MGSCHEMA_COMPOSITING */
DO_COMPSOR_OP_ARGS (calc_mainwin_pos,
get_layer_from_client (cli), zt_type, first, cli, info);
#else /* defined _MGSCHEMA_COMPOSITING */
/* give a default size first */
if (IsRectEmpty (&info->rc)) {
info->rc.left = 0;
info->rc.top = 0;
if (info->ex_style & WS_EX_DIALOGBOX) {
info->rc.right = g_rcScr.right / 2;
info->rc.bottom = g_rcScr.bottom / 3;
}
else {
info->rc.right = g_rcScr.right / 2;
info->rc.bottom = g_rcScr.bottom;
}
}
if (info->ex_style & WS_EX_DIALOGBOX) {
// center the window vertically and horinzontally
int width = info->rc.right - info->rc.left;
int height = info->rc.bottom - info->rc.top;
OffsetRect (&info->rc, (g_rcScr.right - width) >> 1,
(g_rcScr.bottom - height) >> 1);
}
else {
if (first == 0) {
info->rc.left = 0;
info->rc.top = 0;
}
else {
info->rc = nodes[first].rc;
OffsetRect (&info->rc,
DEF_OVERLAPPED_OFFSET_X, DEF_OVERLAPPED_OFFSET_Y);
/* adjust to a reasonable postion */
if (info->rc.top > (g_rcScr.bottom * 3 / 4)) {
OffsetRect (&info->rc, 0, -info->rc.top);
}
if (info->rc.left > (g_rcScr.right * 3 / 4)) {
OffsetRect (&info->rc, -info->rc.left, 0);
}
}
}
#endif /* defined _MGSCHEMA_COMPOSITING */
return 0;
}
static int dskDumpZOrder (ZORDERINFO* zi)
{
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
int from = 0;
int nr = 0;
lock_zi_for_read (zi);
from = __kernel_get_next_znode (zi, from);
while (from > 0) {
#ifdef _MGRM_PROCESSES
const char* caption = "N/A";
if (mgIsServer) {
caption = nodes[from].caption;
}
else if (nodes[from].cli == __mg_client_id) {
caption = GetWindowCaption (nodes[from].hwnd);
}
_WRN_PRINTF ("ZNODE #%d (zidx: %d): hwnd (%p), "
"caption (%s), rect (%d, %d, %d, %d), "
"visibility (%s)\n",
nr, from, nodes[from].hwnd,
caption,
nodes[from].rc.left, nodes[from].rc.top,
nodes[from].rc.right, nodes[from].rc.bottom,
(nodes[from].flags & ZOF_VISIBLE) ? "YES" : "NO");
#else
_WRN_PRINTF ("ZNODE #%d (zidx: %d): hwnd (%p), "
"caption (%s), rect (%d, %d, %d, %d), "
"visibility (%s)\n",
nr, from, nodes[from].hwnd,
nodes[from].caption,
nodes[from].rc.left, nodes[from].rc.top,
nodes[from].rc.right, nodes[from].rc.bottom,
(nodes[from].flags & ZOF_VISIBLE) ? "YES" : "NO");
#endif
nr++;
from = __kernel_get_next_znode (zi, from);
}
unlock_zi_for_read (zi);
return nr;
}
static MSG sg_msgAutoRepeat;
static HWND sg_hCaretWnd;
static UINT sg_uCaretBTime;