4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * this library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * this library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
26 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
28 #define TIMER_ID_AUTOHIDE 1
29 #define TIMER_ID_MOUSETRACK 2
30 #define MOUSETRACK_INTERVAL 100
31 #define AUTOHIDE_DELAY_HIDE 2000
32 #define AUTOHIDE_DELAY_SHOW 50
33 #define AUTOHIDE_INTERVAL_ANIMATING 10
35 #define AUTOHIDE_SPEED_SHOW 10
36 #define AUTOHIDE_SPEED_HIDE 1
38 #define AUTOHIDE_HIDDEN 0
39 #define AUTOHIDE_SHOWING 1
40 #define AUTOHIDE_SHOWN 2
41 #define AUTOHIDE_HIDING 3
43 #define IDHK_RUN 0x1f4
44 #define IDHK_MINIMIZE_ALL 0x1f5
45 #define IDHK_RESTORE_ALL 0x1f6
46 #define IDHK_HELP 0x1f7
47 #define IDHK_EXPLORE 0x1f8
48 #define IDHK_FIND 0x1f9
49 #define IDHK_FIND_COMPUTER 0x1fa
50 #define IDHK_NEXT_TASK 0x1fb
51 #define IDHK_PREV_TASK 0x1fc
52 #define IDHK_SYS_PROPERTIES 0x1fd
53 #define IDHK_DESKTOP 0x1fe
54 #define IDHK_PAGER 0x1ff
56 static const WCHAR szTrayWndClass
[] = L
"Shell_TrayWnd";
62 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
65 : public CWindowImpl
<CStartButton
>
67 HIMAGELIST m_ImageList
;
80 virtual ~CStartButton()
82 if (m_ImageList
!= NULL
)
83 ImageList_Destroy(m_ImageList
);
98 if (m_ImageList
== NULL
||
99 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
101 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
) + GetSystemMetrics(SM_CYCAPTION
) * 3;
104 Size
.cy
= max(Size
.cy
, GetSystemMetrics(SM_CYCAPTION
));
106 /* Save the size of the start button */
112 /* Get the system fonts, we use the caption font, always bold, though. */
113 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
114 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
118 DeleteObject(m_Font
);
120 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
121 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
123 SetFont(m_Font
, FALSE
);
128 SubclassWindow(m_hWnd
);
129 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
131 m_ImageList
= ImageList_LoadImageW(hExplorerInstance
,
132 MAKEINTRESOURCEW(IDB_START
),
135 LR_LOADTRANSPARENT
| LR_CREATEDIBSECTION
);
137 BUTTON_IMAGELIST bil
= {m_ImageList
, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT
};
138 SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
);
142 HWND
Create(HWND hwndParent
)
144 WCHAR szStartCaption
[32];
145 if (!LoadStringW(hExplorerInstance
,
148 _countof(szStartCaption
)))
150 wcscpy(szStartCaption
, L
"Start");
153 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| BS_PUSHBUTTON
| BS_LEFT
| BS_VCENTER
;
155 m_hWnd
= CreateWindowEx(
162 (HMENU
) IDC_STARTBTN
,
172 LRESULT
OnLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
174 if (uMsg
== WM_KEYUP
&& wParam
!= VK_SPACE
)
177 GetParent().PostMessage(TWM_OPENSTARTMENU
);
181 BEGIN_MSG_MAP(CStartButton
)
182 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
188 public CComCoClass
<CTrayWindow
>,
189 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
190 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
192 public IShellDesktopTray
,
196 CStartButton m_StartButton
;
198 CComPtr
<IMenuBand
> m_StartMenuBand
;
199 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
201 CComPtr
<IDeskBand
> m_TaskBand
;
202 CComPtr
<IContextMenu
> m_ContextMenu
;
212 CTrayNotifyWnd
* m_TrayNotifyInstance
;
216 HMONITOR m_PreviousMonitor
;
217 DWORD m_DraggingPosition
;
218 HMONITOR m_DraggingMonitor
;
223 HWND m_TrayPropertiesOwner
;
224 HWND m_RunFileDlgOwner
;
226 UINT m_AutoHideState
;
227 SIZE m_AutoHideOffset
;
228 TRACKMOUSEEVENT m_MouseTrackingInfo
;
230 HDPA m_ShellServices
;
233 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
241 DWORD AlwaysOnTop
: 1;
242 DWORD SmSmallIcons
: 1;
247 DWORD InSizeMove
: 1;
248 DWORD IsDragging
: 1;
249 DWORD NewPosSize
: 1;
264 m_PreviousMonitor(NULL
),
265 m_DraggingPosition(0),
266 m_DraggingMonitor(NULL
),
267 m_TrayPropertiesOwner(NULL
),
268 m_RunFileDlgOwner(NULL
),
269 m_AutoHideState(NULL
),
270 m_ShellServices(NULL
),
273 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
274 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
275 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
276 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
279 virtual ~CTrayWindow()
281 if (m_ShellServices
!= NULL
)
283 ShutdownShellServices(m_ShellServices
);
284 m_ShellServices
= NULL
;
289 DeleteObject(m_Font
);
295 CloseThemeData(m_Theme
);
306 /**********************************************************
307 * ##### command handling #####
310 HRESULT
ExecResourceCmd(int id
)
312 WCHAR szCommand
[256];
313 WCHAR
*pszParameters
;
315 if (!LoadStringW(hExplorerInstance
,
318 _countof(szCommand
)))
323 pszParameters
= wcschr(szCommand
, L
'>');
330 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
334 LRESULT
DoExitWindows()
336 ExitWindowsDialog(m_hWnd
);
340 DWORD WINAPI
RunFileDlgThread()
345 m_StartButton
.GetWindowRect(&posRect
);
347 hwnd
= CreateWindowEx(0,
350 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
353 posRect
.right
- posRect
.left
,
354 posRect
.bottom
- posRect
.top
,
360 m_RunFileDlgOwner
= hwnd
;
362 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
364 m_RunFileDlgOwner
= NULL
;
365 ::DestroyWindow(hwnd
);
370 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
372 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
373 return This
->RunFileDlgThread();
376 void DisplayRunFileDlg()
379 if (m_RunFileDlgOwner
)
381 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
382 if (hRunDlg
!= NULL
&&
383 hRunDlg
!= m_RunFileDlgOwner
)
385 SetForegroundWindow(hRunDlg
);
390 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
393 DWORD WINAPI
TrayPropertiesThread()
398 m_StartButton
.GetWindowRect(&posRect
);
399 hwnd
= CreateWindowEx(0,
402 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
405 posRect
.right
- posRect
.left
,
406 posRect
.bottom
- posRect
.top
,
412 m_TrayPropertiesOwner
= hwnd
;
414 DisplayTrayProperties(hwnd
);
416 m_TrayPropertiesOwner
= NULL
;
417 ::DestroyWindow(hwnd
);
422 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
424 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
426 return This
->TrayPropertiesThread();
429 HWND STDMETHODCALLTYPE
DisplayProperties()
433 if (m_TrayPropertiesOwner
)
435 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
436 if (hTrayProp
!= NULL
&&
437 hTrayProp
!= m_TrayPropertiesOwner
)
439 SetForegroundWindow(hTrayProp
);
444 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
448 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
450 WCHAR szDir
[MAX_PATH
];
452 if (SHGetSpecialFolderPath(hWndOwner
,
454 CSIDL_COMMON_STARTMENU
,
457 ShellExecute(hWndOwner
,
466 VOID
OpenTaskManager(IN HWND hWndOwner
)
468 ShellExecute(hWndOwner
,
476 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
480 case ID_SHELL_CMD_PROPERTIES
:
484 case ID_SHELL_CMD_OPEN_ALL_USERS
:
485 OpenCommonStartMenuDirectory(m_hWnd
,
489 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
490 OpenCommonStartMenuDirectory(m_hWnd
,
495 if (SHRestricted(REST_CLASSICSHELL
) == 0)
501 case ID_SHELL_CMD_OPEN_TASKMGR
:
502 OpenTaskManager(m_hWnd
);
505 case ID_SHELL_CMD_UNDO_ACTION
:
508 case ID_SHELL_CMD_SHOW_DESKTOP
:
511 case ID_SHELL_CMD_TILE_WND_H
:
512 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
515 case ID_SHELL_CMD_TILE_WND_V
:
516 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
519 case ID_SHELL_CMD_CASCADE_WND
:
520 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
523 case ID_SHELL_CMD_CUST_NOTIF
:
524 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
527 case ID_SHELL_CMD_ADJUST_DAT
:
528 //FIXME: Use SHRunControlPanel
529 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
533 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
540 LRESULT
HandleHotKey(DWORD id
)
548 ExecResourceCmd(IDS_HELP_COMMAND
);
551 //FIXME: We don't support this yet:
552 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
553 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
556 SHFindFiles(NULL
, NULL
);
558 case IDHK_FIND_COMPUTER
:
559 SHFindComputer(NULL
, NULL
);
561 case IDHK_SYS_PROPERTIES
:
562 //FIXME: Use SHRunControlPanel
563 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
569 case IDHK_MINIMIZE_ALL
:
571 case IDHK_RESTORE_ALL
:
582 LRESULT
HandleCommand(UINT uCommand
)
586 case IDM_TASKBARANDSTARTMENU
:
591 SHFindFiles(NULL
, NULL
);
594 case IDM_HELPANDSUPPORT
:
595 ExecResourceCmd(IDS_HELP_COMMAND
);
602 /* FIXME: Handle these commands as well */
603 case IDM_SYNCHRONIZE
:
605 case IDM_UNDOCKCOMPUTER
:
609 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
623 IN POINT
*ppt OPTIONAL
,
624 IN HWND hwndExclude OPTIONAL
,
626 IN BOOL IsContextMenu
)
628 TPMPARAMS tmp
, *ptmp
= NULL
;
633 if (hwndExclude
!= NULL
)
635 /* Get the client rectangle and map it to screen coordinates */
636 if (::GetClientRect(hwndExclude
,
638 ::MapWindowPoints(hwndExclude
,
640 (LPPOINT
) &tmp
.rcExclude
,
650 GetClientRect(&tmp
.rcExclude
) &&
653 (LPPOINT
) &tmp
.rcExclude
,
661 /* NOTE: TrackPopupMenuEx will eventually align the track position
662 for us, no need to take care of it here as long as the
663 coordinates are somewhere within the exclusion rectangle */
664 pt
.x
= ptmp
->rcExclude
.left
;
665 pt
.y
= ptmp
->rcExclude
.top
;
673 tmp
.cbSize
= sizeof(tmp
);
675 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
676 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
678 fuFlags
|= TPM_RIGHTBUTTON
;
680 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
682 cmdId
= TrackPopupMenuEx(hMenu
,
692 HRESULT
TrackCtxMenu(
693 IN IContextMenu
* contextMenu
,
694 IN POINT
*ppt OPTIONAL
,
695 IN HWND hwndExclude OPTIONAL
,
697 IN PVOID Context OPTIONAL
)
703 HMENU popup
= CreatePopupMenu();
708 TRACE("Before Query\n");
709 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
710 if (FAILED_UNEXPECTEDLY(hr
))
712 TRACE("Query failed\n");
717 TRACE("Before Tracking\n");
718 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
722 TRACE("Before InvokeCommand\n");
723 CMINVOKECOMMANDINFO cmi
= { 0 };
724 cmi
.cbSize
= sizeof(cmi
);
725 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
727 hr
= contextMenu
->InvokeCommand(&cmi
);
731 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
743 /**********************************************************
744 * ##### moving and sizing handling #####
749 /* There is nothing to do if themes are not enabled */
753 m_StartButton
.UpdateFont();
755 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
756 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
758 ERR("SPI_GETNONCLIENTMETRICS failed\n");
763 DeleteObject(m_Font
);
765 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
766 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
769 ERR("CreateFontIndirect failed\n");
773 SendMessage(m_Rebar
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
774 SendMessage(m_TaskSwitch
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
775 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
778 HMONITOR
GetScreenRectFromRect(
785 mi
.cbSize
= sizeof(mi
);
786 hMon
= MonitorFromRect(pRect
, dwFlags
);
788 GetMonitorInfo(hMon
, &mi
))
790 *pRect
= mi
.rcMonitor
;
796 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
797 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
805 HMONITOR
GetMonitorFromRect(
806 IN
const RECT
*pRect
)
810 /* In case the monitor sizes or saved sizes differ a bit (probably
811 not a lot, only so the tray window overlaps into another monitor
812 now), minimize the risk that we determine a wrong monitor by
813 using the center point of the tray window if we can't determine
814 it using the rectangle. */
815 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
820 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
821 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
823 /* be less error-prone, find the nearest monitor */
824 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
830 HMONITOR
GetScreenRect(
831 IN HMONITOR hMonitor
,
834 HMONITOR hMon
= NULL
;
836 if (hMonitor
!= NULL
)
840 mi
.cbSize
= sizeof(mi
);
841 if (!GetMonitorInfo(hMonitor
, &mi
))
843 /* Hm, the monitor is gone? Try to find a monitor where it
844 could be located now */
845 hMon
= GetMonitorFromRect(pRect
);
847 !GetMonitorInfo(hMon
, &mi
))
854 *pRect
= mi
.rcMonitor
;
861 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
862 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
868 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
870 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
873 if (pos
> ABE_BOTTOM
)
876 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[pos
], 0, NULL
, TS_TRUE
, &size
);
877 if (FAILED_UNEXPECTEDLY(hr
))
883 rc
->bottom
-= size
.cy
;
889 rc
->right
-= size
.cx
;
897 VOID
MakeTrayRectWithSize(IN DWORD Position
,
898 IN
const SIZE
*pTraySize
,
904 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
908 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
912 pRect
->left
= pRect
->right
- pTraySize
->cx
;
917 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
922 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
923 IN
const RECT
*pScreen
,
924 IN
const SIZE
*pTraySize OPTIONAL
,
927 if (pTraySize
== NULL
)
928 pTraySize
= &m_TraySize
;
934 /* Move the border outside of the screen */
936 GetSystemMetrics(SM_CXEDGE
),
937 GetSystemMetrics(SM_CYEDGE
));
940 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
943 BOOL
IsPosHorizontal()
945 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
948 HMONITOR
CalculateValidSize(
957 //Horizontal = IsPosHorizontal();
959 szWnd
.cx
= pRect
->right
- pRect
->left
;
960 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
963 hMon
= GetScreenRectFromRect(
965 MONITOR_DEFAULTTONEAREST
);
967 /* Calculate the maximum size of the tray window and limit the window
968 size to half of the screen's size. */
969 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
970 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
971 if (szWnd
.cx
> szMax
.cx
)
973 if (szWnd
.cy
> szMax
.cy
)
976 /* FIXME - calculate */
978 GetTrayRectFromScreenRect(Position
,
988 GetMinimumWindowSize(
993 AdjustWindowRectEx(&rcMin
,
994 GetWindowLong(m_hWnd
,
997 GetWindowLong(m_hWnd
,
1005 DWORD
GetDraggingRectFromPt(
1008 OUT HMONITOR
*phMonitor
)
1010 HMONITOR hMon
, hMonNew
;
1011 DWORD PosH
, PosV
, Pos
;
1012 SIZE DeltaPt
, ScreenOffset
;
1018 /* Determine the screen rectangle */
1019 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
1024 mi
.cbSize
= sizeof(mi
);
1025 if (!GetMonitorInfo(hMon
, &mi
))
1028 goto GetPrimaryScreenRect
;
1031 /* make left top corner of the screen zero based to
1032 make calculations easier */
1033 pt
.x
-= mi
.rcMonitor
.left
;
1034 pt
.y
-= mi
.rcMonitor
.top
;
1036 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1037 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1038 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1039 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1043 GetPrimaryScreenRect
:
1044 ScreenOffset
.cx
= 0;
1045 ScreenOffset
.cy
= 0;
1046 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1047 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1050 /* Calculate the nearest screen border */
1051 if (pt
.x
< rcScreen
.right
/ 2)
1058 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1062 if (pt
.y
< rcScreen
.bottom
/ 2)
1069 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1073 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1075 /* Fix the screen origin to be relative to the primary monitor again */
1076 OffsetRect(&rcScreen
,
1080 RECT rcPos
= m_TrayRects
[Pos
];
1082 hMonNew
= GetMonitorFromRect(&rcPos
);
1083 if (hMon
!= hMonNew
)
1087 /* Recalculate the rectangle, we're dragging to another monitor.
1088 We don't need to recalculate the rect on single monitor systems. */
1089 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1090 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1092 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1095 pRect
->left
+= m_AutoHideOffset
.cx
;
1096 pRect
->right
+= m_AutoHideOffset
.cx
;
1097 pRect
->top
+= m_AutoHideOffset
.cy
;
1098 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1104 /* The user is dragging the tray window on the same monitor. We don't need
1105 to recalculate the rectangle */
1109 pRect
->left
+= m_AutoHideOffset
.cx
;
1110 pRect
->right
+= m_AutoHideOffset
.cx
;
1111 pRect
->top
+= m_AutoHideOffset
.cy
;
1112 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1121 DWORD
GetDraggingRectFromRect(
1123 OUT HMONITOR
*phMonitor
)
1127 /* Calculate the center of the rectangle. We call
1128 GetDraggingRectFromPt to calculate a valid
1129 dragging rectangle */
1130 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1131 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1133 return GetDraggingRectFromPt(
1139 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1145 rcTray
.left
= pwp
->x
;
1146 rcTray
.top
= pwp
->y
;
1147 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1148 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1151 rcTray
.left
-= m_AutoHideOffset
.cx
;
1152 rcTray
.right
-= m_AutoHideOffset
.cx
;
1153 rcTray
.top
-= m_AutoHideOffset
.cy
;
1154 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1157 if (!EqualRect(&rcTray
,
1158 &m_TrayRects
[m_DraggingPosition
]))
1160 /* Recalculate the rectangle, the user dragged the tray
1161 window to another monitor or the window was somehow else
1163 m_DraggingPosition
= GetDraggingRectFromRect(
1165 &m_DraggingMonitor
);
1166 //m_TrayRects[DraggingPosition] = rcTray;
1169 //Monitor = CalculateValidSize(DraggingPosition,
1172 m_Monitor
= m_DraggingMonitor
;
1173 m_Position
= m_DraggingPosition
;
1176 m_TrayRects
[m_Position
] = rcTray
;
1179 else if (GetWindowRect(&rcTray
))
1183 if (!(pwp
->flags
& SWP_NOMOVE
))
1185 rcTray
.left
= pwp
->x
;
1186 rcTray
.top
= pwp
->y
;
1189 if (!(pwp
->flags
& SWP_NOSIZE
))
1191 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1192 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1195 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1197 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1204 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1209 rcTray
.left
-= m_AutoHideOffset
.cx
;
1210 rcTray
.right
-= m_AutoHideOffset
.cx
;
1211 rcTray
.top
-= m_AutoHideOffset
.cy
;
1212 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1214 m_TrayRects
[m_Position
] = rcTray
;
1218 /* If the user isn't resizing the tray window we need to make sure the
1219 new size or position is valid. this is to prevent changes to the window
1220 without user interaction. */
1221 rcTray
= m_TrayRects
[m_Position
];
1225 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1226 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1230 rcTray
.left
+= m_AutoHideOffset
.cx
;
1231 rcTray
.right
+= m_AutoHideOffset
.cx
;
1232 rcTray
.top
+= m_AutoHideOffset
.cy
;
1233 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1236 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1237 pwp
->x
= rcTray
.left
;
1238 pwp
->y
= rcTray
.top
;
1239 pwp
->cx
= m_TraySize
.cx
;
1240 pwp
->cy
= m_TraySize
.cy
;
1244 VOID
ApplyClipping(IN BOOL Clip
)
1246 RECT rcClip
, rcWindow
;
1249 if (GetWindowRect(&rcWindow
))
1251 /* Disable clipping on systems with only one monitor */
1252 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1259 GetScreenRect(m_Monitor
, &rcClip
);
1261 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1270 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1275 /* Set the clipping region or make sure the window isn't clipped
1276 by disabling it explicitly. */
1277 SetWindowRgn(hClipRgn
, TRUE
);
1281 VOID
ResizeWorkArea()
1283 #if !WIN7_DEBUG_MODE
1284 RECT rcTray
, rcWorkArea
;
1286 /* If monitor has changed then fix the previous monitors work area */
1287 if (m_PreviousMonitor
!= m_Monitor
)
1289 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1290 SystemParametersInfoW(SPI_SETWORKAREA
,
1296 rcTray
= m_TrayRects
[m_Position
];
1298 GetScreenRect(m_Monitor
, &rcWorkArea
);
1299 m_PreviousMonitor
= m_Monitor
;
1301 /* If AutoHide is false then change the workarea to exclude
1302 the area that the taskbar covers. */
1308 rcWorkArea
.top
= rcTray
.bottom
;
1311 rcWorkArea
.left
= rcTray
.right
;
1314 rcWorkArea
.right
= rcTray
.left
;
1317 rcWorkArea
.bottom
= rcTray
.top
;
1323 * Resize the current monitor work area. Win32k will also send
1324 * a WM_SIZE message to automatically resize the desktop.
1326 SystemParametersInfoW(SPI_SETWORKAREA
,
1333 VOID
CheckTrayWndPosition()
1337 rcTray
= m_TrayRects
[m_Position
];
1341 rcTray
.left
+= m_AutoHideOffset
.cx
;
1342 rcTray
.right
+= m_AutoHideOffset
.cx
;
1343 rcTray
.top
+= m_AutoHideOffset
.cy
;
1344 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1347 IUnknown_Exec(m_TrayBandSite
,
1349 DBID_BANDINFOCHANGED
,
1354 FitToRebar(&rcTray
);
1355 m_TrayRects
[m_Position
] = rcTray
;
1357 /* Move the tray window */
1361 rcTray
.right
- rcTray
.left
,
1362 rcTray
.bottom
- rcTray
.top
,
1363 SWP_NOZORDER
| SWP_NOACTIVATE
);
1367 ApplyClipping(TRUE
);
1370 typedef struct _TW_STUCKRECTS2
1378 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1380 VOID
RegLoadSettings()
1385 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1386 DWORD cbSize
= sizeof(sr
);
1387 SIZE StartBtnSize
= m_StartButton
.GetSize();
1389 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1390 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1391 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1392 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1394 if (SHGetValue(hkExplorer
,
1395 TEXT("StuckRects2"),
1399 &cbSize
) == ERROR_SUCCESS
&&
1400 sr
.cbSize
== sizeof(sr
))
1402 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1403 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1404 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1405 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1407 /* FIXME: Are there more flags? */
1410 m_Position
= ABE_LEFT
;
1412 if (sr
.Position
> ABE_BOTTOM
)
1413 m_Position
= ABE_BOTTOM
;
1415 m_Position
= sr
.Position
;
1418 /* Try to find out which monitor the tray window was located on last.
1419 Here we're only interested in the monitor screen that we think
1420 is the last one used. We're going to determine on which monitor
1421 we really are after calculating the docked position. */
1423 GetScreenRectFromRect(
1425 MONITOR_DEFAULTTONEAREST
);
1429 m_Position
= ABE_BOTTOM
;
1432 /* Use the minimum size of the taskbar, we'll use the start
1433 button as a minimum for now. Make sure we calculate the
1434 entire window size, not just the client size. However, we
1435 use a thinner border than a standard thick border, so that
1436 the start button and bands are not stuck to the screen border. */
1439 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1440 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1444 sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1445 sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1447 sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1450 /* Use the primary screen by default */
1453 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1454 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1455 GetScreenRectFromRect(
1457 MONITOR_DEFAULTTOPRIMARY
);
1462 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1467 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1469 /* Determine a minimum tray window rectangle. The "client" height is
1470 zero here since we cannot determine an optimal minimum width when
1471 loaded as a vertical tray window. We just need to make sure the values
1472 loaded from the registry are at least. The windows explorer behaves
1473 the same way, it allows the user to save a zero width vertical tray
1474 window, but not a zero height horizontal tray window. */
1477 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1478 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1482 WndSize
.cx
= StartBtnSize
.cx
;
1483 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1486 if (WndSize
.cx
< sr
.Size
.cx
)
1487 WndSize
.cx
= sr
.Size
.cx
;
1488 if (WndSize
.cy
< sr
.Size
.cy
)
1489 WndSize
.cy
= sr
.Size
.cy
;
1491 /* Save the calculated size */
1492 m_TraySize
= WndSize
;
1494 /* Calculate all docking rectangles. We need to do this here so they're
1495 initialized and dragging the tray window to another position gives
1497 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1499 GetTrayRectFromScreenRect(Pos
,
1503 // TRACE("m_TrayRects[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, m_TrayRects[Pos].left, m_TrayRects[Pos].top, m_TrayRects[Pos].right, m_TrayRects[Pos].bottom);
1506 /* Determine which monitor we are on. It shouldn't matter which docked
1507 position rectangle we use */
1508 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1511 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1514 SIZE TraySize
, StartSize
;
1515 POINT ptTrayNotify
= { 0, 0 };
1519 m_StartButton
.UpdateSize();
1520 if (prcClient
!= NULL
)
1522 rcClient
= *prcClient
;
1526 if (!GetClientRect(&rcClient
))
1528 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1533 Horizontal
= IsPosHorizontal();
1535 IUnknown_Exec(m_TrayBandSite
,
1537 DBID_BANDINFOCHANGED
,
1542 /* We're about to resize/move the start button, the rebar control and
1543 the tray notification control */
1544 dwp
= BeginDeferWindowPos(3);
1547 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1551 /* Limit the Start button width to the client width, if necessary */
1552 StartSize
= m_StartButton
.GetSize();
1553 if (StartSize
.cx
> rcClient
.right
)
1554 StartSize
.cx
= rcClient
.right
;
1558 HWND hwndTaskToolbar
= ::GetWindow(m_TaskSwitch
, GW_CHILD
);
1559 if (hwndTaskToolbar
)
1561 DWORD size
= SendMessageW(hwndTaskToolbar
, TB_GETBUTTONSIZE
, 0, 0);
1562 StartSize
.cy
= HIWORD(size
);
1566 if (m_StartButton
.m_hWnd
!= NULL
)
1568 /* Resize and reposition the button */
1569 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1575 SWP_NOZORDER
| SWP_NOACTIVATE
);
1578 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1583 /* Determine the size that the tray notification window needs */
1587 TraySize
.cy
= rcClient
.bottom
;
1591 TraySize
.cx
= rcClient
.right
;
1595 if (m_TrayNotify
!= NULL
&&
1596 SendMessage(m_TrayNotify
,
1597 TNWM_GETMINIMUMSIZE
,
1601 /* Move the tray notification window to the desired location */
1603 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1605 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1607 dwp
= ::DeferWindowPos(dwp
,
1614 SWP_NOZORDER
| SWP_NOACTIVATE
);
1617 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1622 /* Resize/Move the rebar control */
1623 if (m_Rebar
!= NULL
)
1625 POINT ptRebar
= { 0, 0 };
1628 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1632 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1633 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1634 szRebar
.cy
= rcClient
.bottom
;
1638 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1639 szRebar
.cx
= rcClient
.right
;
1640 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1643 dwp
= ::DeferWindowPos(dwp
,
1650 SWP_NOZORDER
| SWP_NOACTIVATE
);
1654 EndDeferWindowPos(dwp
);
1656 if (m_TaskSwitch
!= NULL
)
1658 /* Update the task switch window configuration */
1659 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1663 void FitToRebar(PRECT pRect
)
1665 /* Get the rect of the rebar */
1666 RECT rebarRect
, taskbarRect
, clientRect
;
1667 ::GetWindowRect(m_Rebar
, &rebarRect
);
1668 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1669 ::GetClientRect(m_hWnd
, &clientRect
);
1670 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1672 /* Calculate the difference of size of the taskbar and the rebar */
1674 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- clientRect
.right
+ clientRect
.left
;
1675 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- clientRect
.bottom
+ clientRect
.top
;
1677 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1681 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1682 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1683 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1686 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1687 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1688 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1691 rebarRect
.right
= rebarRect
.left
+ (pRect
->right
- pRect
->left
- margins
.cx
);
1692 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1693 pRect
->right
= pRect
->left
+ (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1696 rebarRect
.left
= rebarRect
.right
- (pRect
->right
- pRect
->left
- margins
.cx
);
1697 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1698 pRect
->left
= pRect
->right
- (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1702 CalculateValidSize(m_Position
, pRect
);
1705 void PopupStartMenu()
1707 if (m_StartMenuPopup
!= NULL
)
1713 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1718 pt
.x
= rcExclude
.left
;
1719 pt
.y
= rcExclude
.top
;
1720 dwFlags
|= MPPF_TOP
;
1723 pt
.x
= rcExclude
.left
;
1724 pt
.y
= rcExclude
.bottom
;
1725 dwFlags
|= MPPF_BOTTOM
;
1728 pt
.x
= rcExclude
.right
;
1729 pt
.y
= rcExclude
.top
;
1730 dwFlags
|= MPPF_RIGHT
;
1733 pt
.x
= rcExclude
.left
;
1734 pt
.y
= rcExclude
.top
;
1735 dwFlags
|= MPPF_LEFT
;
1739 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1741 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1746 void ProcessMouseTracking()
1751 UINT state
= m_AutoHideState
;
1754 GetWindowRect(&rcCurrent
);
1755 over
= PtInRect(&rcCurrent
, pt
);
1757 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1764 if (state
== AUTOHIDE_HIDING
)
1766 TRACE("AutoHide cancelling hide.\n");
1767 m_AutoHideState
= AUTOHIDE_SHOWING
;
1768 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1770 else if (state
== AUTOHIDE_HIDDEN
)
1772 TRACE("AutoHide starting show.\n");
1773 m_AutoHideState
= AUTOHIDE_SHOWING
;
1774 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1779 if (state
== AUTOHIDE_SHOWING
)
1781 TRACE("AutoHide cancelling show.\n");
1782 m_AutoHideState
= AUTOHIDE_HIDING
;
1783 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1785 else if (state
== AUTOHIDE_SHOWN
)
1787 TRACE("AutoHide starting hide.\n");
1788 m_AutoHideState
= AUTOHIDE_HIDING
;
1789 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1792 KillTimer(TIMER_ID_MOUSETRACK
);
1796 void ProcessAutoHide()
1798 RECT rc
= m_TrayRects
[m_Position
];
1799 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1800 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1802 TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", m_AutoHideState
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, w
, h
);
1804 switch (m_AutoHideState
)
1806 case AUTOHIDE_HIDING
:
1810 m_AutoHideOffset
.cy
= 0;
1811 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1812 if (m_AutoHideOffset
.cx
< -w
)
1813 m_AutoHideOffset
.cx
= -w
;
1816 m_AutoHideOffset
.cx
= 0;
1817 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1818 if (m_AutoHideOffset
.cy
< -h
)
1819 m_AutoHideOffset
.cy
= -h
;
1822 m_AutoHideOffset
.cy
= 0;
1823 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1824 if (m_AutoHideOffset
.cx
> w
)
1825 m_AutoHideOffset
.cx
= w
;
1828 m_AutoHideOffset
.cx
= 0;
1829 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1830 if (m_AutoHideOffset
.cy
> h
)
1831 m_AutoHideOffset
.cy
= h
;
1835 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1837 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1842 case AUTOHIDE_HIDDEN
:
1847 m_AutoHideOffset
.cx
= -w
;
1848 m_AutoHideOffset
.cy
= 0;
1851 m_AutoHideOffset
.cx
= 0;
1852 m_AutoHideOffset
.cy
= -h
;
1855 m_AutoHideOffset
.cx
= w
;
1856 m_AutoHideOffset
.cy
= 0;
1859 m_AutoHideOffset
.cx
= 0;
1860 m_AutoHideOffset
.cy
= h
;
1864 KillTimer(TIMER_ID_AUTOHIDE
);
1865 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1868 case AUTOHIDE_SHOWING
:
1869 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1871 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1873 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1875 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1879 m_AutoHideOffset
.cx
= 0;
1882 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1884 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1886 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1888 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1892 m_AutoHideOffset
.cy
= 0;
1895 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1897 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1902 case AUTOHIDE_SHOWN
:
1904 KillTimer(TIMER_ID_AUTOHIDE
);
1905 m_AutoHideState
= AUTOHIDE_SHOWN
;
1909 rc
.left
+= m_AutoHideOffset
.cx
;
1910 rc
.right
+= m_AutoHideOffset
.cx
;
1911 rc
.top
+= m_AutoHideOffset
.cy
;
1912 rc
.bottom
+= m_AutoHideOffset
.cy
;
1914 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1915 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1922 /**********************************************************
1923 * ##### taskbar drawing #####
1926 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1929 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1931 ASSERT(m_Position
<= ABE_BOTTOM
);
1935 GetClientRect(&rect
);
1936 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1942 int DrawSizerWithTheme(IN HRGN hRgn
)
1946 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1949 ASSERT(m_Position
<= ABE_BOTTOM
);
1951 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
1952 if (FAILED_UNEXPECTEDLY(hr
))
1955 GetWindowRect(&rect
);
1956 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1958 hdc
= GetWindowDC();
1963 rect
.left
= rect
.right
- size
.cx
;
1966 rect
.top
= rect
.bottom
- size
.cy
;
1969 rect
.right
= rect
.left
+ size
.cx
;
1973 rect
.bottom
= rect
.top
+ size
.cy
;
1977 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
1990 HRESULT STDMETHODCALLTYPE
Open()
1994 /* Check if there's already a window created and try to show it.
1995 If it was somehow destroyed just create a new tray window. */
1996 if (m_hWnd
!= NULL
&& IsWindow())
2001 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
2003 dwExStyle
|= WS_EX_TOPMOST
;
2005 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
2008 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
2011 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
2012 if (m_Position
!= (DWORD
) -1)
2013 rcWnd
= m_TrayRects
[m_Position
];
2015 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
2018 /* Align all controls on the tray window */
2019 AlignControls(NULL
);
2021 /* Move the tray window to the right position and resize it if necessary */
2022 CheckTrayWndPosition();
2027 HRESULT STDMETHODCALLTYPE
Close()
2040 HWND STDMETHODCALLTYPE
GetHWND()
2045 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2047 return (m_hWnd
== hWnd
||
2048 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2051 BOOL STDMETHODCALLTYPE
IsHorizontal()
2053 return IsPosHorizontal();
2056 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2058 BOOL bPrevLock
= Locked
;
2060 if (Locked
!= bLock
)
2064 if (m_TrayBandSite
!= NULL
)
2066 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2076 /* Update cached tray sizes */
2077 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2079 RECT rcGripper
= {0};
2080 AdjustSizerRect(&rcGripper
, Pos
);
2084 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2085 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2086 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2087 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2091 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2092 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2093 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2094 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2098 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2100 ApplyClipping(TRUE
);
2110 HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup
,
2118 HRESULT hr
= TrayWindowCtxMenuCreator(this, m_hWnd
, &m_ContextMenu
);
2119 if (FAILED_UNEXPECTEDLY(hr
))
2123 return m_ContextMenu
->QueryContextMenu(hPopup
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
2126 HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2129 return E_INVALIDARG
;
2131 return m_ContextMenu
->InvokeCommand(lpici
);
2134 HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd
,
2141 return E_INVALIDARG
;
2143 return m_ContextMenu
->GetCommandString(idCmd
, uType
, pwReserved
, pszName
, cchMax
);
2147 /**********************************************************
2148 * ##### message handling #####
2151 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2155 ((ITrayWindow
*)this)->AddRef();
2157 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2159 /* Create the Start button */
2160 m_StartButton
.Create(m_hWnd
);
2162 /* Load the saved tray window settings */
2165 /* Create and initialize the start menu */
2166 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2167 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2169 /* Create the task band */
2170 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2171 if (FAILED_UNEXPECTEDLY(hRet
))
2174 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2175 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2176 if (FAILED_UNEXPECTEDLY(hRet
))
2179 /* Get the hwnd of the rebar */
2180 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2181 if (FAILED_UNEXPECTEDLY(hRet
))
2184 /* Get the hwnd of the tasks toolbar */
2185 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2186 if (FAILED_UNEXPECTEDLY(hRet
))
2189 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2191 /* Create the tray notification window */
2192 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2196 InitShellServices(&m_ShellServices
);
2200 m_AutoHideState
= AUTOHIDE_HIDING
;
2201 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2204 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2205 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2206 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2207 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2208 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2209 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2210 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2211 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2212 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2213 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2214 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2215 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2220 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2223 CloseThemeData(m_Theme
);
2225 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2229 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2233 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2235 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2240 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2242 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2244 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2246 AlignControls(NULL
);
2247 CheckTrayWndPosition();
2253 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2255 HDC hdc
= (HDC
) wParam
;
2263 return EraseBackgroundWithTheme(hdc
);
2266 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2268 /* Move the tray window to the right position and resize it if necessary */
2269 CheckTrayWndPosition();
2274 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2278 TRACE("WM_COPYDATA notify message received. Handling...\n");
2279 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2284 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2292 return DrawSizerWithTheme((HRGN
) wParam
);
2295 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2297 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2298 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2301 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2308 /* The user may not be able to resize the tray window.
2309 Pretend like the window is not sizeable when the user
2310 clicks on the border. */
2314 SetLastError(ERROR_SUCCESS
);
2315 if (GetClientRect(&rcClient
) &&
2316 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2318 pt
.x
= (SHORT
) LOWORD(lParam
);
2319 pt
.y
= (SHORT
) HIWORD(lParam
);
2321 if (PtInRect(&rcClient
,
2324 /* The user is trying to drag the tray window */
2328 /* Depending on the position of the tray window, allow only
2329 changing the border next to the monitor working area */
2333 if (pt
.y
> rcClient
.bottom
)
2337 if (pt
.x
> rcClient
.right
)
2341 if (pt
.x
< rcClient
.left
)
2346 if (pt
.y
< rcClient
.top
)
2355 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2358 PRECT pRect
= (PRECT
) lParam
;
2360 /* We need to ensure that an application can not accidently
2361 move the tray window (using SetWindowPos). However, we still
2362 need to be able to move the window in case the user wants to
2363 drag the tray window to another position or in case the user
2364 wants to resize the tray window. */
2365 if (!Locked
&& GetCursorPos(&ptCursor
))
2368 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2372 *pRect
= m_TrayRects
[m_Position
];
2376 pRect
->left
+= m_AutoHideOffset
.cx
;
2377 pRect
->right
+= m_AutoHideOffset
.cx
;
2378 pRect
->top
+= m_AutoHideOffset
.cy
;
2379 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2385 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2387 PRECT pRect
= (PRECT
) lParam
;
2395 *pRect
= m_TrayRects
[m_Position
];
2399 pRect
->left
+= m_AutoHideOffset
.cx
;
2400 pRect
->right
+= m_AutoHideOffset
.cx
;
2401 pRect
->top
+= m_AutoHideOffset
.cy
;
2402 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2408 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2410 ChangingWinPos((LPWINDOWPOS
) lParam
);
2414 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2417 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2420 /* Clip the tray window on multi monitor systems so the edges can't
2421 overlap into another monitor */
2422 ApplyClipping(TRUE
);
2424 if (!GetClientRect(&rcClient
))
2431 rcClient
.left
= rcClient
.top
= 0;
2432 rcClient
.right
= LOWORD(lParam
);
2433 rcClient
.bottom
= HIWORD(lParam
);
2436 AlignControls(&rcClient
);
2440 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2446 /* Remove the clipping on multi monitor systems while dragging around */
2447 ApplyClipping(FALSE
);
2452 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2457 /* Apply clipping */
2458 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2463 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2469 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2470 The tray window needs to handle this specially, since it normally doesn't have
2473 static const UINT uidDisableItem
[] = {
2483 /* temporarily enable the system menu */
2484 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2486 hSysMenu
= GetSystemMenu(FALSE
);
2487 if (hSysMenu
!= NULL
)
2489 /* Disable all items that are not relevant */
2490 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2492 EnableMenuItem(hSysMenu
,
2494 MF_BYCOMMAND
| MF_GRAYED
);
2497 EnableMenuItem(hSysMenu
,
2500 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2502 /* Display the system menu */
2506 m_StartButton
.m_hWnd
,
2507 m_Position
!= ABE_TOP
,
2511 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2515 /* revert the system menu window style */
2516 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2526 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2528 /* This handler implements the trick that makes the start button to
2529 get pressed when the user clicked left or below the button */
2531 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2532 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2537 m_StartButton
.GetWindowRect(&rcStartBtn
);
2538 GetWindowInfo(m_hWnd
, &wi
);
2545 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2551 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2554 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2555 pt
.x
> rcStartBtn
.right
)
2563 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2568 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2569 pt
.y
> rcStartBtn
.bottom
)
2583 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2585 /* We want the user to be able to get a context menu even on the nonclient
2586 area (including the sizing border)! */
2587 uMsg
= WM_CONTEXTMENU
;
2588 wParam
= (WPARAM
) m_hWnd
;
2590 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2593 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2595 LRESULT Ret
= FALSE
;
2596 POINT pt
, *ppt
= NULL
;
2597 HWND hWndExclude
= NULL
;
2599 /* Check if the administrator has forbidden access to context menus */
2600 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2603 pt
.x
= (SHORT
) LOWORD(lParam
);
2604 pt
.y
= (SHORT
) HIWORD(lParam
);
2606 if (pt
.x
!= -1 || pt
.y
!= -1)
2609 hWndExclude
= m_StartButton
.m_hWnd
;
2611 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2613 /* Make sure we can't track the context menu if the start
2614 menu is currently being shown */
2615 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2617 CComPtr
<IContextMenu
> ctxMenu
;
2618 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2619 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2624 /* See if the context menu should be handled by the task band site */
2625 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2628 POINT ptClient
= *ppt
;
2630 /* Convert the coordinates to client-coordinates */
2631 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2633 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2634 if (hWndAtPt
!= NULL
&&
2635 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2637 /* Check if the user clicked on the task switch window */
2639 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2641 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2642 if (hWndAtPt
== m_TaskSwitch
)
2643 goto HandleTrayContextMenu
;
2645 /* Forward the message to the task band site */
2646 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2649 goto HandleTrayContextMenu
;
2653 HandleTrayContextMenu
:
2654 /* Tray the default tray window context menu */
2655 TrackCtxMenu(this, ppt
, NULL
, FALSE
, this);
2661 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2663 LRESULT Ret
= FALSE
;
2664 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2665 the rebar control! But we shouldn't forward messages that the band
2666 site doesn't handle, such as other controls (start button, tray window */
2668 HRESULT hr
= E_FAIL
;
2672 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2677 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2679 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2681 if (nmh
->hwndFrom
== m_TrayNotify
)
2686 /* Cause all controls to be aligned */
2687 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2695 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2697 /* We "handle" this message so users can't cause a weird maximize/restore
2698 window animation when double-clicking the tray window! */
2700 /* We should forward mouse messages to child windows here.
2701 Right now, this is only clock double-click */
2703 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2706 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2707 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2708 if (PtInRect(&rcClock
, ptClick
))
2710 //FIXME: use SHRunControlPanel
2711 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2717 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2723 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2726 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2727 if (FAILED_UNEXPECTEDLY(hr
))
2730 if (::IsWindowVisible(hwndStartMenu
))
2732 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2742 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2745 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2746 * to show the shutdown dialog. Also a WM_CLOSE message sent
2747 * by apps should show the dialog.
2749 return DoExitWindows();
2752 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2754 if (wParam
== SC_CLOSE
)
2756 return DoExitWindows();
2763 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2765 return HandleHotKey(wParam
);
2768 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2770 LRESULT Ret
= FALSE
;
2772 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2777 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2779 return HandleCommand(LOWORD(wParam
));
2784 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2788 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2794 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2796 if (wParam
== TIMER_ID_MOUSETRACK
)
2798 ProcessMouseTracking();
2800 else if (wParam
== TIMER_ID_AUTOHIDE
)
2809 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2812 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2813 if(!m_Theme
|| Locked
)
2824 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2825 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2830 rc
= &prms
->rgrc
[0];
2833 AdjustSizerRect(rc
, m_Position
);
2838 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2841 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2847 ::GetWindowRect(m_hWnd
, &rc
);
2851 rc
.bottom
- rc
.top
};
2853 as
->rcTarget
.right
- as
->rcTarget
.left
,
2854 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2856 as
->rcActual
.right
- as
->rcActual
.left
,
2857 as
->rcActual
.bottom
- as
->rcActual
.top
};
2860 szWindow
.cx
- szTarget
.cx
,
2861 szWindow
.cy
- szTarget
.cx
,
2867 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2870 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2873 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2874 rc
.left
= rc
.right
- szWindow
.cy
;
2877 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2878 rc
.top
= rc
.bottom
- szWindow
.cy
;
2882 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2889 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2891 BEGIN_MSG_MAP(CTrayWindow
)
2892 if (m_StartMenuBand
!= NULL
)
2899 Msg
.wParam
= wParam
;
2900 Msg
.lParam
= lParam
;
2902 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2907 wParam
= Msg
.wParam
;
2908 lParam
= Msg
.lParam
;
2910 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2911 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2912 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2913 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2914 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2915 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2916 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2917 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2918 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2919 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2920 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2921 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2922 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2923 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2924 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2925 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2926 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2927 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2928 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2929 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2930 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2931 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2932 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
2933 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2934 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2935 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2936 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2937 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2938 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2939 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2940 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2941 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2942 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2943 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2947 /*****************************************************************************/
2949 VOID
TrayProcessMessages()
2953 /* FIXME: We should keep a reference here... */
2955 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2957 if (Msg
.message
== WM_QUIT
)
2960 if (m_StartMenuBand
== NULL
||
2961 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2963 TranslateMessage(&Msg
);
2964 DispatchMessage(&Msg
);
2969 VOID
TrayMessageLoop()
2974 /* FIXME: We should keep a reference here... */
2978 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2980 if (!Ret
|| Ret
== -1)
2983 if (m_StartMenuBand
== NULL
||
2984 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2986 TranslateMessage(&Msg
);
2987 DispatchMessage(&Msg
);
2995 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2996 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2997 * The reason we implement it is because we have to use SHCreateDesktop() so
2998 * that the shell provides the desktop window and all the features that come
2999 * with it (especially positioning of desktop icons)
3002 virtual ULONG STDMETHODCALLTYPE
GetState()
3004 /* FIXME: Return ABS_ flags? */
3005 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3009 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
3011 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
3012 *phWndTray
= m_hWnd
;
3016 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
3018 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
3020 m_DesktopWnd
= hWndDesktop
;
3024 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
3026 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
3030 virtual HRESULT
RaiseStartButton()
3032 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
3036 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
3039 return E_INVALIDARG
;
3044 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
3051 m_Position
= (DWORD
) -1;
3054 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
3056 DECLARE_PROTECT_FINAL_CONSTRUCT()
3057 BEGIN_COM_MAP(CTrayWindow
)
3058 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3059 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
3060 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
3061 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3065 class CTrayWindowCtxMenu
:
3066 public CComCoClass
<CTrayWindowCtxMenu
>,
3067 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
3071 CComPtr
<CTrayWindow
> TrayWnd
;
3072 CComPtr
<IContextMenu
> pcm
;
3073 UINT m_idCmdCmFirst
;
3076 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3078 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3079 this->hWndOwner
= hWndOwner
;
3080 this->m_idCmdCmFirst
= 0;
3084 virtual HRESULT STDMETHODCALLTYPE
3085 QueryContextMenu(HMENU hPopup
,
3091 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3093 return HRESULT_FROM_WIN32(GetLastError());
3095 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3102 CheckMenuItem(hPopup
,
3104 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3107 idCmdNext
= Shell_MergeMenus(hPopup
, menubase
, indexMenu
, idCmdFirst
, idCmdLast
, MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
3108 m_idCmdCmFirst
= idCmdNext
- idCmdFirst
;
3110 ::DestroyMenu(menubase
);
3112 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3114 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3122 WARN("AddContextMenus failed.\n");
3130 virtual HRESULT STDMETHODCALLTYPE
3131 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3133 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3136 if (uiCmdId
>= m_idCmdCmFirst
)
3138 CMINVOKECOMMANDINFO cmici
= { 0 };
3142 /* Setup and invoke the shell command */
3143 cmici
.cbSize
= sizeof(cmici
);
3144 cmici
.hwnd
= hWndOwner
;
3145 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- m_idCmdCmFirst
);
3146 cmici
.nShow
= SW_NORMAL
;
3148 pcm
->InvokeCommand(&cmici
);
3153 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3160 virtual HRESULT STDMETHODCALLTYPE
3161 GetCommandString(UINT_PTR idCmd
,
3170 CTrayWindowCtxMenu()
3174 virtual ~CTrayWindowCtxMenu()
3178 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3179 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3183 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3185 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3186 mnu
->Initialize(TrayWnd
, hWndOwner
);
3191 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3193 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3195 return E_OUTOFMEMORY
;
3200 *ppTray
= (ITrayWindow
*) Tray
;
3206 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3208 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3209 return TrayWindow
->RaiseStartButton();
3212 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3214 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3215 TrayWindow
->TrayProcessMessages();
3218 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3220 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3221 TrayWindow
->TrayMessageLoop();