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
);
1692 /* FIXME: what to do here? */
1696 CalculateValidSize(m_Position
, pRect
);
1699 void PopupStartMenu()
1701 if (m_StartMenuPopup
!= NULL
)
1707 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1712 pt
.x
= rcExclude
.left
;
1713 pt
.y
= rcExclude
.top
;
1714 dwFlags
|= MPPF_TOP
;
1717 pt
.x
= rcExclude
.left
;
1718 pt
.y
= rcExclude
.bottom
;
1719 dwFlags
|= MPPF_BOTTOM
;
1722 pt
.x
= rcExclude
.right
;
1723 pt
.y
= rcExclude
.top
;
1724 dwFlags
|= MPPF_RIGHT
;
1727 pt
.x
= rcExclude
.left
;
1728 pt
.y
= rcExclude
.top
;
1729 dwFlags
|= MPPF_LEFT
;
1733 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1735 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1740 void ProcessMouseTracking()
1745 UINT state
= m_AutoHideState
;
1748 GetWindowRect(&rcCurrent
);
1749 over
= PtInRect(&rcCurrent
, pt
);
1751 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1758 if (state
== AUTOHIDE_HIDING
)
1760 TRACE("AutoHide cancelling hide.\n");
1761 m_AutoHideState
= AUTOHIDE_SHOWING
;
1762 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1764 else if (state
== AUTOHIDE_HIDDEN
)
1766 TRACE("AutoHide starting show.\n");
1767 m_AutoHideState
= AUTOHIDE_SHOWING
;
1768 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1773 if (state
== AUTOHIDE_SHOWING
)
1775 TRACE("AutoHide cancelling show.\n");
1776 m_AutoHideState
= AUTOHIDE_HIDING
;
1777 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1779 else if (state
== AUTOHIDE_SHOWN
)
1781 TRACE("AutoHide starting hide.\n");
1782 m_AutoHideState
= AUTOHIDE_HIDING
;
1783 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1786 KillTimer(TIMER_ID_MOUSETRACK
);
1790 void ProcessAutoHide()
1792 RECT rc
= m_TrayRects
[m_Position
];
1793 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1794 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1796 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
);
1798 switch (m_AutoHideState
)
1800 case AUTOHIDE_HIDING
:
1804 m_AutoHideOffset
.cy
= 0;
1805 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1806 if (m_AutoHideOffset
.cx
< -w
)
1807 m_AutoHideOffset
.cx
= -w
;
1810 m_AutoHideOffset
.cx
= 0;
1811 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1812 if (m_AutoHideOffset
.cy
< -h
)
1813 m_AutoHideOffset
.cy
= -h
;
1816 m_AutoHideOffset
.cy
= 0;
1817 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1818 if (m_AutoHideOffset
.cx
> w
)
1819 m_AutoHideOffset
.cx
= w
;
1822 m_AutoHideOffset
.cx
= 0;
1823 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1824 if (m_AutoHideOffset
.cy
> h
)
1825 m_AutoHideOffset
.cy
= h
;
1829 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1831 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1836 case AUTOHIDE_HIDDEN
:
1841 m_AutoHideOffset
.cx
= -w
;
1842 m_AutoHideOffset
.cy
= 0;
1845 m_AutoHideOffset
.cx
= 0;
1846 m_AutoHideOffset
.cy
= -h
;
1849 m_AutoHideOffset
.cx
= w
;
1850 m_AutoHideOffset
.cy
= 0;
1853 m_AutoHideOffset
.cx
= 0;
1854 m_AutoHideOffset
.cy
= h
;
1858 KillTimer(TIMER_ID_AUTOHIDE
);
1859 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1862 case AUTOHIDE_SHOWING
:
1863 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1865 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1867 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1869 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1873 m_AutoHideOffset
.cx
= 0;
1876 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1878 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1880 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1882 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1886 m_AutoHideOffset
.cy
= 0;
1889 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1891 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1896 case AUTOHIDE_SHOWN
:
1898 KillTimer(TIMER_ID_AUTOHIDE
);
1899 m_AutoHideState
= AUTOHIDE_SHOWN
;
1903 rc
.left
+= m_AutoHideOffset
.cx
;
1904 rc
.right
+= m_AutoHideOffset
.cx
;
1905 rc
.top
+= m_AutoHideOffset
.cy
;
1906 rc
.bottom
+= m_AutoHideOffset
.cy
;
1908 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1909 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1916 /**********************************************************
1917 * ##### taskbar drawing #####
1920 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1923 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1925 ASSERT(m_Position
<= ABE_BOTTOM
);
1929 GetClientRect(&rect
);
1930 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1936 int DrawSizerWithTheme(IN HRGN hRgn
)
1940 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1943 ASSERT(m_Position
<= ABE_BOTTOM
);
1945 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
1946 if (FAILED_UNEXPECTEDLY(hr
))
1949 GetWindowRect(&rect
);
1950 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1952 hdc
= GetWindowDC();
1957 rect
.left
= rect
.right
- size
.cx
;
1960 rect
.top
= rect
.bottom
- size
.cy
;
1963 rect
.right
= rect
.left
+ size
.cx
;
1967 rect
.bottom
= rect
.top
+ size
.cy
;
1971 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
1984 HRESULT STDMETHODCALLTYPE
Open()
1988 /* Check if there's already a window created and try to show it.
1989 If it was somehow destroyed just create a new tray window. */
1990 if (m_hWnd
!= NULL
&& IsWindow())
1995 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1997 dwExStyle
|= WS_EX_TOPMOST
;
1999 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
2002 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
2005 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
2006 if (m_Position
!= (DWORD
) -1)
2007 rcWnd
= m_TrayRects
[m_Position
];
2009 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
2012 /* Align all controls on the tray window */
2013 AlignControls(NULL
);
2015 /* Move the tray window to the right position and resize it if necessary */
2016 CheckTrayWndPosition();
2021 HRESULT STDMETHODCALLTYPE
Close()
2034 HWND STDMETHODCALLTYPE
GetHWND()
2039 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2041 return (m_hWnd
== hWnd
||
2042 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2045 BOOL STDMETHODCALLTYPE
IsHorizontal()
2047 return IsPosHorizontal();
2050 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2052 BOOL bPrevLock
= Locked
;
2054 if (Locked
!= bLock
)
2058 if (m_TrayBandSite
!= NULL
)
2060 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2070 /* Update cached tray sizes */
2071 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2073 RECT rcGripper
= {0};
2074 AdjustSizerRect(&rcGripper
, Pos
);
2078 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2079 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2080 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2081 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2085 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2086 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2087 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2088 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2092 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2094 ApplyClipping(TRUE
);
2104 HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup
,
2112 HRESULT hr
= TrayWindowCtxMenuCreator(this, m_hWnd
, &m_ContextMenu
);
2113 if (FAILED_UNEXPECTEDLY(hr
))
2117 return m_ContextMenu
->QueryContextMenu(hPopup
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
2120 HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2123 return E_INVALIDARG
;
2125 return m_ContextMenu
->InvokeCommand(lpici
);
2128 HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd
,
2135 return E_INVALIDARG
;
2137 return m_ContextMenu
->GetCommandString(idCmd
, uType
, pwReserved
, pszName
, cchMax
);
2141 /**********************************************************
2142 * ##### message handling #####
2145 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2149 ((ITrayWindow
*)this)->AddRef();
2151 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2153 /* Create the Start button */
2154 m_StartButton
.Create(m_hWnd
);
2156 /* Load the saved tray window settings */
2159 /* Create and initialize the start menu */
2160 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2161 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2163 /* Create the task band */
2164 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2165 if (FAILED_UNEXPECTEDLY(hRet
))
2168 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2169 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2170 if (FAILED_UNEXPECTEDLY(hRet
))
2173 /* Get the hwnd of the rebar */
2174 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2175 if (FAILED_UNEXPECTEDLY(hRet
))
2178 /* Get the hwnd of the tasks toolbar */
2179 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2180 if (FAILED_UNEXPECTEDLY(hRet
))
2183 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2185 /* Create the tray notification window */
2186 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2190 InitShellServices(&m_ShellServices
);
2194 m_AutoHideState
= AUTOHIDE_HIDING
;
2195 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2198 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2199 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2200 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2201 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2202 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2203 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2204 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2205 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2206 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2207 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2208 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2209 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2214 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2217 CloseThemeData(m_Theme
);
2219 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2223 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2227 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2229 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2234 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2236 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2238 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2240 AlignControls(NULL
);
2241 CheckTrayWndPosition();
2247 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2249 HDC hdc
= (HDC
) wParam
;
2257 return EraseBackgroundWithTheme(hdc
);
2260 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2262 /* Move the tray window to the right position and resize it if necessary */
2263 CheckTrayWndPosition();
2268 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2272 TRACE("WM_COPYDATA notify message received. Handling...\n");
2273 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2278 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2286 return DrawSizerWithTheme((HRGN
) wParam
);
2289 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2291 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2292 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2295 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2302 /* The user may not be able to resize the tray window.
2303 Pretend like the window is not sizeable when the user
2304 clicks on the border. */
2308 SetLastError(ERROR_SUCCESS
);
2309 if (GetClientRect(&rcClient
) &&
2310 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2312 pt
.x
= (SHORT
) LOWORD(lParam
);
2313 pt
.y
= (SHORT
) HIWORD(lParam
);
2315 if (PtInRect(&rcClient
,
2318 /* The user is trying to drag the tray window */
2322 /* Depending on the position of the tray window, allow only
2323 changing the border next to the monitor working area */
2327 if (pt
.y
> rcClient
.bottom
)
2331 if (pt
.x
> rcClient
.right
)
2335 if (pt
.x
< rcClient
.left
)
2340 if (pt
.y
< rcClient
.top
)
2349 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2352 PRECT pRect
= (PRECT
) lParam
;
2354 /* We need to ensure that an application can not accidently
2355 move the tray window (using SetWindowPos). However, we still
2356 need to be able to move the window in case the user wants to
2357 drag the tray window to another position or in case the user
2358 wants to resize the tray window. */
2359 if (!Locked
&& GetCursorPos(&ptCursor
))
2362 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2366 *pRect
= m_TrayRects
[m_Position
];
2370 pRect
->left
+= m_AutoHideOffset
.cx
;
2371 pRect
->right
+= m_AutoHideOffset
.cx
;
2372 pRect
->top
+= m_AutoHideOffset
.cy
;
2373 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2379 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2381 PRECT pRect
= (PRECT
) lParam
;
2389 *pRect
= m_TrayRects
[m_Position
];
2393 pRect
->left
+= m_AutoHideOffset
.cx
;
2394 pRect
->right
+= m_AutoHideOffset
.cx
;
2395 pRect
->top
+= m_AutoHideOffset
.cy
;
2396 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2402 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2404 ChangingWinPos((LPWINDOWPOS
) lParam
);
2408 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2411 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2414 /* Clip the tray window on multi monitor systems so the edges can't
2415 overlap into another monitor */
2416 ApplyClipping(TRUE
);
2418 if (!GetClientRect(&rcClient
))
2425 rcClient
.left
= rcClient
.top
= 0;
2426 rcClient
.right
= LOWORD(lParam
);
2427 rcClient
.bottom
= HIWORD(lParam
);
2430 AlignControls(&rcClient
);
2434 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2440 /* Remove the clipping on multi monitor systems while dragging around */
2441 ApplyClipping(FALSE
);
2446 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2451 /* Apply clipping */
2452 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2457 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2463 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2464 The tray window needs to handle this specially, since it normally doesn't have
2467 static const UINT uidDisableItem
[] = {
2477 /* temporarily enable the system menu */
2478 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2480 hSysMenu
= GetSystemMenu(FALSE
);
2481 if (hSysMenu
!= NULL
)
2483 /* Disable all items that are not relevant */
2484 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2486 EnableMenuItem(hSysMenu
,
2488 MF_BYCOMMAND
| MF_GRAYED
);
2491 EnableMenuItem(hSysMenu
,
2494 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2496 /* Display the system menu */
2500 m_StartButton
.m_hWnd
,
2501 m_Position
!= ABE_TOP
,
2505 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2509 /* revert the system menu window style */
2510 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2520 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2522 /* This handler implements the trick that makes the start button to
2523 get pressed when the user clicked left or below the button */
2525 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2526 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2531 m_StartButton
.GetWindowRect(&rcStartBtn
);
2532 GetWindowInfo(m_hWnd
, &wi
);
2539 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2545 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2548 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2549 pt
.x
> rcStartBtn
.right
)
2557 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2562 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2563 pt
.y
> rcStartBtn
.bottom
)
2577 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2579 /* We want the user to be able to get a context menu even on the nonclient
2580 area (including the sizing border)! */
2581 uMsg
= WM_CONTEXTMENU
;
2582 wParam
= (WPARAM
) m_hWnd
;
2584 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2587 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2589 LRESULT Ret
= FALSE
;
2590 POINT pt
, *ppt
= NULL
;
2591 HWND hWndExclude
= NULL
;
2593 /* Check if the administrator has forbidden access to context menus */
2594 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2597 pt
.x
= (SHORT
) LOWORD(lParam
);
2598 pt
.y
= (SHORT
) HIWORD(lParam
);
2600 if (pt
.x
!= -1 || pt
.y
!= -1)
2603 hWndExclude
= m_StartButton
.m_hWnd
;
2605 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2607 /* Make sure we can't track the context menu if the start
2608 menu is currently being shown */
2609 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2611 CComPtr
<IContextMenu
> ctxMenu
;
2612 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2613 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2618 /* See if the context menu should be handled by the task band site */
2619 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2622 POINT ptClient
= *ppt
;
2624 /* Convert the coordinates to client-coordinates */
2625 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2627 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2628 if (hWndAtPt
!= NULL
&&
2629 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2631 /* Check if the user clicked on the task switch window */
2633 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2635 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2636 if (hWndAtPt
== m_TaskSwitch
)
2637 goto HandleTrayContextMenu
;
2639 /* Forward the message to the task band site */
2640 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2643 goto HandleTrayContextMenu
;
2647 HandleTrayContextMenu
:
2648 /* Tray the default tray window context menu */
2649 TrackCtxMenu(this, ppt
, NULL
, FALSE
, this);
2655 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2657 LRESULT Ret
= FALSE
;
2658 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2659 the rebar control! But we shouldn't forward messages that the band
2660 site doesn't handle, such as other controls (start button, tray window */
2662 HRESULT hr
= E_FAIL
;
2666 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2671 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2673 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2675 if (nmh
->hwndFrom
== m_TrayNotify
)
2680 /* Cause all controls to be aligned */
2681 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2689 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2691 /* We "handle" this message so users can't cause a weird maximize/restore
2692 window animation when double-clicking the tray window! */
2694 /* We should forward mouse messages to child windows here.
2695 Right now, this is only clock double-click */
2697 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2700 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2701 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2702 if (PtInRect(&rcClock
, ptClick
))
2704 //FIXME: use SHRunControlPanel
2705 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2711 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2717 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2720 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2721 if (FAILED_UNEXPECTEDLY(hr
))
2724 if (::IsWindowVisible(hwndStartMenu
))
2726 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2736 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2739 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2740 * to show the shutdown dialog. Also a WM_CLOSE message sent
2741 * by apps should show the dialog.
2743 return DoExitWindows();
2746 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2748 if (wParam
== SC_CLOSE
)
2750 return DoExitWindows();
2757 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2759 return HandleHotKey(wParam
);
2762 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2764 LRESULT Ret
= FALSE
;
2766 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2771 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2773 return HandleCommand(LOWORD(wParam
));
2778 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2782 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2788 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2790 if (wParam
== TIMER_ID_MOUSETRACK
)
2792 ProcessMouseTracking();
2794 else if (wParam
== TIMER_ID_AUTOHIDE
)
2803 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2806 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2807 if(!m_Theme
|| Locked
)
2818 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2819 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2824 rc
= &prms
->rgrc
[0];
2827 AdjustSizerRect(rc
, m_Position
);
2832 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2835 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2841 ::GetWindowRect(m_hWnd
, &rc
);
2845 rc
.bottom
- rc
.top
};
2847 as
->rcTarget
.right
- as
->rcTarget
.left
,
2848 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2850 as
->rcActual
.right
- as
->rcActual
.left
,
2851 as
->rcActual
.bottom
- as
->rcActual
.top
};
2854 szWindow
.cx
- szTarget
.cx
,
2855 szWindow
.cy
- szTarget
.cx
,
2861 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2864 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2867 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2868 rc
.left
= rc
.right
- szWindow
.cy
;
2871 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2872 rc
.top
= rc
.bottom
- szWindow
.cy
;
2876 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2883 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2885 BEGIN_MSG_MAP(CTrayWindow
)
2886 if (m_StartMenuBand
!= NULL
)
2893 Msg
.wParam
= wParam
;
2894 Msg
.lParam
= lParam
;
2896 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2901 wParam
= Msg
.wParam
;
2902 lParam
= Msg
.lParam
;
2904 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2905 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2906 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2907 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2908 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2909 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2910 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2911 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2912 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2913 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2914 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2915 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2916 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2917 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2918 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2919 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2920 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2921 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2922 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2923 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2924 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2925 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2926 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
2927 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2928 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2929 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2930 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2931 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2932 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2933 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2934 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2935 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2936 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2937 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2941 /*****************************************************************************/
2943 VOID
TrayProcessMessages()
2947 /* FIXME: We should keep a reference here... */
2949 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2951 if (Msg
.message
== WM_QUIT
)
2954 if (m_StartMenuBand
== NULL
||
2955 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2957 TranslateMessage(&Msg
);
2958 DispatchMessage(&Msg
);
2963 VOID
TrayMessageLoop()
2968 /* FIXME: We should keep a reference here... */
2972 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2974 if (!Ret
|| Ret
== -1)
2977 if (m_StartMenuBand
== NULL
||
2978 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2980 TranslateMessage(&Msg
);
2981 DispatchMessage(&Msg
);
2989 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2990 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2991 * The reason we implement it is because we have to use SHCreateDesktop() so
2992 * that the shell provides the desktop window and all the features that come
2993 * with it (especially positioning of desktop icons)
2996 virtual ULONG STDMETHODCALLTYPE
GetState()
2998 /* FIXME: Return ABS_ flags? */
2999 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3003 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
3005 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
3006 *phWndTray
= m_hWnd
;
3010 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
3012 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
3014 m_DesktopWnd
= hWndDesktop
;
3018 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
3020 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
3024 virtual HRESULT
RaiseStartButton()
3026 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
3030 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
3033 return E_INVALIDARG
;
3038 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
3045 m_Position
= (DWORD
) -1;
3048 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
3050 DECLARE_PROTECT_FINAL_CONSTRUCT()
3051 BEGIN_COM_MAP(CTrayWindow
)
3052 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3053 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
3054 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
3055 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3059 class CTrayWindowCtxMenu
:
3060 public CComCoClass
<CTrayWindowCtxMenu
>,
3061 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
3065 CComPtr
<CTrayWindow
> TrayWnd
;
3066 CComPtr
<IContextMenu
> pcm
;
3067 UINT m_idCmdCmFirst
;
3070 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3072 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3073 this->hWndOwner
= hWndOwner
;
3074 this->m_idCmdCmFirst
= 0;
3078 virtual HRESULT STDMETHODCALLTYPE
3079 QueryContextMenu(HMENU hPopup
,
3085 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3087 return HRESULT_FROM_WIN32(GetLastError());
3089 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3096 CheckMenuItem(hPopup
,
3098 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3101 idCmdNext
= Shell_MergeMenus(hPopup
, menubase
, indexMenu
, idCmdFirst
, idCmdLast
, MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
3102 m_idCmdCmFirst
= idCmdNext
- idCmdFirst
;
3104 ::DestroyMenu(menubase
);
3106 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3108 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3116 WARN("AddContextMenus failed.\n");
3124 virtual HRESULT STDMETHODCALLTYPE
3125 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3127 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3130 if (uiCmdId
>= m_idCmdCmFirst
)
3132 CMINVOKECOMMANDINFO cmici
= { 0 };
3136 /* Setup and invoke the shell command */
3137 cmici
.cbSize
= sizeof(cmici
);
3138 cmici
.hwnd
= hWndOwner
;
3139 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- m_idCmdCmFirst
);
3140 cmici
.nShow
= SW_NORMAL
;
3142 pcm
->InvokeCommand(&cmici
);
3147 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3154 virtual HRESULT STDMETHODCALLTYPE
3155 GetCommandString(UINT_PTR idCmd
,
3164 CTrayWindowCtxMenu()
3168 virtual ~CTrayWindowCtxMenu()
3172 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3173 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3177 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3179 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3180 mnu
->Initialize(TrayWnd
, hWndOwner
);
3185 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3187 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3189 return E_OUTOFMEMORY
;
3194 *ppTray
= (ITrayWindow
*) Tray
;
3200 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3202 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3203 return TrayWindow
->RaiseStartButton();
3206 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3208 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3209 TrayWindow
->TrayProcessMessages();
3212 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3214 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3215 TrayWindow
->TrayMessageLoop();