📄 traywnd.c
字号:
rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
}
/* Calculate the nearest screen border */
if (pt.x < rcScreen.right / 2)
{
DeltaPt.cx = pt.x;
PosH = ABE_LEFT;
}
else
{
DeltaPt.cx = rcScreen.right - pt.x;
PosH = ABE_RIGHT;
}
if (pt.y < rcScreen.bottom / 2)
{
DeltaPt.cy = pt.y;
PosV = ABE_TOP;
}
else
{
DeltaPt.cy = rcScreen.bottom - pt.y;
PosV = ABE_BOTTOM;
}
Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
/* Fix the screen origin to be relative to the primary monitor again */
OffsetRect(&rcScreen,
ScreenOffset.cx,
ScreenOffset.cy);
hMonNew = ITrayWindowImpl_GetMonitorFromRect(This,
&This->rcTrayWnd[Pos]);
if (hMon != hMonNew)
{
SIZE szTray;
/* Recalculate the rectangle, we're dragging to another monitor.
We don't need to recalculate the rect on single monitor systems. */
szTray.cx = This->rcTrayWnd[Pos].right - This->rcTrayWnd[Pos].left;
szTray.cy = This->rcTrayWnd[Pos].bottom - This->rcTrayWnd[Pos].top;
ITrayWindowImpl_GetTrayRectFromScreenRect(This,
Pos,
&rcScreen,
&szTray,
pRect);
hMon = hMonNew;
}
else
{
/* The user is dragging the tray window on the same monitor. We don't need
to recalculate the rectangle */
*pRect = This->rcTrayWnd[Pos];
}
*phMonitor = hMon;
return Pos;
}
static DWORD
ITrayWindowImpl_GetDraggingRectFromRect(IN OUT ITrayWindowImpl *This,
IN OUT RECT *pRect,
OUT HMONITOR *phMonitor)
{
POINT pt;
/* Calculate the center of the rectangle. We call
ITrayWindowImpl_GetDraggingRectFromPt to calculate a valid
dragging rectangle */
pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
return ITrayWindowImpl_GetDraggingRectFromPt(This,
pt,
pRect,
phMonitor);
}
static VOID
ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This,
IN OUT LPWINDOWPOS pwp)
{
RECT rcTray;
if (This->IsDragging)
{
rcTray.left = pwp->x;
rcTray.top = pwp->y;
rcTray.right = rcTray.left + pwp->cx;
rcTray.bottom = rcTray.top + pwp->cy;
if (!EqualRect(&rcTray,
&This->rcTrayWnd[This->DraggingPosition]))
{
/* Recalculate the rectangle, the user dragged the tray
window to another monitor or the window was somehow else
moved or resized */
This->DraggingPosition = ITrayWindowImpl_GetDraggingRectFromRect(This,
&rcTray,
&This->DraggingMonitor);
//This->rcTrayWnd[This->DraggingPosition] = rcTray;
}
//This->Monitor = ITrayWindowImpl_CalculateValidSize(This,
// This->DraggingPosition,
// &rcTray);
This->Monitor = This->DraggingMonitor;
This->Position = This->DraggingPosition;
This->IsDragging = FALSE;
This->rcTrayWnd[This->Position] = rcTray;
goto ChangePos;
}
else if (GetWindowRect(This->hWnd,
&rcTray))
{
if (This->InSizeMove)
{
if (!(pwp->flags & SWP_NOMOVE))
{
rcTray.left = pwp->x;
rcTray.top = pwp->y;
}
if (!(pwp->flags & SWP_NOSIZE))
{
rcTray.right = rcTray.left + pwp->cx;
rcTray.bottom = rcTray.top + pwp->cy;
}
This->Position = ITrayWindowImpl_GetDraggingRectFromRect(This,
&rcTray,
&This->Monitor);
if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
{
SIZE szWnd;
szWnd.cx = pwp->cx;
szWnd.cy = pwp->cy;
ITrayWindowImpl_MakeTrayRectWithSize(This->Position,
&szWnd,
&rcTray);
}
This->rcTrayWnd[This->Position] = rcTray;
}
else
{
/* If the user isn't resizing the tray window we need to make sure the
new size or position is valid. This is to prevent changes to the window
without user interaction. */
rcTray = This->rcTrayWnd[This->Position];
}
ChangePos:
This->TraySize.cx = rcTray.right - rcTray.left;
This->TraySize.cy = rcTray.bottom - rcTray.top;
pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
pwp->x = rcTray.left;
pwp->y = rcTray.top;
pwp->cx = This->TraySize.cx;
pwp->cy = This->TraySize.cy;
}
}
static VOID
ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl *This,
IN BOOL Clip)
{
RECT rcClip, rcWindow;
HRGN hClipRgn;
if (GetWindowRect(This->hWnd,
&rcWindow))
{
/* Disable clipping on systems with only one monitor */
if (GetSystemMetrics(SM_CMONITORS) <= 1)
Clip = FALSE;
if (Clip)
{
rcClip = rcWindow;
ITrayWindowImpl_GetScreenRect(This,
This->Monitor,
&rcClip);
if (!IntersectRect(&rcClip,
&rcClip,
&rcWindow))
{
rcClip = rcWindow;
}
OffsetRect(&rcClip,
-rcWindow.left,
-rcWindow.top);
hClipRgn = CreateRectRgnIndirect(&rcClip);
}
else
hClipRgn = NULL;
/* Set the clipping region or make sure the window isn't clipped
by disabling it explicitly. */
SetWindowRgn(This->hWnd,
hClipRgn,
TRUE);
}
}
static VOID
ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl *This)
{
RECT rcTray;
rcTray = This->rcTrayWnd[This->Position];
// DbgPrint("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
/* Move the tray window */
SetWindowPos(This->hWnd,
NULL,
rcTray.left,
rcTray.top,
rcTray.right - rcTray.left,
rcTray.bottom - rcTray.top,
SWP_NOZORDER);
ITrayWindowImpl_ApplyClipping(This,
TRUE);
}
typedef struct _TW_STUCKRECTS2
{
DWORD cbSize;
LONG Unknown;
DWORD dwFlags;
DWORD Position;
SIZE Size;
RECT Rect;
} TW_STRUCKRECTS2, *PTW_STUCKRECTS2;
static VOID
ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
{
DWORD Pos;
TW_STRUCKRECTS2 sr;
RECT rcScreen;
SIZE WndSize, EdgeSize, DlgFrameSize;
DWORD cbSize = sizeof(sr);
EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
if (SHGetValue(hkExplorer,
TEXT("StuckRects2"),
TEXT("Settings"),
NULL,
&sr,
&cbSize) == ERROR_SUCCESS &&
sr.cbSize == sizeof(sr))
{
This->AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0;
This->AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0;
This->SmSmallIcons = (sr.dwFlags & 0x4) != 0;
This->HideClock = (sr.dwFlags & 0x8) != 0;
/* FIXME: Are there more flags? */
if (sr.Position > ABE_BOTTOM)
This->Position = ABE_BOTTOM;
else
This->Position = sr.Position;
/* Try to find out which monitor the tray window was located on last.
Here we're only interested in the monitor screen that we think
is the last one used. We're going to determine on which monitor
we really are after calculating the docked position. */
rcScreen = sr.Rect;
ITrayWindowImpl_GetScreenRectFromRect(This,
&rcScreen,
MONITOR_DEFAULTTONEAREST);
}
else
{
This->Position = ABE_BOTTOM;
/* Use the minimum size of the taskbar, we'll use the start
button as a minimum for now. Make sure we calculate the
entire window size, not just the client size. However, we
use a thinner border than a standard thick border, so that
the start button and bands are not stuck to the screen border. */
sr.Size.cx = This->StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
sr.Size.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
/* Use the primary screen by default */
rcScreen.left = 0;
rcScreen.top = 0;
rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
rcScreen.right = GetSystemMetrics(SM_CYSCREEN);
ITrayWindowImpl_GetScreenRectFromRect(This,
&rcScreen,
MONITOR_DEFAULTTOPRIMARY);
}
/* Determine a minimum tray window rectangle. The "client" height is
zero here since we cannot determine an optimal minimum width when
loaded as a vertical tray window. We just need to make sure the values
loaded from the registry are at least. The windows explorer behaves
the same way, it allows the user to save a zero width vertical tray
window, but not a zero height horizontal tray window. */
WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
WndSize.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
if (WndSize.cx < sr.Size.cx)
WndSize.cx = sr.Size.cx;
if (WndSize.cy < sr.Size.cy)
WndSize.cy = sr.Size.cy;
/* Save the calculated size */
This->TraySize = WndSize;
/* Calculate all docking rectangles. We need to do this here so they're
initialized and dragging the tray window to another position gives
usable results */
for (Pos = ABE_LEFT;
Pos <= ABE_BOTTOM;
Pos++)
{
ITrayWindowImpl_GetTrayRectFromScreenRect(This,
Pos,
&rcScreen,
&This->TraySize,
&This->rcTrayWnd[Pos]);
// DbgPrint("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom);
}
/* Determine which monitor we are on. It shouldn't matter which docked
position rectangle we use */
This->Monitor = ITrayWindowImpl_GetMonitorFromRect(This,
&This->rcTrayWnd[ABE_LEFT]);
}
static UINT
ITrayWindowImpl_TrackMenu(IN OUT ITrayWindowImpl *This,
IN HMENU hMenu,
IN POINT *ppt OPTIONAL,
IN HWND hwndExclude OPTIONAL,
IN BOOL TrackUp,
IN BOOL IsContextMenu)
{
TPMPARAMS tmp, *ptmp = NULL;
POINT pt;
UINT cmdId;
UINT fuFlags;
if (hwndExclude != NULL)
{
/* Get the client rectangle and map it to screen coordinates */
if (GetClientRect(hwndExclude,
&tmp.rcExclude) &&
MapWindowPoints(hwndExclude,
NULL,
(LPPOINT)&tmp.rcExclude,
2) != 0)
{
ptmp = &tmp;
}
}
if (ppt == NULL)
{
if (ptmp == NULL &&
GetClientRect(This->hWnd,
&tmp.rcExclude) &&
MapWindowPoints(This->hWnd,
NULL,
(LPPOINT)&tmp.rcExclude,
2) != 0)
{
ptmp = &tmp;
}
if (ptmp != NULL)
{
/* NOTE: TrackPopupMenuEx will eventually align the track position
for us, no need to take care of it here as long as the
coordinates are somewhere within the exclusion rectangle */
pt.x = ptmp->rcExclude.left;
pt.y = ptmp->rcExclude.top;
}
else
pt.x = pt.y = 0;
}
else
pt = *ppt;
tmp.cbSize = sizeof(tmp);
fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
if (IsContextMenu)
fuFlags |= TPM_RIGHTBUTTON;
else
fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
cmdId = TrackPopupMenuEx(hMenu,
fuFlags,
pt.x,
pt.y,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -