📄 mdi.c
字号:
/**********************************************************************
* MDIRefreshMenu
*/
static LRESULT MDI_RefreshMenu(MDICLIENTINFO *ci)
{
UINT i, count, visible, id;
WCHAR buf[MDI_MAXTITLELENGTH];
TRACE("children %u, window menu %p\n", ci->nActiveChildren, ci->hWindowMenu);
if (!ci->hWindowMenu)
return 0;
if (!IsMenu(ci->hWindowMenu))
{
WARN("Window menu handle %p is no more valid\n", ci->hWindowMenu);
return 0;
}
/* Windows finds the last separator in the menu, and if after it
* there is a menu item with MDI magic ID removes all existing
* menu items after it, and then adds visible MDI children.
*/
count = GetMenuItemCount(ci->hWindowMenu);
for (i = 0; i < count; i++)
{
MENUITEMINFOW mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE;
if (GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii))
{
if (mii.fType & MF_SEPARATOR)
{
/* Windows checks only ID of the menu item */
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID;
if (GetMenuItemInfoW(ci->hWindowMenu, i + 1, TRUE, &mii))
{
if (mii.wID == ci->idFirstChild)
{
TRACE("removing %u items including separator\n", count - i);
while (RemoveMenu(ci->hWindowMenu, i, MF_BYPOSITION))
/* nothing */;
break;
}
}
}
}
}
visible = 0;
for (i = 0; i < ci->nActiveChildren; i++)
{
if (GetWindowLongW(ci->child[i], GWL_STYLE) & WS_VISIBLE)
{
id = ci->idFirstChild + visible;
if (visible == MDI_MOREWINDOWSLIMIT)
{
LoadStringW(User32Instance, IDS_MDI_MOREWINDOWS, buf, sizeof(buf)/sizeof(WCHAR));
AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf);
break;
}
if (!visible)
/* Visio expects that separator has id 0 */
AppendMenuW(ci->hWindowMenu, MF_SEPARATOR, 0, NULL);
visible++;
SetWindowLongPtrW(ci->child[i], GWLP_ID, id);
buf[0] = '&';
buf[1] = '0' + visible;
buf[2] = ' ';
InternalGetWindowText(ci->child[i], buf + 3, sizeof(buf)/sizeof(WCHAR) - 3);
TRACE("Adding %p, id %u %s\n", ci->child[i], id, debugstr_w(buf));
AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf);
if (ci->child[i] == ci->hwndActiveChild)
CheckMenuItem(ci->hWindowMenu, id, MF_CHECKED);
}
else
TRACE("MDI child %p is not visible, skipping\n", ci->child[i]);
}
return (LRESULT)ci->hFrameMenu;
}
/* ------------------ MDI child window functions ---------------------- */
/**********************************************************************
* MDI_ChildGetMinMaxInfo
*
* Note: The rule here is that client rect of the maximized MDI child
* is equal to the client rect of the MDI client window.
*/
static void MDI_ChildGetMinMaxInfo( HWND client, HWND hwnd, MINMAXINFO* lpMinMax )
{
RECT rect;
GetClientRect( client, &rect );
AdjustWindowRectEx( &rect, GetWindowLongW( hwnd, GWL_STYLE ),
0, GetWindowLongW( hwnd, GWL_EXSTYLE ));
lpMinMax->ptMaxSize.x = rect.right -= rect.left;
lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
lpMinMax->ptMaxPosition.x = rect.left;
lpMinMax->ptMaxPosition.y = rect.top;
TRACE("max rect (%ld,%ld - %ld, %ld)\n",
rect.left,rect.top,rect.right,rect.bottom);
}
/**********************************************************************
* MDI_SwitchActiveChild
*
* Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
* being activated
*/
static void MDI_SwitchActiveChild( MDICLIENTINFO *ci, HWND hwndTo, BOOL activate )
{
HWND hwndPrev;
hwndPrev = ci->hwndActiveChild;
TRACE("from %p, to %p\n", hwndPrev, hwndTo);
if ( hwndTo != hwndPrev )
{
BOOL was_zoomed = IsZoomed(hwndPrev);
if (was_zoomed)
{
/* restore old MDI child */
SendMessageW( hwndPrev, WM_SETREDRAW, FALSE, 0 );
ShowWindow( hwndPrev, SW_RESTORE );
SendMessageW( hwndPrev, WM_SETREDRAW, TRUE, 0 );
/* activate new MDI child */
SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
/* maximize new MDI child */
ShowWindow( hwndTo, SW_MAXIMIZE );
}
/* activate new MDI child */
SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | (activate ? 0 : SWP_NOACTIVATE) );
}
}
/**********************************************************************
* MDIDestroyChild
*/
static LRESULT MDIDestroyChild( HWND client, MDICLIENTINFO *ci,
HWND child, BOOL flagDestroy )
{
UINT i;
TRACE("# of managed children %u\n", ci->nActiveChildren);
if( child == ci->hwndActiveChild )
{
HWND next = MDI_GetWindow(ci, child, TRUE, 0);
if (next)
MDI_SwitchActiveChild(ci, next, TRUE);
else
{
ShowWindow(child, SW_HIDE);
if (IsZoomed(child))
{
MDI_RestoreFrameMenu(GetParent(client), child, ci->hBmpClose);
MDI_UpdateFrameText(GetParent(client), client, NULL);
}
MDI_ChildActivate(client, 0);
}
}
for (i = 0; i < ci->nActiveChildren; i++)
{
if (ci->child[i] == child)
{
HWND *new_child = HeapAlloc(GetProcessHeap(), 0, (ci->nActiveChildren - 1) * sizeof(HWND));
memcpy(new_child, ci->child, i * sizeof(HWND));
if (i + 1 < ci->nActiveChildren)
memcpy(new_child + i, ci->child + i + 1, (ci->nActiveChildren - i - 1) * sizeof(HWND));
HeapFree(GetProcessHeap(), 0, ci->child);
ci->child = new_child;
ci->nActiveChildren--;
break;
}
}
SendMessageW(client, WM_MDIREFRESHMENU, 0, 0);
if (flagDestroy)
{
MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
DestroyWindow(child);
}
TRACE("child destroyed - %p\n", child);
return 0;
}
/**********************************************************************
* MDI_ChildActivate
*
* Called in response to WM_CHILDACTIVATE, or when last MDI child
* is being deactivated.
*/
static LONG MDI_ChildActivate( HWND client, HWND child )
{
MDICLIENTINFO *clientInfo;
HWND prevActiveWnd, frame;
BOOL isActiveFrameWnd;
clientInfo = get_client_info( client );
if (clientInfo->hwndActiveChild == child) return 0;
TRACE("%p\n", child);
frame = GetParent(client);
isActiveFrameWnd = (GetActiveWindow() == frame);
prevActiveWnd = clientInfo->hwndActiveChild;
/* deactivate prev. active child */
if(prevActiveWnd)
{
SendMessageW( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
SendMessageW( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child);
}
MDI_SwitchActiveChild( clientInfo, child, FALSE );
clientInfo->hwndActiveChild = child;
MDI_RefreshMenu(clientInfo);
if( isActiveFrameWnd )
{
SendMessageW( child, WM_NCACTIVATE, TRUE, 0L);
SetFocus( client );
}
SendMessageW( child, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child );
return TRUE;
}
/* -------------------- MDI client window functions ------------------- */
/**********************************************************************
* CreateMDIMenuBitmap
*/
static HBITMAP CreateMDIMenuBitmap(void)
{
HDC hDCSrc = CreateCompatibleDC(0);
HDC hDCDest = CreateCompatibleDC(hDCSrc);
HBITMAP hbClose = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_OLD_CLOSE) );
HBITMAP hbCopy;
HBITMAP hobjSrc, hobjDest;
hobjSrc = SelectObject(hDCSrc, hbClose);
hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
hobjDest = SelectObject(hDCDest, hbCopy);
BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
SelectObject(hDCSrc, hobjSrc);
DeleteObject(hbClose);
DeleteDC(hDCSrc);
hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
SelectObject(hDCDest, hobjSrc );
SelectObject(hDCDest, hobjDest);
DeleteDC(hDCDest);
return hbCopy;
}
/**********************************************************************
* MDICascade
*/
static LONG MDICascade( HWND client, MDICLIENTINFO *ci )
{
HWND *win_array;
BOOL has_icons = FALSE;
int i, total;
if (IsZoomed(ci->hwndActiveChild))
SendMessageW(client, WM_MDIRESTORE, (WPARAM)ci->hwndActiveChild, 0);
if (ci->nActiveChildren == 0) return 0;
if (!(win_array = WIN_ListChildren( client ))) return 0;
/* remove all the windows we don't want */
for (i = total = 0; win_array[i]; i++)
{
if (!IsWindowVisible( win_array[i] )) continue;
if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows */
if (IsIconic( win_array[i] ))
{
has_icons = TRUE;
continue;
}
win_array[total++] = win_array[i];
}
win_array[total] = 0;
if (total)
{
INT delta = 0, n = 0, i;
POINT pos[2];
if (has_icons) delta = GetSystemMetrics(SM_CYICONSPACING) + GetSystemMetrics(SM_CYICON);
/* walk the list (backwards) and move windows */
for (i = total - 1; i >= 0; i--)
{
TRACE("move %p to (%ld,%ld) size [%ld,%ld]\n",
win_array[i], pos[0].x, pos[0].y, pos[1].x, pos[1].y);
MDI_CalcDefaultChildPos(client, n++, pos, delta, NULL);
SetWindowPos( win_array[i], 0, pos[0].x, pos[0].y, pos[1].x, pos[1].y,
SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
}
}
HeapFree( GetProcessHeap(), 0, win_array );
if (has_icons) ArrangeIconicWindows( client );
return 0;
}
/**********************************************************************
* MDITile
*/
static void MDITile( HWND client, MDICLIENTINFO *ci, WPARAM wParam )
{
HWND *win_array;
int i, total;
BOOL has_icons = FALSE;
if (IsZoomed(ci->hwndActiveChild))
SendMessageW(client, WM_MDIRESTORE, (WPARAM)ci->hwndActiveChild, 0);
if (ci->nActiveChildren == 0) return;
if (!(win_array = WIN_ListChildren( client ))) return;
/* remove all the windows we don't want */
for (i = total = 0; win_array[i]; i++)
{
if (!IsWindowVisible( win_array[i] )) continue;
if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows (icon titles) */
if (IsIconic( win_array[i] ))
{
has_icons = TRUE;
continue;
}
if ((wParam & MDITILE_SKIPDISABLED) && !IsWindowEnabled( win_array[i] )) continue;
win_array[total++] = win_array[i];
}
win_array[total] = 0;
TRACE("%u windows to tile\n", total);
if (total)
{
HWND *pWnd = win_array;
RECT rect;
int x, y, xsize, ysize;
int rows, columns, r, c, i;
GetClientRect(client,&rect);
rows = (int) sqrt((double)total);
columns = total / rows;
if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */
{
i = rows;
rows = columns; /* exchange r and c */
columns = i;
}
if (has_icons)
{
y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
}
ysize = rect.bottom / rows;
xsize = rect.right / columns;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -