📄 traywnd.c
字号:
/*
* ReactOS Explorer
*
* Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <precomp.h>
static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;
#define WM_APP_TRAYDESTROY (WM_APP + 0x100)
static LONG TrayWndCount = 0;
static const TCHAR szTrayWndClass[] = TEXT("Shell_TrayWnd");
static const ITrayWindowVtbl ITrayWindowImpl_Vtbl;
static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl;
/*
* ITrayWindow
*/
const GUID IID_IShellDesktopTray = {0x213e2df9, 0x9a14, 0x4328, {0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9}};
typedef struct
{
const ITrayWindowVtbl *lpVtbl;
const IShellDesktopTrayVtbl *lpVtblShellDesktopTray;
LONG Ref;
HWND hWnd;
HWND hWndDesktop;
HWND hwndStart;
HIMAGELIST himlStartBtn;
SIZE StartBtnSize;
HFONT hStartBtnFont;
HFONT hCaptionFont;
ITrayBandSite *TrayBandSite;
HWND hwndRebar;
HWND hwndTaskSwitch;
HWND hwndTrayNotify;
DWORD Position;
HMONITOR Monitor;
DWORD DraggingPosition;
HMONITOR DraggingMonitor;
RECT rcTrayWnd[4];
RECT rcNewPosSize;
SIZE TraySize;
union
{
DWORD Flags;
struct
{
DWORD AutoHide : 1;
DWORD AlwaysOnTop : 1;
DWORD SmSmallIcons : 1;
DWORD HideClock : 1;
DWORD Locked : 1;
/* UI Status */
DWORD InSizeMove : 1;
DWORD IsDragging : 1;
DWORD NewPosSize : 1;
};
};
NONCLIENTMETRICS ncm;
HFONT hFont;
IMenuBand *StartMenuBand;
IMenuPopup *StartMenuPopup;
HBITMAP hbmStartMenu;
HWND hWndTrayProperties;
} ITrayWindowImpl;
static IUnknown *
IUnknown_from_impl(ITrayWindowImpl *This)
{
return (IUnknown *)&This->lpVtbl;
}
static ITrayWindow *
ITrayWindow_from_impl(ITrayWindowImpl *This)
{
return (ITrayWindow *)&This->lpVtbl;
}
static IShellDesktopTray *
IShellDesktopTray_from_impl(ITrayWindowImpl *This)
{
return (IShellDesktopTray *)&This->lpVtblShellDesktopTray;
}
static ITrayWindowImpl *
impl_from_ITrayWindow(ITrayWindow *iface)
{
return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl,
lpVtbl));
}
static ITrayWindowImpl *
impl_from_IShellDesktopTray(IShellDesktopTray *iface)
{
return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl,
lpVtblShellDesktopTray));
}
/*
* ITrayWindow
*/
static BOOL
ITrayWindowImpl_UpdateNonClientMetrics(IN OUT ITrayWindowImpl *This)
{
This->ncm.cbSize = sizeof(This->ncm);
if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
sizeof(This->ncm),
&This->ncm,
0))
{
if (This->hFont != NULL)
DeleteObject(This->hFont);
This->hFont = CreateFontIndirect(&This->ncm.lfMessageFont);
return TRUE;
}
return FALSE;
}
static VOID
ITrayWindowImpl_SetWindowsFont(IN OUT ITrayWindowImpl *This)
{
if (This->hwndTrayNotify != NULL)
{
SendMessage(This->hwndTrayNotify,
WM_SETFONT,
(WPARAM)This->hFont,
TRUE);
}
}
static HMONITOR
ITrayWindowImpl_GetScreenRectFromRect(IN OUT ITrayWindowImpl *This,
IN OUT RECT *pRect,
IN DWORD dwFlags)
{
MONITORINFO mi;
HMONITOR hMon;
mi.cbSize = sizeof(mi);
hMon = MonitorFromRect(pRect,
dwFlags);
if (hMon != NULL &&
GetMonitorInfo(hMon,
&mi))
{
*pRect = mi.rcMonitor;
}
else
{
pRect->left = 0;
pRect->top = 0;
pRect->right = GetSystemMetrics(SM_CXSCREEN);
pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
hMon = NULL;
}
return hMon;
}
static HMONITOR
ITrayWindowImpl_GetMonitorFromRect(IN OUT ITrayWindowImpl *This,
IN const RECT *pRect)
{
HMONITOR hMon;
/* In case the monitor sizes or saved sizes differ a bit (probably
not a lot, only so the tray window overlaps into another monitor
now), minimize the risk that we determine a wrong monitor by
using the center point of the tray window if we can't determine
it using the rectangle. */
hMon = MonitorFromRect(pRect,
MONITOR_DEFAULTTONULL);
if (hMon == NULL)
{
POINT pt;
pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
/* be less error-prone, find the nearest monitor */
hMon = MonitorFromPoint(pt,
MONITOR_DEFAULTTONEAREST);
}
return hMon;
}
static HMONITOR
ITrayWindowImpl_GetScreenRect(IN OUT ITrayWindowImpl *This,
IN HMONITOR hMonitor,
IN OUT RECT *pRect)
{
HMONITOR hMon = NULL;
if (hMonitor != NULL)
{
MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (!GetMonitorInfo(This->Monitor,
&mi))
{
/* Hm, the monitor is gone? Try to find a monitor where it
could be located now */
hMon = ITrayWindowImpl_GetMonitorFromRect(This,
pRect);
if (hMon == NULL ||
!GetMonitorInfo(hMon,
&mi))
{
hMon = NULL;
goto GetPrimaryRect;
}
}
*pRect = mi.rcMonitor;
}
else
{
GetPrimaryRect:
pRect->left = 0;
pRect->top = 0;
pRect->right = GetSystemMetrics(SM_CXSCREEN);
pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
}
return hMon;
}
static VOID
ITrayWindowImpl_MakeTrayRectWithSize(IN DWORD Position,
IN const SIZE *pTraySize,
IN OUT RECT *pRect)
{
switch (Position)
{
case ABE_LEFT:
pRect->right = pRect->left + pTraySize->cx;
break;
case ABE_TOP:
pRect->bottom = pRect->top + pTraySize->cy;
break;
case ABE_RIGHT:
pRect->left = pRect->right - pTraySize->cx;
break;
case ABE_BOTTOM:
default:
pRect->top = pRect->bottom - pTraySize->cy;
break;
}
}
static VOID
ITrayWindowImpl_GetTrayRectFromScreenRect(IN OUT ITrayWindowImpl *This,
IN DWORD Position,
IN const RECT *pScreen,
IN const SIZE *pTraySize OPTIONAL,
OUT RECT *pRect)
{
if (pTraySize == NULL)
pTraySize = &This->TraySize;
*pRect = *pScreen;
/* Move the border outside of the screen */
InflateRect(pRect,
GetSystemMetrics(SM_CXEDGE),
GetSystemMetrics(SM_CYEDGE));
ITrayWindowImpl_MakeTrayRectWithSize(Position,
pTraySize,
pRect);
}
BOOL
ITrayWindowImpl_IsPosHorizontal(IN OUT ITrayWindowImpl *This)
{
return This->Position == ABE_TOP || This->Position == ABE_BOTTOM;
}
static HMONITOR
ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl *This,
IN DWORD Position,
IN OUT RECT *pRect)
{
RECT rcScreen;
BOOL Horizontal;
HMONITOR hMon;
SIZE szMax, szWnd;
Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
szWnd.cx = pRect->right - pRect->left;
szWnd.cy = pRect->bottom - pRect->top;
rcScreen = *pRect;
hMon = ITrayWindowImpl_GetScreenRectFromRect(This,
&rcScreen,
MONITOR_DEFAULTTONEAREST);
/* Calculate the maximum size of the tray window and limit the window
size to half of the screen's size. */
szMax.cx = (rcScreen.right - rcScreen.left) / 2;
szMax.cy = (rcScreen.bottom - rcScreen.top) / 2;
if (szWnd.cx > szMax.cx)
szWnd.cx = szMax.cx;
if (szWnd.cy > szMax.cy)
szWnd.cy = szMax.cy;
/* FIXME - calculate */
ITrayWindowImpl_GetTrayRectFromScreenRect(This,
Position,
&rcScreen,
&szWnd,
pRect);
return hMon;
}
#if 0
static VOID
ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl *This,
OUT RECT *pRect)
{
RECT rcMin = {0};
AdjustWindowRectEx(&rcMin,
GetWindowLong(This->hWnd,
GWL_STYLE),
FALSE,
GetWindowLong(This->hWnd,
GWL_EXSTYLE));
*pRect = rcMin;
}
#endif
static DWORD
ITrayWindowImpl_GetDraggingRectFromPt(IN OUT ITrayWindowImpl *This,
IN POINT pt,
OUT RECT *pRect,
OUT HMONITOR *phMonitor)
{
HMONITOR hMon, hMonNew;
DWORD PosH, PosV, Pos;
SIZE DeltaPt, ScreenOffset;
RECT rcScreen;
rcScreen.left = 0;
rcScreen.top = 0;
/* Determine the screen rectangle */
hMon = MonitorFromPoint(pt,
MONITOR_DEFAULTTONULL);
if (hMon != NULL)
{
MONITORINFO mi;
mi.cbSize = sizeof(mi);
if (!GetMonitorInfo(hMon,
&mi))
{
hMon = NULL;
goto GetPrimaryScreenRect;
}
/* make left top corner of the screen zero based to
make calculations easier */
pt.x -= mi.rcMonitor.left;
pt.y -= mi.rcMonitor.top;
ScreenOffset.cx = mi.rcMonitor.left;
ScreenOffset.cy = mi.rcMonitor.top;
rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left;
rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top;
}
else
{
GetPrimaryScreenRect:
ScreenOffset.cx = 0;
ScreenOffset.cy = 0;
rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -