Files
MiniGUI/src/kernel/desktop-comm.c
2023-09-04 10:45:05 +08:00

2204 lines
61 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~2018, 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-comm.c: The Desktop module.
**
** Current maintainer: Wei Yongming.
**
*/
/* only for MiniGUI-Threads or MiniGUI-Standalone */
#include "desktop.c"
#if defined(_MGRM_THREADS) || defined(_MGRM_STANDALONE)
static LRESULT DesktopWinProc (HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam);
static void init_desktop_win (void)
{
static MAINWIN sg_desktop_win;
PMAINWIN pDesktopWin;
LICENSE_SET_MESSAGE_OFFSET();
pDesktopWin = &sg_desktop_win;
pDesktopWin->pMsgQueue = __mg_dsk_msg_queue;
pDesktopWin->MainWindowProc = DesktopWinProc;
pDesktopWin->DataType = TYPE_HWND;
pDesktopWin->WinType = TYPE_ROOTWIN;
pDesktopWin->pLogFont = GetSystemFont (SYSLOGFONT_WCHAR_DEF);
pDesktopWin->spCaption = "THE DESKTOP WINDOW";
pDesktopWin->pGCRInfo = &sg_ScrGCRInfo;
pDesktopWin->idx_znode = 0;
pDesktopWin->pMainWin = pDesktopWin;
pDesktopWin->we_rdr = __mg_def_renderer;
__mg_hwnd_desktop = (HWND)pDesktopWin;
__mg_dsk_win = pDesktopWin;
__mg_dsk_msg_queue->pRootMainWin = __mg_dsk_win;
}
static PMAINWIN dskGetActiveWindow (void)
{
ZORDERNODE* nodes;
nodes = GET_ZORDERNODE(__mg_zorder_info);
return (PMAINWIN)nodes[__mg_zorder_info->active_win].hwnd;
}
static PMAINWIN dskSetActiveWindow (PMAINWIN pWin)
{
PMAINWIN pOldActive = dskGetActiveWindow();
if (pWin == pOldActive)
return pOldActive;
pOldActive = (PMAINWIN) dskSetActiveZOrderNode (__mg_zorder_info, 0, pWin?pWin->idx_znode:0);
#ifndef _MGRM_PROCESSES /*for MiniGUI-Threads, not for MiniGUI-StandAlone*/
if (pOldActive != (PMAINWIN)HWND_INVALID && __mg_ime_wnd)
SendNotifyMessage (__mg_ime_wnd, MSG_IME_SETTARGET, (WPARAM)pWin, 0);
#endif
return pOldActive;
}
/*
* Shows/Activates a main window.
* This function called when a window was shown.
*/
static void dskShowMainWindow (PMAINWIN pWin, BOOL bActive)
{
if (pWin->dwStyle & WS_VISIBLE)
return;
//dskUpdateGCRInfoOnShowMainWin (pWin);
pWin->dwStyle |= WS_VISIBLE;
dskShowWindow (0, pWin->idx_znode);
SendAsyncMessage ((HWND)pWin, MSG_NCPAINT, 0, 0);
InvalidateRect ((HWND)pWin, NULL, TRUE);
#if 0
if (pWin->dwExStyle & WS_EX_TOPMOST)
return dskSetActiveWindow (pWin);
// if the showing window cover the current active window
// set this window as the active one.
//if (bActive && dskDoesCoverOther (pWin, dskGetActiveWindow()))
#endif
if (bActive)
dskSetActiveWindow (pWin);
return;
}
static int dskAllocZOrderNode (PMAINWIN pWin)
{
RECT rc;
dskGetWindowRectInScreen (pWin, &rc);
return AllocZOrderNode (0, (HWND)pWin,
(HWND)pWin->pMainWin,
get_znode_flags_from_style (pWin),
&rc, pWin->spCaption, HDC_INVALID,
CT_OPAQUE, 0);
}
/*
* This funciton add the new main window to the z-order list.
* If new main window is a visible window,
* this new main window becomes the active window.
*
* Return 0 if OK, else -1;
*/
static int dskAddNewMainWindow (PMAINWIN pWin)
{
pWin->pGCRInfo = &pWin->GCRInfo;
// Update Z Order info.
pWin->idx_znode = dskAllocZOrderNode (pWin);
if (pWin->idx_znode <= 0) {
return -1;
}
/* Since 5.0.0: handle window style if failed to allocate znode
for special main window */
if (pWin->dwExStyle & WS_EX_WINTYPE_MASK) {
ZORDERNODE* nodes = GET_ZORDERNODE(__mg_zorder_info);
pWin->dwExStyle &= ~WS_EX_WINTYPE_MASK;
switch (nodes [pWin->idx_znode].flags & ZOF_TYPE_MASK) {
case ZOF_TYPE_TOOLTIP:
pWin->dwExStyle |= WS_EX_WINTYPE_TOOLTIP;
break;
case ZOF_TYPE_GLOBAL:
pWin->dwExStyle |= WS_EX_WINTYPE_GLOBAL;
break;
case ZOF_TYPE_SCREENLOCK:
pWin->dwExStyle |= WS_EX_WINTYPE_SCREENLOCK;
break;
case ZOF_TYPE_DOCKER:
pWin->dwExStyle |= WS_EX_WINTYPE_DOCKER;
break;
case ZOF_TYPE_HIGHER:
pWin->dwExStyle |= WS_EX_WINTYPE_HIGHER;
pWin->dwExStyle |= WS_EX_TOPMOST;
break;
case ZOF_TYPE_NORMAL:
pWin->dwExStyle |= WS_EX_WINTYPE_NORMAL;
break;
case ZOF_TYPE_LAUNCHER:
pWin->dwExStyle |= WS_EX_WINTYPE_LAUNCHER;
break;
default:
assert(0);
break;
}
}
#if 0 /* move to window.c since 5.0.0 */
// Handle main window hosting.
if (pWin->pHosting)
dskAddNewHostedMainWindow (pWin->pHosting, pWin);
#endif /* moved code */
// Init Global Clip Region info.
dskInitGCRInfo (pWin);
// Init Invalid Region info.
dskInitInvRgn (pWin);
/* houhh 20081128, create secondary window dc before
* InvalidateRect, erase_bk will used this. */
if (pWin->dwExStyle & WS_EX_AUTOSECONDARYDC) {
pWin->secondaryDC = CreateSecondaryDC ((HWND)pWin);
pWin->update_secdc = ON_UPDSECDC_DEFAULT;
}
if (pWin->secondaryDC == HDC_INVALID) {
/* remove the flag of WS_EX_AUTOSECONDARYDC */
pWin->dwExStyle &= ~WS_EX_AUTOSECONDARYDC;
pWin->secondaryDC = 0;
}
/* Create private client dc. */
if (pWin->dwExStyle & WS_EX_USEPRIVATECDC) {
#if 0 /* deprecated code */
if (pWin->dwExStyle & WS_EX_AUTOSECONDARYDC)
pWin->privCDC = GetSecondarySubDC (pWin->secondaryDC,
(HWND)pWin, TRUE);
else
pWin->privCDC = CreatePrivateClientDC ((HWND)pWin);
#else
/* since 5.0.0, always call CreatePrivateClientDC */
pWin->privCDC = CreatePrivateClientDC ((HWND)pWin);
#endif
}
else
pWin->privCDC = 0;
// show and active this main window.
if (pWin->dwStyle & WS_VISIBLE) {
SendAsyncMessage ((HWND)pWin, MSG_NCPAINT, 0, 0);
SendNotifyMessage ((HWND)pWin, MSG_SHOWWINDOW, SW_SHOWNORMAL, 0);
InvalidateRect ((HWND)pWin, NULL, TRUE);
dskSetActiveWindow (pWin);
}
return 0;
}
static void dskHideGlobalControl (PMAINWIN pWin, int reason, LPARAM lParam)
{
int first = 0;
ZORDERNODE* nodes = GET_ZORDERNODE(__mg_zorder_info);
lock_zi_for_read (__mg_zorder_info);
switch (nodes [pWin->idx_znode].flags & ZOF_TYPE_MASK) {
#if 0 /* no global ones */
case ZOF_TYPE_GLOBAL:
first = __mg_zorder_info->first_global;
break;
#endif
case ZOF_TYPE_HIGHER:
first = __mg_zorder_info->first_topmost;
break;
case ZOF_TYPE_NORMAL:
first = __mg_zorder_info->first_normal;
break;
default:
break;
}
unlock_zi_for_read (__mg_zorder_info);
if (first > 0 && !(nodes [first].flags & ZOF_TF_MAINWIN)
&& (nodes [first].flags & ZOF_VISIBLE)) {
RECT rc = nodes [first].rc;
PMAINWIN pCurTop = (PMAINWIN) nodes [first].hwnd;
pCurTop->dwStyle &= ~WS_VISIBLE;
dskHideWindow (0, pCurTop->idx_znode);
dskSetPrimitiveChildren (pCurTop, FALSE);
SendNotifyMessage (pCurTop->hParent,
MSG_CHILDHIDDEN, reason, lParam);
dskScreenToClient (pCurTop->pMainWin, &rc, &rc);
InvalidateRect ((HWND)pCurTop->pMainWin, &rc, TRUE);
}
}
static int update_client_window_rgn (int cli, HWND hwnd)
{
CLIPRECT* crc = sg_UpdateRgn.head;
if (hwnd) {
while (crc) {
__mg_update_window (hwnd, crc->rc.left, crc->rc.top,
crc->rc.right, crc->rc.bottom);
crc = crc->next;
}
}
return 0;
}
static void dskMoveToTopMost (PMAINWIN pWin, int reason, LPARAM lParam)
{
if (!pWin) return;
if (dskIsTopMost (pWin) && (pWin->dwStyle & WS_VISIBLE))
return;
dskHideGlobalControl (pWin, reason, lParam);
dskMove2Top (0, pWin->idx_znode);
if (!(pWin->dwStyle & WS_VISIBLE)) {
pWin->dwStyle |= WS_VISIBLE;
dskShowWindow (0, pWin->idx_znode);
SendAsyncMessage ((HWND)pWin, MSG_NCPAINT, 0, 0);
InvalidateRect ((HWND)pWin, NULL, TRUE);
}
else {
SendAsyncMessage ((HWND)pWin, MSG_NCPAINT, 0, 0);
}
// activate this main window.
if (reason != RCTM_SHOWCTRL)
dskSetActiveWindow (pWin);
}
/* Since 5.0.0 */
static BOOL dskSetMainWindowAlwaysTop (PMAINWIN pWin, BOOL fSet)
{
if ((pWin->dwStyle & WS_ALWAYSTOP) && fSet)
return TRUE;
if (!(pWin->dwStyle & WS_ALWAYSTOP) && !fSet)
return TRUE;
if (dskSetZNodeAlwaysTop (0, pWin->idx_znode, fSet))
return FALSE;
if (fSet) {
pWin->dwStyle |= WS_ALWAYSTOP;
}
else {
pWin->dwStyle &= ~WS_ALWAYSTOP;
}
return TRUE;
}
/* Since 5.0.6 */
static inline int dskSetMainWindowGestureFlags (PMAINWIN pWin, DWORD dwFlags)
{
if (dskSetZNodeGestureFlags (0, pWin->idx_znode, dwFlags))
return FALSE;
return TRUE;
}
/* Since 5.0.0 */
static int dskSetWindowMask (HWND pWin, const WINMASKINFO* mask_info)
{
FreeZOrderMaskRect (0, ((PMAINWIN)pWin)->idx_znode);
return AllocZOrderMaskRect (0, ((PMAINWIN)pWin)->idx_znode,
get_znode_flags_from_style ((PMAINWIN)pWin),
mask_info->rcs, mask_info->nr_rcs);
}
static void dskHideMainWindow (PMAINWIN pWin)
{
if (!(pWin->dwStyle & WS_VISIBLE))
return;
pWin->dwStyle &= ~WS_VISIBLE;
dskHideWindow (0, pWin->idx_znode);
}
// When destroy a main win, all main win which is covered by
// this destroying main win will be redraw.
//
// Functions which lead to call this function:
// DestroyWindow: destroy a visible window.
//
static void dskRemoveMainWindow (PMAINWIN pWin)
{
FreeZOrderMaskRect (0, pWin->idx_znode);
// Update window Z order list.
FreeZOrderNode (0, pWin->idx_znode, NULL);
#if 0 /* move to window.c since 5.0.0 */
// Handle main window hosting.
if (pWin->pHosting)
dskRemoveHostedMainWindow (pWin->pHosting, pWin);
#endif /* moved code */
/* houhh 20081127.*/
if ((pWin->dwExStyle & WS_EX_AUTOSECONDARYDC) && pWin->secondaryDC) {
#if 0 /* deprecated code */
DeleteSecondaryDC ((HWND)pWin);
#else /* deprecated code */
__mg_delete_secondary_dc (pWin);
#endif
pWin->update_secdc = NULL;
}
if (pWin->privCDC) {
#if 0 /* deprecated code */
if (pWin->dwExStyle & WS_EX_AUTOSECONDARYDC) {
ReleaseSecondarySubDC (pWin->privCDC);
}
else {
if (pWin->secondaryDC)
ReleaseSecondarySubDC (pWin->privCDC);
else
DeletePrivateDC (pWin->privCDC);
}
#else /* deprecated code */
/* since 5.0.0, always call DeletePrivateDC */
DeletePrivateDC (pWin->privCDC);
#endif
pWin->privCDC = 0;
}
/* since 5.0.0, reset auto-repeat message if target window is the
main window being removed or it is contained in this main window */
if (checkAndGetMainWinIfWindow (sg_msgAutoRepeat.hwnd) == pWin) {
sg_msgAutoRepeat.hwnd = 0;
}
if (checkAndGetMainWinIfWindow (sg_hCaretWnd) == pWin) {
sg_hCaretWnd = 0;
}
}
#ifdef _MGHAVE_MENU
static void dskForceCloseMenu (void)
{
ZORDERINFO* zi = __mg_zorder_info;
if (zi->cli_trackmenu < 0)
return;
srvForceCloseMenu (0);
}
static int dskStartTrackPopupMenu(PTRACKMENUINFO ptmi)
{
PTRACKMENUINFO plast;
if (sg_ptmi) {
plast = sg_ptmi;
while (plast->next) {
plast = plast->next;
}
plast->next = ptmi;
ptmi->prev = plast;
ptmi->next = NULL;
}
else {
sg_ptmi = ptmi;
ptmi->next = NULL;
ptmi->prev = NULL;
}
if (PopupMenuTrackProc (ptmi, MSG_INITMENU, 0, 0))
return -1;
ptmi->idx_znode = srvStartTrackPopupMenu (0, &ptmi->rc, (HWND)ptmi,
0, 0, -1);
if (ptmi->idx_znode < 0) {
if (sg_ptmi == ptmi) {
sg_ptmi = NULL;
}
else {
plast = sg_ptmi;
while (plast->next) {
plast = plast->next;
}
plast->prev->next = NULL;
plast = plast->prev;
}
return -1;
}
PopupMenuTrackProc (ptmi, MSG_SHOWMENU, 0, 0);
return 0;
}
static int dskEndTrackPopupMenu (PTRACKMENUINFO ptmi)
{
ZORDERINFO* zi = __mg_zorder_info;
PTRACKMENUINFO plast = NULL;
RECT rc;
RECT rcScr = GetScreenRect();
if (sg_ptmi == ptmi) {
sg_ptmi = NULL;
}
else {
plast = sg_ptmi;
while (plast->next) {
plast = plast->next;
}
plast->prev->next = NULL;
}
if (zi->cli_trackmenu == 0) {
srvEndTrackPopupMenu (0, ptmi->idx_znode);
}
PopupMenuTrackProc (ptmi, MSG_HIDEMENU, 0, 0);
PopupMenuTrackProc (ptmi, MSG_ENDTRACKMENU, 0, 0);
rc = ptmi->rc;
ptmi = sg_ptmi;
while (ptmi) {
if (DoesIntersect (&rc, &ptmi->rc)) {
SelectClipRect (HDC_SCREEN_SYS, &rc);
PopupMenuTrackProc (ptmi, MSG_SHOWMENU, 0, 0);
}
ptmi = ptmi->next;
}
SelectClipRect (HDC_SCREEN_SYS, &rcScr);
return 0;
}
#endif /* defiend _MGHAVE_MENU */
static void dskEnableWindow (PMAINWIN pWin, int flags)
{
if (dskEnableZOrderNode (0, pWin?pWin->idx_znode:0, flags))
return;
if ( (!(pWin->dwStyle & WS_DISABLED) && !flags)
|| ((pWin->dwStyle & WS_DISABLED) && flags) ) {
if (flags)
pWin->dwStyle &= ~WS_DISABLED;
else
pWin->dwStyle |= WS_DISABLED;
if (pWin->dwStyle & WS_DISABLED) {
if (__mg_captured_wnd &&
checkAndGetMainWinIfWindow (__mg_captured_wnd) == pWin)
__mg_captured_wnd = 0;
if (dskGetActiveWindow () == pWin) {
dskSetActiveWindow (NULL);
return;
}
}
SendAsyncMessage ((HWND)pWin, MSG_NCPAINT, 0, 0);
}
}
static int dskMoveMainWindow (PMAINWIN pWin, const RECT* prcExpect)
{
RECT rcResult;
SendAsyncMessage ((HWND)pWin, MSG_CHANGESIZE,
(WPARAM)(prcExpect), (LPARAM)(&rcResult));
return dskMoveWindow (0, pWin->idx_znode, HDC_INVALID, &rcResult);
}
static int dskMoveGlobalControl (PMAINWIN pCtrl, RECT* prcExpect)
{
RECT newWinRect, rcResult;
int ret;
SendAsyncMessage ((HWND)pCtrl, MSG_CHANGESIZE,
(WPARAM)(prcExpect), (LPARAM)(&rcResult));
dskClientToScreen ((PMAINWIN)(pCtrl->hParent), prcExpect, &newWinRect);
ret = dskMoveWindow (0, pCtrl->idx_znode, HDC_INVALID, &newWinRect);
if (ret == 0 && pCtrl->dwStyle & WS_VISIBLE) {
SendAsyncMessage ((HWND)pCtrl, MSG_NCPAINT, 0, 0);
InvalidateRect ((HWND)pCtrl, NULL, TRUE);
}
return ret;
}
/*********************** Desktop window support ******************************/
PMAINWIN gui_GetMainWindowPtrUnderPoint (int x, int y)
{
int slot;
ZORDERNODE* nodes = GET_ZORDERNODE(__mg_zorder_info);
slot = get_znode_at_point (__mg_zorder_info, nodes, x, y);
if (slot == 0)
return NULL;
else
return (PMAINWIN)(nodes[slot].hwnd);
}
static int HandleSpecialKey (int scancode)
{
switch (scancode) {
case SCANCODE_BACKSPACE:
ExitGUISafely (-1);
return 0;
}
return 0;
}
static LRESULT KeyMessageHandler (UINT message, int scancode, DWORD status)
{
static int mg_altdown = 0;
static int mg_modal = 0;
int next_node;
if ((message == MSG_KEYDOWN) && (status & KS_ALT) && (status & KS_CTRL))
return HandleSpecialKey (scancode);
if (scancode == SCANCODE_LEFTALT ||
scancode == SCANCODE_RIGHTALT) {
if (message == MSG_KEYDOWN) {
mg_altdown = 1;
return 0;
}
else {
mg_altdown = 0;
if (mg_modal == 1) {
mg_modal = 0;
return 0;
}
}
}
if (mg_altdown) {
if (message == MSG_KEYDOWN) {
if( scancode == SCANCODE_TAB) {
mg_modal = 1;
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
next_node =
get_next_activable_mainwin (__mg_zorder_info,
__mg_zorder_info->active_win);
if (next_node) {
dskMove2Top (0, next_node);
dskSetActiveZOrderNode (__mg_zorder_info, 0, next_node);
}
return 0;
}
else if (scancode == SCANCODE_ESCAPE) {
mg_modal = 1;
if (__mg_zorder_info->active_win) {
__mg_post_msg_by_znode (__mg_zorder_info,
__mg_zorder_info->active_win,
MSG_CLOSE, 0, 0);
return 0;
}
}
}
else if (mg_modal == 1)
return 0;
}
if (scancode == SCANCODE_LEFTALT
|| scancode == SCANCODE_RIGHTALT || mg_altdown) {
if (message == MSG_KEYDOWN)
message = MSG_SYSKEYDOWN;
else {
message = MSG_SYSKEYUP;
mg_altdown = 0;
}
}
#if 0 /* since 5.0.0, deprecated code */
#ifndef _MGRM_THREADS
if (__mg_ime_wnd
&& message != MSG_SYSKEYDOWN && message != MSG_SYSKEYUP) {
if (dskHandleKeyHooks (__mg_ime_wnd,
message, (WPARAM)scancode, (LPARAM)status) == HOOK_GOON)
PostMessage (__mg_ime_wnd,
message, (WPARAM)scancode, (LPARAM)status);
return 0;
}
#else
else if (__mg_ime_wnd && __mg_zorder_info->active_win) {
if (dskHandleKeyHooks (__mg_ime_wnd,
message, (WPARAM)scancode, (LPARAM)status) == HOOK_GOON)
PostMessage (__mg_ime_wnd,
message, (WPARAM)scancode, (LPARAM)status);
return 0;
}
#endif
if (__mg_zorder_info->active_win) {
if (dskHandleKeyHooks ((HWND)dskGetActiveWindow(),
message, (WPARAM)scancode, (LPARAM)status) == HOOK_GOON) {
__mg_post_msg_by_znode (__mg_zorder_info,
__mg_zorder_info->active_win, message,
(WPARAM)scancode, (LPARAM)status);
}
}
else {
if (dskHandleKeyHooks (HWND_DESKTOP, message,
(WPARAM)scancode, (LPARAM)status) == HOOK_GOON) {
SendMessage (HWND_DESKTOP, MSG_DT_KEYOFF + message,
(WPARAM)scancode, (LPARAM)status);
}
}
#else /* since 5.0.0, deprecated code */
#ifndef _MGRM_THREADS
if (__mg_ime_wnd &&
message != MSG_SYSKEYDOWN && message != MSG_SYSKEYUP) {
PostMessage (__mg_ime_wnd, message, (WPARAM)scancode, (LPARAM)status);
return 0;
}
#else
else if (__mg_ime_wnd && __mg_zorder_info->active_win) {
PostMessage (__mg_ime_wnd,
message, (WPARAM)scancode, (LPARAM)status);
return 0;
}
#endif
if (__mg_zorder_info->active_win) {
__mg_post_msg_by_znode (__mg_zorder_info,
__mg_zorder_info->active_win,
message, (WPARAM)scancode, (LPARAM)status);
}
else {
SendMessage (HWND_DESKTOP, MSG_DT_KEYOFF + message,
(WPARAM)scancode, (LPARAM)status);
}
#endif /* since 5.0.0: do not handle hook function here */
return 0;
}
static PMAINWIN _mgs_button_down_main_window = NULL;
static PMAINWIN _mgs_old_under_p = NULL;
#define DOWN_BUTTON_NONE 0x0000
#define DOWN_BUTTON_LEFT 0x0001
#define DOWN_BUTTON_RIGHT 0x0002
#define DOWN_BUTTON_MIDDLE 0x0004
#define DOWN_BUTTON_ANY 0x000F
static DWORD _mgs_down_buttons = 0;
/* defined in ../gui/window.c */
extern void __mg_reset_mainwin_capture_info (PCONTROL ctrl);
void __mg_reset_desktop_capture_info (PMAINWIN pWin)
{
_mgs_old_under_p = NULL;
if (!__mg_ime_wnd || (HWND)pWin != __mg_ime_wnd) {
_mgs_button_down_main_window = NULL;
_mgs_down_buttons = DOWN_BUTTON_NONE;
}
if ((HWND)pWin == __mg_captured_wnd)
__mg_captured_wnd = 0;
__mg_reset_mainwin_capture_info ((PCONTROL)pWin);
}
static HWND DesktopSetCapture (HWND hwnd)
{
HWND hTemp;
_mgs_old_under_p = NULL;
_mgs_button_down_main_window = checkAndGetMainWinIfWindow (hwnd);
_mgs_down_buttons = DOWN_BUTTON_NONE;
hTemp = __mg_captured_wnd;
__mg_captured_wnd = hwnd;
return hTemp;
}
static LRESULT MouseMessageHandler (UINT message, WPARAM flags, int x, int y)
{
PMAINWIN pUnderPointer;
PMAINWIN pCtrlPtrIn;
if (__mg_captured_wnd) {
PostMessage (__mg_captured_wnd, message,
flags | KS_CAPTURED, MAKELONG (x, y));
return 0;
}
pCtrlPtrIn = gui_GetMainWindowPtrUnderPoint (x, y);
#if 0 /* since 5.0.0, do not handle hook function here */
if (dskHandleMouseHooks ((HWND)pCtrlPtrIn,
message, flags, MAKELONG (x, y)) == HOOK_STOP)
return 0;
#endif /* since 5.0.0, do not handle hook function here */
if (pCtrlPtrIn && pCtrlPtrIn->WinType == TYPE_CONTROL) {
pUnderPointer = pCtrlPtrIn->pMainWin;
}
else {
pUnderPointer = pCtrlPtrIn;
pCtrlPtrIn = NULL;
}
switch (message) {
case MSG_MOUSEMOVE:
if (_mgs_button_down_main_window) {
PostMessage ((HWND)_mgs_button_down_main_window,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
}
else {
if (_mgs_old_under_p != pUnderPointer) {
if (_mgs_old_under_p) {
PostMessage ((HWND)_mgs_old_under_p,
MSG_MOUSEMOVEIN, FALSE, (LPARAM)pUnderPointer);
PostMessage ((HWND)_mgs_old_under_p,
MSG_NCMOUSEMOVE, HT_OUT, MAKELONG (x, y));
}
if (pUnderPointer)
PostMessage ((HWND)pUnderPointer,
MSG_MOUSEMOVEIN, TRUE, (LPARAM)_mgs_old_under_p);
else
SetCursor (GetSystemCursor (IDC_ARROW));
_mgs_old_under_p = pUnderPointer;
}
if (pUnderPointer) {
if (pUnderPointer->dwStyle & WS_DISABLED) {
HCURSOR def_cursor = GetDefaultCursor ();
if (def_cursor)
SetCursor (def_cursor);
}
else
PostMessage ((HWND)pUnderPointer,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
}
else {
HCURSOR def_cursor = GetDefaultCursor ();
if (def_cursor)
SetCursor (def_cursor);
PostMessage (HWND_DESKTOP, MSG_DT_MOUSEMOVE,
flags, MAKELONG (x, y));
}
}
break;
case MSG_LBUTTONDOWN:
case MSG_RBUTTONDOWN:
case MSG_MBUTTONDOWN:
if (_mgs_button_down_main_window) {
PostMessage ((HWND)_mgs_button_down_main_window,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
if (message == MSG_LBUTTONDOWN)
_mgs_down_buttons |= DOWN_BUTTON_LEFT;
else if (message == MSG_RBUTTONDOWN)
_mgs_down_buttons |= DOWN_BUTTON_RIGHT;
else
_mgs_down_buttons |= DOWN_BUTTON_MIDDLE;
}
else if (pUnderPointer) {
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
if (pUnderPointer->dwStyle & WS_DISABLED) {
Ping ();
break;
}
if (pCtrlPtrIn == NULL) {
if (!dskIsTopMost (pUnderPointer)) {
dskMoveToTopMost (pUnderPointer,
RCTM_CLICK, MAKELONG (x, y));
}
if (pUnderPointer != dskSetActiveWindow (pUnderPointer))
SendNotifyMessage ((HWND) pUnderPointer,
MSG_MOUSEACTIVE, 0, 0);
}
PostMessage ((HWND)pUnderPointer, message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
_mgs_button_down_main_window = pUnderPointer;
if (message == MSG_LBUTTONDOWN)
_mgs_down_buttons = DOWN_BUTTON_LEFT;
else if (message == MSG_RBUTTONDOWN)
_mgs_down_buttons = DOWN_BUTTON_RIGHT;
else
_mgs_down_buttons = DOWN_BUTTON_MIDDLE;
}
else {
dskSetActiveWindow (NULL);
PostMessage (HWND_DESKTOP, message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
_mgs_button_down_main_window = NULL;
_mgs_down_buttons = DOWN_BUTTON_NONE;
}
break;
case MSG_LBUTTONUP:
case MSG_RBUTTONUP:
case MSG_MBUTTONUP:
if (_mgs_down_buttons == DOWN_BUTTON_LEFT &&
message != MSG_LBUTTONUP) {
break;
}
if (_mgs_down_buttons == DOWN_BUTTON_RIGHT &&
message != MSG_RBUTTONUP) {
break;
}
if (_mgs_down_buttons == DOWN_BUTTON_MIDDLE &&
message != MSG_MBUTTONUP) {
break;
}
if (_mgs_button_down_main_window) {
PostMessage ((HWND)_mgs_button_down_main_window,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
if (message == MSG_LBUTTONUP)
_mgs_down_buttons &= ~DOWN_BUTTON_LEFT;
else if (message == MSG_RBUTTONUP)
_mgs_down_buttons &= ~DOWN_BUTTON_RIGHT;
else
_mgs_down_buttons &= ~DOWN_BUTTON_MIDDLE;
if (!(_mgs_down_buttons & DOWN_BUTTON_ANY)) {
_mgs_button_down_main_window = NULL;
_mgs_down_buttons = DOWN_BUTTON_NONE;
}
}
else {
/* fixed bug 4961: for deal with when _mgs_button_down_main_window was reset,
* but there real has a mouse up message. by humingming 2010.9.1
*/
if (pUnderPointer == NULL) {
PostMessage (HWND_DESKTOP,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
}
else {
if ((pUnderPointer->dwStyle & WS_DISABLED)) {
break;
}
else {
PostMessage((HWND)pUnderPointer,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
}
}
}
break;
case MSG_LBUTTONDBLCLK:
case MSG_RBUTTONDBLCLK:
case MSG_MBUTTONDBLCLK:
if (_mgs_button_down_main_window) {
PostMessage ((HWND)_mgs_button_down_main_window,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
if (message == MSG_LBUTTONDBLCLK)
_mgs_down_buttons |= DOWN_BUTTON_LEFT;
else if (message == MSG_RBUTTONDBLCLK)
_mgs_down_buttons |= DOWN_BUTTON_RIGHT;
else
_mgs_down_buttons |= DOWN_BUTTON_MIDDLE;
}
else if (pUnderPointer) {
PostMessage ((HWND)pUnderPointer,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
_mgs_button_down_main_window = pUnderPointer;
if (message == MSG_LBUTTONDBLCLK)
_mgs_down_buttons = DOWN_BUTTON_LEFT;
else if (message == MSG_RBUTTONDBLCLK)
_mgs_down_buttons = DOWN_BUTTON_RIGHT;
else
_mgs_down_buttons = DOWN_BUTTON_MIDDLE;
}
else {
PostMessage (HWND_DESKTOP,
message + MSG_DT_MOUSEOFF,
flags, MAKELONG (x, y));
_mgs_button_down_main_window = NULL;
_mgs_down_buttons = DOWN_BUTTON_NONE;
}
break;
}
return 0;
}
typedef struct _DRAGDROPINFO {
HWND hwnd;
RECT rc;
int location;
int last_x, last_y;
} DRAGDROPINFO;
static DRAGDROPINFO _dd_info;
#ifndef _MGRM_THREADS
inline static void lock_zorder_info (void) { }
inline static void unlock_zorder_info (void) { }
#else /* not define _MGRM_THREADS */
static void lock_zorder_info (void)
{
PMAINWIN pWin = NULL;
int level, slot;
ZORDERNODE* nodes = GET_ZORDERNODE(__mg_zorder_info);
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
slot = __mg_zorder_info->first_in_levels[level];
for (; slot > 0; slot = nodes[slot].next) {
pWin = (PMAINWIN)(nodes[slot].hwnd);
if (pWin)
pthread_mutex_lock (&pWin->pGCRInfo->lock);
}
}
#if 0 /* deprected code */
static int fixed_slots [] = { ZNIDX_SCREENLOCK, ZNIDX_DOCKER,
ZNIDX_LAUNCHER };
/* Since 5.0.0 */
for (slot = 0; slot < TABLESIZE(fixed_slots); slot++) {
pWin = (PMAINWIN)(nodes[fixed_slots[slot]].hwnd);
if (pWin)
pthread_mutex_lock (&pWin->pGCRInfo->lock);
}
slot = __mg_zorder_info->first_topmost;
for (; slot > 0; slot = nodes[slot].next) {
pWin = (PMAINWIN)(nodes[slot].hwnd);
if (pWin)
pthread_mutex_lock (&pWin->pGCRInfo->lock);
}
slot = __mg_zorder_info->first_normal;
for (; slot > 0; slot = nodes[slot].next) {
pWin = (PMAINWIN)(nodes[slot].hwnd);
if (pWin)
pthread_mutex_lock (&pWin->pGCRInfo->lock);
}
#endif /* deprected code */
}
static void unlock_zorder_info (void)
{
PMAINWIN pWin;
int level, slot;
ZORDERNODE* nodes = GET_ZORDERNODE(__mg_zorder_info);
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
slot = __mg_zorder_info->first_in_levels[level];
for (; slot > 0; slot = nodes[slot].next) {
pWin = (PMAINWIN)(nodes[slot].hwnd);
if (pWin)
pthread_mutex_unlock (&pWin->pGCRInfo->lock);
}
}
}
#endif /* define _MGRM_THREADS */
static int dskStartDragWindow (PMAINWIN pWin, const DRAGINFO* drag_info)
{
if (!(pWin->dwStyle & WS_VISIBLE))
return -1;
if (_dd_info.hwnd != 0)
return -1;
_mgs_old_under_p = NULL;
_mgs_button_down_main_window = NULL;
_mgs_down_buttons = 0;
lock_zorder_info ();
_dd_info.hwnd = (HWND)pWin;
_dd_info.rc.left = pWin->left;
_dd_info.rc.top = pWin->top;
_dd_info.rc.right = pWin->right;
_dd_info.rc.bottom = pWin->bottom;
_dd_info.location = drag_info->location;
_dd_info.last_x = drag_info->init_x;
_dd_info.last_y = drag_info->init_y;
switch (_dd_info.location) {
case HT_CAPTION:
//SetDefaultCursor (GetSystemCursor (IDC_MOVE));
SetCursor (GetSystemCursor (IDC_MOVE));
break;
case HT_BORDER_TOP:
case HT_BORDER_BOTTOM:
//SetDefaultCursor (GetSystemCursor (IDC_SIZENS));
SetCursor (GetSystemCursor (IDC_SIZENS));
break;
case HT_BORDER_LEFT:
case HT_BORDER_RIGHT:
//SetDefaultCursor (GetSystemCursor (IDC_SIZEWE));
SetCursor (GetSystemCursor (IDC_SIZEWE));
break;
case HT_CORNER_TL:
case HT_CORNER_BR:
//SetDefaultCursor (GetSystemCursor (IDC_SIZENWSE));
SetCursor (GetSystemCursor (IDC_SIZENWSE));
break;
case HT_CORNER_BL:
case HT_CORNER_TR:
//SetDefaultCursor (GetSystemCursor (IDC_SIZENESW));
SetCursor (GetSystemCursor (IDC_SIZENESW));
break;
default:
_WRN_PRINTF ("bad location\n");
break;
}
SetPenColor (HDC_SCREEN_SYS, PIXEL_lightwhite);
FocusRect (HDC_SCREEN_SYS, _dd_info.rc.left, _dd_info.rc.top,
_dd_info.rc.right, _dd_info.rc.bottom);
SyncUpdateDC (HDC_SCREEN_SYS);
return 0;
}
static int dskCancelDragWindow (PMAINWIN pWin)
{
RECT rcScr = GetScreenRect();
if (!(pWin->dwStyle & WS_VISIBLE))
return -1;
if (_dd_info.hwnd == 0 || _dd_info.hwnd != (HWND)pWin)
return -1;
_dd_info.hwnd = (HWND)-1;
unlock_zorder_info ();
SelectClipRect (HDC_SCREEN_SYS, &rcScr);
return 0;
}
static int do_drag_drop_window (UINT msg, int x, int y)
{
if (_dd_info.hwnd == 0)
return 0;
if (msg == MSG_MOUSEMOVE) {
SetPenColor (HDC_SCREEN_SYS, PIXEL_lightwhite);
FocusRect (HDC_SCREEN_SYS, _dd_info.rc.left, _dd_info.rc.top,
_dd_info.rc.right, _dd_info.rc.bottom);
SyncUpdateDC (HDC_SCREEN_SYS);
switch (_dd_info.location) {
case HT_CAPTION:
OffsetRect (&_dd_info.rc,
x - _dd_info.last_x,
y - _dd_info.last_y);
break;
case HT_BORDER_TOP:
_dd_info.rc.top += y - _dd_info.last_y;
break;
case HT_BORDER_BOTTOM:
_dd_info.rc.bottom += y - _dd_info.last_y;
break;
case HT_BORDER_LEFT:
_dd_info.rc.left += x - _dd_info.last_x;
break;
case HT_BORDER_RIGHT:
_dd_info.rc.right += x - _dd_info.last_x;
break;
case HT_CORNER_TL:
_dd_info.rc.left += x - _dd_info.last_x;
_dd_info.rc.top += y - _dd_info.last_y;
break;
case HT_CORNER_TR:
_dd_info.rc.right += x - _dd_info.last_x;
_dd_info.rc.top += y - _dd_info.last_y;
break;
case HT_CORNER_BL:
_dd_info.rc.left += x - _dd_info.last_x;
_dd_info.rc.bottom += y - _dd_info.last_y;
break;
case HT_CORNER_BR:
_dd_info.rc.right += x - _dd_info.last_x;
_dd_info.rc.bottom += y - _dd_info.last_y;
break;
default:
_WRN_PRINTF ("bad location\n");
break;
}
FocusRect (HDC_SCREEN_SYS, _dd_info.rc.left, _dd_info.rc.top,
_dd_info.rc.right, _dd_info.rc.bottom);
SyncUpdateDC (HDC_SCREEN_SYS);
_dd_info.last_x = x;
_dd_info.last_y = y;
}
else {
RECT rcScr = GetScreenRect();
SetPenColor (HDC_SCREEN_SYS, PIXEL_lightwhite);
FocusRect (HDC_SCREEN_SYS, _dd_info.rc.left, _dd_info.rc.top,
_dd_info.rc.right, _dd_info.rc.bottom);
SyncUpdateDC (HDC_SCREEN_SYS);
/* post MSG_WINDOWDROPPED to the target window */
SendNotifyMessage (_dd_info.hwnd, MSG_WINDOWDROPPED,
MAKELONG (_dd_info.rc.left, _dd_info.rc.top),
MAKELONG (_dd_info.rc.right, _dd_info.rc.bottom));
unlock_zorder_info ();
SelectClipRect (HDC_SCREEN_SYS, &rcScr);
if (_dd_info.hwnd != (HWND)gui_GetMainWindowPtrUnderPoint (x, y))
SetDefaultCursor (GetSystemCursor (IDC_ARROW));
_dd_info.hwnd = 0;
}
return 1;
}
static LRESULT WindowMessageHandler(UINT message, PMAINWIN pWin, LPARAM lParam)
{
LRESULT lRet = 0;
/* cancel the current drag and drop operation */
do_drag_drop_window (message, 0, 0);
switch (message) {
case MSG_ADDNEWMAINWIN:
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
return dskAddNewMainWindow(pWin);
case MSG_REMOVEMAINWIN:
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
dskRemoveMainWindow(pWin);
__mg_reset_desktop_capture_info (pWin);
return 0;
case MSG_MOVETOTOPMOST:
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
dskMoveToTopMost(pWin, RCTM_MESSAGE, 0);
return 0;
case MSG_SHOWMAINWIN:
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
dskShowMainWindow(pWin, TRUE);
return 0;
case MSG_HIDEMAINWIN:
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
dskHideMainWindow (pWin);
__mg_reset_desktop_capture_info (pWin);
return 0;
case MSG_MOVEMAINWIN:
if (pWin->WinType == TYPE_CONTROL)
lRet = (LRESULT)dskMoveGlobalControl (pWin, (RECT*)lParam);
else {
lRet = (LRESULT)dskMoveMainWindow (pWin, (RECT*)lParam);
}
return lRet;
case MSG_GETACTIVEMAIN:
return (LRESULT)dskGetActiveWindow();
case MSG_SETACTIVEMAIN:
lRet = (LRESULT)dskSetActiveWindow (pWin);
return lRet;
case MSG_GETCAPTURE:
return (LRESULT)__mg_captured_wnd;
case MSG_SETCAPTURE:
return (LRESULT)DesktopSetCapture ((HWND)pWin);
#ifdef _MGHAVE_MENU
case MSG_TRACKPOPUPMENU:
return dskStartTrackPopupMenu((PTRACKMENUINFO)lParam);
case MSG_ENDTRACKMENU:
return dskEndTrackPopupMenu((PTRACKMENUINFO)lParam);
case MSG_CLOSEMENU:
return dskCloseMenu ();
#endif
case MSG_SCROLLMAINWIN:
lRet = dskScrollMainWindow (pWin, (PSCROLLWINDOWINFO)lParam);
return lRet;
case MSG_CARET_CREATE:
sg_hCaretWnd = (HWND)pWin;
sg_uCaretBTime = pWin->pCaretInfo->uTime;
return 0;
case MSG_CARET_DESTROY:
sg_hCaretWnd = 0;
return 0;
case MSG_ENABLEMAINWIN:
dskEnableWindow (pWin, lParam);
return 0;
case MSG_ISENABLED:
return !(pWin->dwStyle & WS_DISABLED);
case MSG_SETWINCURSOR: {
HCURSOR old = pWin->hCursor;
pWin->hCursor = (HCURSOR)lParam;
return (LRESULT)old;
}
case MSG_GETNEXTMAINWIN: {
ZORDERINFO* zi = __mg_zorder_info;
ZORDERNODE* nodes = GET_ZORDERNODE(zi);
HWND hwnd = HWND_NULL;
int from;
if (pWin) {
from = pWin->idx_znode;
}
else {
from = 0;
}
lock_zi_for_read (zi);
from = __kernel_get_next_znode (zi, from);
while (from > 0) {
hwnd = nodes[from].hwnd;
if ((pWin = checkAndGetMainWinIfMainWin (hwnd)) &&
!(pWin->dwExStyle & WS_EX_CTRLASMAINWIN)) {
break;
}
from = __kernel_get_next_znode (zi, from);
}
unlock_zi_for_read (zi);
return (LRESULT)hwnd;
}
case MSG_DUMPZORDER:
dskDumpZOrder (__mg_zorder_info);
break;
/* Since 5.0.0 */
case MSG_SETAUTOREPEAT:
sg_msgAutoRepeat = *(const MSG*)lParam;
/* start auto-repeat after 300ms */
sg_msgAutoRepeat.time = __mg_tick_counter + (__mg_timeout_usec/10000);
break;
/* Since 5.0.0 */
case MSG_SETALWAYSTOP:
return dskSetMainWindowAlwaysTop (pWin, (BOOL)lParam);
/* Since 5.0.6 */
case MSG_SETGESTUREFLAGS:
return dskSetMainWindowGestureFlags (pWin, (DWORD)lParam);
/* Since 5.0.0 */
case MSG_SETWINDOWMASK:
return dskSetWindowMask (pWin, (WINMASKINFO*)lParam);
case MSG_SHOWGLOBALCTRL:
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
dskMoveGlobalControl (pWin, (RECT*)&(pWin->left));
dskMoveToTopMost (pWin, RCTM_SHOWCTRL, 0);
dskSetPrimitiveChildren (pWin, TRUE);
break;
case MSG_HIDEGLOBALCTRL:
#ifdef _MGHAVE_MENU
if (sg_ptmi)
dskForceCloseMenu ();
#endif
dskHideMainWindow (pWin);
dskSetPrimitiveChildren (pWin, FALSE);
break;
case MSG_STARTDRAGWIN:
return dskStartDragWindow (pWin, (DRAGINFO*)lParam);
case MSG_CANCELDRAGWIN:
return dskCancelDragWindow (pWin);
}
return lRet;
}
#define IDM_REDRAWBG MINID_RESERVED
#define IDM_CLOSEALLWIN (MINID_RESERVED + 1)
#define IDM_ENDSESSION (MINID_RESERVED + 2)
#define IDM_FIRSTWINDOW (MINID_RESERVED + 101)
#ifdef _MGHAVE_MENU
static HMENU dskCreateWindowSubMenu (void)
{
HMENU hmnu;
MENUITEMINFO mii;
memset (&mii, 0, sizeof(MENUITEMINFO));
mii.type = MFT_STRING;
mii.id = 0;
mii.typedata = (DWORD)GetSysText(IDS_MGST_WINDOW);
hmnu = CreatePopupMenu (&mii);
return hmnu;
}
static HMENU dskCreateDesktopMenu (void)
{
HMENU hmnu;
MENUITEMINFO mii;
memset (&mii, 0, sizeof(MENUITEMINFO));
mii.type = MFT_STRING;
mii.id = 0;
mii.typedata = (DWORD)GetSysText(IDS_MGST_START);
hmnu = CreatePopupMenu (&mii);
memset (&mii, 0, sizeof(MENUITEMINFO));
mii.type = MFT_STRING;
mii.id = IDM_REDRAWBG;
mii.typedata = (DWORD)GetSysText(IDS_MGST_REFRESH);
InsertMenuItem (hmnu, 0, TRUE, &mii);
mii.type = MFT_STRING;
mii.id = IDM_CLOSEALLWIN;
mii.typedata = (DWORD)GetSysText(IDS_MGST_CLOSEALLWIN);
InsertMenuItem (hmnu, 1, TRUE, &mii);
mii.type = MFT_STRING;
mii.id = IDM_ENDSESSION;
mii.typedata = (DWORD)GetSysText(IDS_MGST_ENDSESSION);
InsertMenuItem (hmnu, 2, TRUE, &mii);
mii.type = MFT_STRING;
mii.id = 0;
mii.typedata = (DWORD)GetSysText(IDS_MGST_WINDOW);
mii.hsubmenu = dskCreateWindowSubMenu();
InsertMenuItem (hmnu, 3, TRUE, &mii);
mii.type = MFT_SEPARATOR;
mii.id = 0;
mii.typedata = 0;
mii.hsubmenu = 0;
InsertMenuItem(hmnu, 4, TRUE, &mii);
return hmnu;
}
static void dskUpdateDesktopMenu (HMENU hDesktopMenu)
{
MENUITEMINFO mii;
HMENU hWinMenu;
int nCount, iPos;
PMAINWIN pWin;
int id;
int level, slot;
ZORDERNODE* nodes = GET_ZORDERNODE(__mg_zorder_info);
hWinMenu = GetSubMenu (hDesktopMenu, 3);
nCount = GetMenuItemCount (hWinMenu);
for (iPos = nCount; iPos > 0; iPos--)
DeleteMenu (hWinMenu, iPos - 1, MF_BYPOSITION);
memset (&mii, 0, sizeof(MENUITEMINFO));
mii.type = MFT_STRING;
id = IDM_FIRSTWINDOW;
iPos = 0;
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
BOOL inserted;
inserted = FALSE;
slot = __mg_zorder_info->first_in_levels[level];
for (; slot > 0; slot = nodes[slot].next) {
pWin = (PMAINWIN)(nodes[slot].hwnd);
if (pWin && pWin->WinType == TYPE_MAINWIN) {
if (nodes[slot].flags & ZOF_VISIBLE &&
!(nodes[slot].flags & ZOF_DISABLED))
mii.state = MFS_ENABLED;
else
mii.state = MFS_DISABLED;
}
else {
continue;
}
mii.type = MFT_STRING;
mii.id = id;
mii.typedata = (DWORD)pWin->spCaption;
mii.itemdata = (DWORD)pWin;
InsertMenuItem (hWinMenu, iPos, TRUE, &mii);
id++;
iPos++;
inserted = TRUE;
}
if (inserted && level < (NR_ZORDER_LEVELS - 1) &&
__mg_zorder_info->first_in_levels[level+1] > 0) {
mii.type = MFT_SEPARATOR;
mii.state = 0;
mii.id = 0;
mii.typedata = 0;
InsertMenuItem(hWinMenu, iPos, TRUE, &mii);
iPos ++;
}
}
nCount = GetMenuItemCount (hDesktopMenu);
for (iPos = nCount; iPos > 5; iPos --)
DeleteMenu (hDesktopMenu, iPos - 1, MF_BYPOSITION);
dsk_ops->customize_desktop_menu (dt_context, hDesktopMenu, 5);
}
#endif
static void close_all_main_window (void)
{
int level, slot;
PMAINWIN pWin;
ZORDERNODE* nodes = GET_ZORDERNODE(__mg_zorder_info);
for (level = 0; level < NR_ZORDER_LEVELS; level++) {
slot = __mg_zorder_info->first_in_levels[level];
for (; slot > 0; slot = nodes[slot].next) {
pWin = (PMAINWIN)(nodes[slot].hwnd);
if (pWin && (pWin->WinType == TYPE_MAINWIN))
SendNotifyMessage ((HWND)pWin, MSG_CLOSE, 0, 0);
}
}
}
static int dskDesktopCommand (HMENU hDesktopMenu, int id)
{
if (id == IDM_REDRAWBG)
SendMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0, 0);
else if (id == IDM_CLOSEALLWIN) {
close_all_main_window ();
}
else if (id == IDM_ENDSESSION) {
#ifdef _MGHAVE_VIRTUAL_WINDOW
//close_all_main_window ();
post_quit_to_all_message_threads (TRUE);
#else
SendNotifyMessage (HWND_DESKTOP, MSG_ENDSESSION, 0, 0);
#endif /* defined _MGHAVE_VIRTUAL_WINDOW */
}
#ifdef _MGHAVE_MENU
else if (id >= IDM_FIRSTWINDOW) {
HMENU win_menu;
MENUITEMINFO mii = {MIIM_DATA};
PMAINWIN pSelectedWin;
win_menu = GetSubMenu (hDesktopMenu, 3);
if (GetMenuItemInfo (win_menu, id, MF_BYCOMMAND, &mii) == 0) {
pSelectedWin = (PMAINWIN)mii.itemdata;
if (pSelectedWin
&& pSelectedWin->WinType == TYPE_MAINWIN
&& !(pSelectedWin->dwStyle & WS_DISABLED)) {
if (sg_ptmi)
dskForceCloseMenu ();
dskMoveToTopMost (pSelectedWin, RCTM_MESSAGE, 0);
dskSetActiveWindow (pSelectedWin);
}
}
}
#endif
return 0;
}
static int dskOnNewCtrlInstance (PCONTROL pParent, PCONTROL pNewCtrl)
{
PCONTROL pFirstCtrl, pLastCtrl;
if (pNewCtrl->dwExStyle & WS_EX_CTRLASMAINWIN) {
// Add to Z-Order list.
pNewCtrl->idx_znode = dskAllocZOrderNode ((PMAINWIN)pNewCtrl);
if (pNewCtrl->idx_znode <= 0) {
_WRN_PRINTF ("Failed to allocate znode for control.\n");
return -1;
}
// Init Global Clip Region info.
dskInitGCRInfo ((PMAINWIN)pNewCtrl);
}
pFirstCtrl = pParent->children;
pNewCtrl->next = NULL;
if (!pFirstCtrl) {
pParent->children = pNewCtrl;
pNewCtrl->prev = NULL;
}
else {
pLastCtrl = pFirstCtrl;
while (pLastCtrl->next)
pLastCtrl = pLastCtrl->next;
pLastCtrl->next = pNewCtrl;
pNewCtrl->prev = pLastCtrl;
}
dskInitInvRgn ((PMAINWIN)pNewCtrl);
pNewCtrl->pcci->nUseCount ++;
return 0;
}
static int dskOnRemoveCtrlInstance (PCONTROL pParent, PCONTROL pCtrl)
{
PCONTROL pFirstCtrl;
BOOL fFound = FALSE;
pFirstCtrl = pParent->children;
if (!pFirstCtrl)
return -1;
else {
if (pFirstCtrl == pCtrl) {
pParent->children = pCtrl->next;
if (pCtrl->next)
pCtrl->next->prev = NULL;
fFound = TRUE;
}
else {
while (pFirstCtrl->next) {
if (pFirstCtrl->next == pCtrl) {
pFirstCtrl->next = pCtrl->next;
if (pFirstCtrl->next)
pFirstCtrl->next->prev = pCtrl->prev;
fFound = TRUE;
break;
}
pFirstCtrl = pFirstCtrl->next;
}
}
}
if (pCtrl->dwExStyle & WS_EX_CTRLASMAINWIN) {
FreeZOrderMaskRect (0, pCtrl->idx_znode);
FreeZOrderNode (0, pCtrl->idx_znode, NULL);
}
if ((HWND)pCtrl == __mg_captured_wnd) {
/* force release the capture */
__mg_captured_wnd = 0;
}
/* Since 5.0.0 */
if ((HWND)pCtrl == sg_hCaretWnd) {
sg_hCaretWnd = 0;
}
if ((HWND)pCtrl == sg_msgAutoRepeat.hwnd) {
sg_msgAutoRepeat.hwnd = 0;
}
if (fFound) {
pCtrl->pcci->nUseCount--;
return 0;
}
return -1;
}
typedef struct _REFRESH_INFO
{
const RECT* invrc;
BOOL is_empty_invrc;
} REFRESH_INFO;
static BOOL _cb_refresh_znode (void* context,
const ZORDERINFO* zi, ZORDERNODE* node)
{
PMAINWIN pTemp;
REFRESH_INFO* info = (REFRESH_INFO*) context;
pTemp = (PMAINWIN)node->hwnd;
if (pTemp
&& ((pTemp->WinType == TYPE_CONTROL &&
(pTemp->dwExStyle & WS_EX_CTRLASMAINWIN))
|| pTemp->WinType != TYPE_CONTROL)
&& pTemp->dwStyle & WS_VISIBLE) {
if (info->is_empty_invrc) {
SendAsyncMessage ((HWND)pTemp, MSG_NCPAINT, 0, 0);
InvalidateRect ((HWND)pTemp, NULL, TRUE);
}
else {
RECT rcTemp, rcInv, rcWin;
if (pTemp->WinType == TYPE_CONTROL &&
(pTemp->dwExStyle & WS_EX_CTRLASMAINWIN)){
dskGetWindowRectInScreen (pTemp, &rcWin);
}
else
GetWindowRect((HWND)pTemp, &rcWin);
if (IntersectRect (&rcTemp,
&rcWin, info->invrc)) {
dskScreenToWindow (pTemp, &rcTemp, &rcInv);
SendAsyncMessage ((HWND)pTemp,
MSG_NCPAINT, 0, (LPARAM)(&rcInv));
dskScreenToClient (pTemp, &rcTemp, &rcInv);
InvalidateRect ((HWND)pTemp, &rcInv, TRUE);
}
}
}
return TRUE;
}
static void dskRefreshAllWindow (const RECT* invrc)
{
REFRESH_INFO info = {invrc, FALSE};
if (invrc->top == invrc->bottom || invrc->left == invrc->right)
info.is_empty_invrc = TRUE;
#ifdef _MGHAVE_MENU
dskForceCloseMenu ();
#endif
SendMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0,
(LPARAM)(info.is_empty_invrc?0:&invrc));
lock_zi_for_read (__mg_zorder_info);
do_for_all_znodes (&info, __mg_zorder_info, _cb_refresh_znode, ZT_ALL);
unlock_zi_for_read (__mg_zorder_info);
}
static int dskRegisterIMEWnd (HWND hwnd)
{
if (__mg_ime_wnd != 0)
return ERR_IME_TOOMUCHIMEWND;
if (!checkAndGetMainWinIfMainWin (hwnd))
return ERR_INV_HWND;
__mg_ime_wnd = hwnd;
SendNotifyMessage (__mg_ime_wnd, MSG_IME_CLOSE, 0, 0);
#ifndef _MGRM_PROCESSES
hwnd = (HWND)dskGetActiveWindow();
if (__mg_ime_wnd != hwnd)
SendNotifyMessage (__mg_ime_wnd, MSG_IME_SETTARGET, (WPARAM)hwnd, 0);
#endif
return ERR_OK;
}
static int dskUnregisterIMEWnd (HWND hwnd)
{
if (__mg_ime_wnd != hwnd)
return ERR_IME_NOSUCHIMEWND;
__mg_ime_wnd = 0;
return ERR_OK;
}
void GUIAPI DesktopUpdateAllWindow(void)
{
SendMessage(HWND_DESKTOP, MSG_PAINT, 0, 0);
}
static void dskOnTimeout (void)
{
static DWORD uCounter = 0;
static DWORD blink_counter = 0;
if (sg_msgAutoRepeat.hwnd != 0 &&
__mg_tick_counter >= sg_msgAutoRepeat.time) {
PostMessage (sg_msgAutoRepeat.hwnd, sg_msgAutoRepeat.message,
sg_msgAutoRepeat.wParam, sg_msgAutoRepeat.lParam);
/* next auto-repeat msg after 50ms */
sg_msgAutoRepeat.time = __mg_tick_counter + (__mg_repeat_usec/10000);
}
if (__mg_tick_counter < (blink_counter + 10))
return;
uCounter += (__mg_tick_counter - blink_counter) * 10;
blink_counter = __mg_tick_counter;
if (sg_hCaretWnd != 0 &&
checkAndGetMainWinIfWindow (sg_hCaretWnd) ==
dskGetActiveWindow() &&
uCounter >= sg_uCaretBTime) {
PostMessage (sg_hCaretWnd, MSG_CARETBLINK, 0, 0);
uCounter = 0;
}
}
static LRESULT DesktopWinProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
static HDC hDesktopDC;
WPARAM flags;
int x, y;
PMAINWIN active_mainwnd = dskGetActiveWindow();
if (message >= MSG_FIRSTWINDOWMSG && message <= MSG_LASTWINDOWMSG)
return WindowMessageHandler (message, (PMAINWIN)wParam, lParam);
if (message == MSG_CHAR && active_mainwnd) {
PostMessage ((HWND)active_mainwnd, message, wParam, lParam);
}
// VW: Since 4.0.0 for extra input messages.
else if (message >= MSG_FIRSTEXTRAINPUTMSG &&
message <= MSG_LASTEXTRAINPUTMSG) {
if (dskPreExtraMessageHandler (message, wParam, lParam))
return 0;
if (do_drag_drop_window (message, 0, 0))
return 0;
PostMessage ((HWND)active_mainwnd, message, wParam, lParam);
}
else if (message >= MSG_FIRSTKEYMSG && message <= MSG_LASTKEYMSG) {
if (dskPreKeyMessageHandler (message, wParam, lParam))
return 0;
if (do_drag_drop_window (message, 0, 0))
return 0;
if (wParam == SCANCODE_PRINTSCREEN && message == MSG_KEYDOWN) {
#ifdef _MGMISC_SAVESCREEN
static int n = 1;
char buffer[64]; // VM: 20 is too small for file name
sprintf (buffer, "%p-%d.bmp", (lParam & KS_CTRL)?
(HWND)active_mainwnd:
0, n);
if (SaveMainWindowContent ((lParam & KS_CTRL)?
(HWND)active_mainwnd:
HWND_DESKTOP,
buffer)) {
Ping ();
n ++;
}
#endif
}
#ifdef _MGHAVE_MENU
else if (wParam == SCANCODE_ESCAPE && lParam & KS_CTRL) {
dskUpdateDesktopMenu (sg_DesktopMenu);
TrackPopupMenu (sg_DesktopMenu, TPM_DEFAULT,
0, g_rcScr.bottom, HWND_DESKTOP);
}
if (sg_ptmi) {
if (PopupMenuTrackProc (sg_ptmi, message, wParam, lParam))
return KeyMessageHandler (message, (int)wParam, (DWORD)lParam);
}
else
#endif
return KeyMessageHandler (message, (int)wParam, (DWORD)lParam);
}
if (message >= MSG_FIRSTMOUSEMSG && message <= MSG_LASTMOUSEMSG) {
if (dskPreMouseMessageHandler (message, wParam, lParam))
return 0;
flags = wParam;
x = LOSWORD (lParam);
y = HISWORD (lParam);
if (do_drag_drop_window (message, x, y))
return 0;
#ifdef _MGHAVE_MENU
if (sg_ptmi) {
if (PopupMenuTrackProc (sg_ptmi, message, x, y))
return MouseMessageHandler (message, flags, x, y);
}
else
#endif
return MouseMessageHandler (message, flags, x, y);
}
if (message == MSG_COMMAND) {
if (wParam <= MAXID_RESERVED && wParam >= MINID_RESERVED) {
#ifdef _MGHAVE_MENU
dskDesktopCommand (sg_DesktopMenu, (int)wParam);
#endif
}
else {
if(dsk_ops->desktop_menucmd_handler)
dsk_ops->desktop_menucmd_handler(dt_context, (int)wParam);
}
return 0;
}
switch (message) {
case MSG_STARTSESSION:
__mg_init_local_sys_text ();
hDesktopDC = GetDC (HWND_DESKTOP);
dsk_ops = &def_dsk_ops;
if (dsk_ops->init)
dt_context = dsk_ops->init (hDesktopDC);
#ifdef _MGHAVE_MENU
sg_DesktopMenu = dskCreateDesktopMenu ();
#endif
break;
case MSG_REINITSESSION:
if (wParam)
__mg_init_local_sys_text ();
#ifdef _MGHAVE_MENU
if (sg_DesktopMenu) {
DestroyMenu (sg_DesktopMenu);
sg_DesktopMenu = 0;
}
sg_DesktopMenu = dskCreateDesktopMenu ();
#endif
SendMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0, 0);
break;
case MSG_REINITDESKOPS:
if (dsk_ops->init) {
dt_context = dsk_ops->init (hDesktopDC);
SendMessage (HWND_DESKTOP, MSG_ERASEDESKTOP, 0, 0);
}
break;
case MSG_ENDSESSION:
__mg_screensaver_destroy ();
if (hDesktopDC)
ReleaseDC (hDesktopDC);
hDesktopDC = 0;
#ifdef _MGHAVE_MENU
if (sg_DesktopMenu) {
DestroyMenu (sg_DesktopMenu);
sg_DesktopMenu = 0;
}
#endif
if (dsk_ops->deinit)
dsk_ops->deinit (dt_context);
PostQuitMessage (HWND_DESKTOP);
return 1;
case MSG_ERASEDESKTOP:
if (dsk_ops->paint_desktop)
dsk_ops->paint_desktop(dt_context, hDesktopDC, (PRECT)lParam);
break;
#ifndef _MGRM_THREADS
case MSG_SETFOCUS: {
HWND active_win = (HWND)dskGetActiveWindow();
if (active_win) {
SendNotifyMessage ((HWND)active_win, MSG_SETFOCUS, 0, 0);
}
break;
}
#endif
case MSG_PAINT: {
RECT invrc;
invrc.left = LOWORD(wParam);
invrc.top = HIWORD(wParam);
invrc.right = LOWORD(lParam);
invrc.bottom = HIWORD(lParam);
dskRefreshAllWindow (&invrc);
break;
}
case MSG_BROADCASTMSG:
return dskBroadcastMessage ((PMSG)lParam);
case MSG_REGISTERWNDCLASS:
return gui_AddNewControlClass ((PWNDCLASS)lParam);
case MSG_UNREGISTERWNDCLASS:
return gui_DeleteControlClass ((const char*)lParam);
case MSG_NEWCTRLINSTANCE:
return dskOnNewCtrlInstance ((PCONTROL)wParam, (PCONTROL)lParam);
case MSG_REMOVECTRLINSTANCE:
return dskOnRemoveCtrlInstance ((PCONTROL)wParam, (PCONTROL)lParam);
case MSG_GETCTRLCLASSINFO:
return (LRESULT)gui_GetControlClassInfo ((const char*)lParam);
case MSG_CTRLCLASSDATAOP:
return (LRESULT)gui_ControlClassDataOp (wParam, (WNDCLASS*)lParam);
/* Since 5.0.0 */
case MSG_REGISTERHOOKFUNC:
return (LRESULT)dskRegisterHookFunc ((int)wParam, (HOOKINFO*)lParam);
/* Since 5.0.0 */
case MSG_REGISTERHOOKWIN:
return (LRESULT)dskRegisterHookWin (0, (HWND)wParam, (DWORD)lParam);
/* Since 5.0.0 */
case MSG_UNREGISTERHOOKWIN:
return (LRESULT)dskUnregisterHookWin (0, (HWND)wParam);
#ifdef _MGHAVE_VIRTUAL_WINDOW
/* Since 5.0.0 */
case MSG_MANAGE_MSGTHREAD:
if (wParam == MSGTHREAD_SIGNIN)
return dskRegisterMsgQueue ((MSGQUEUE*)lParam);
return dskUnregisterMsgQueue ((MSGQUEUE*)lParam);
#endif
/* Since 5.0.0 */
case MSG_CALC_POSITION:
dskCalculateDefaultPosition (0, (CALCPOSINFO*)lParam);
return 0;
case MSG_IME_REGISTER:
return dskRegisterIMEWnd ((HWND)wParam);
case MSG_IME_UNREGISTER:
return dskUnregisterIMEWnd ((HWND)wParam);
case MSG_IME_SETSTATUS:
return dskSetIMEStatus ((int)wParam, (int)lParam);
case MSG_IME_SET_TARGET_INFO:
return dskSetIMETargetInfo ((IME_TARGET_INFO*)lParam);
case MSG_IME_GET_TARGET_INFO:
return dskGetIMETargetInfo ((IME_TARGET_INFO*)lParam);
case MSG_IME_GETSTATUS:
return dskGetIMEStatus ((int)wParam);
#if 0
case MSG_SRVNOTIFY:
BroadcastMessage (MSG_SRVNOTIFY, wParam, lParam);
break;
#endif
/* Since 5.0.6, the desktop handles caret blinking in MSG_TIMEOUT
message, and the interval for this message changes to about 0.05s. */
case MSG_TIMEOUT:
dskOnTimeout ();
// Since 5.0.0: MSG_IDLE messages will be generated by PeekMessage.
// BroadcastMessageInThisThread (MSG_IDLE, wParam, 0);
break;
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:
if(dsk_ops->keyboard_handler)
dsk_ops->keyboard_handler(dt_context, message, wParam, lParam);
break;
#ifdef _MGHAVE_MENU
case MSG_DT_RBUTTONUP:
dskUpdateDesktopMenu (sg_DesktopMenu);
#endif
case MSG_DT_LBUTTONDOWN:
case MSG_DT_LBUTTONUP:
case MSG_DT_LBUTTONDBLCLK:
case MSG_DT_MOUSEMOVE:
case MSG_DT_RBUTTONDOWN:
case MSG_DT_RBUTTONDBLCLK:
case MSG_DT_MBUTTONDOWN:
case MSG_DT_MBUTTONDBLCLK:
case MSG_DT_MBUTTONUP:
if(dsk_ops->mouse_handler)
dsk_ops->mouse_handler(dt_context, message, wParam, lParam);
break;
default:
break;
}
return 0;
}
#endif /* defined(_MGRM_THREADS) || defined(_MGRM_STANDALONE) */