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 /* We're about to resize/move the start button, the rebar control and
1536 the tray notification control */
1537 dwp
= BeginDeferWindowPos(3);
1540 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1544 /* Limit the Start button width to the client width, if necessary */
1545 StartSize
= m_StartButton
.GetSize();
1546 if (StartSize
.cx
> rcClient
.right
)
1547 StartSize
.cx
= rcClient
.right
;
1549 if (m_StartButton
.m_hWnd
!= NULL
)
1551 /* Resize and reposition the button */
1552 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1558 SWP_NOZORDER
| SWP_NOACTIVATE
);
1561 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1566 /* Determine the size that the tray notification window needs */
1570 TraySize
.cy
= rcClient
.bottom
;
1574 TraySize
.cx
= rcClient
.right
;
1578 if (m_TrayNotify
!= NULL
&&
1579 SendMessage(m_TrayNotify
,
1580 TNWM_GETMINIMUMSIZE
,
1584 /* Move the tray notification window to the desired location */
1586 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1588 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1590 dwp
= ::DeferWindowPos(dwp
,
1597 SWP_NOZORDER
| SWP_NOACTIVATE
);
1600 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1605 /* Resize/Move the rebar control */
1606 if (m_Rebar
!= NULL
)
1608 POINT ptRebar
= { 0, 0 };
1611 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1615 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1616 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1617 szRebar
.cy
= rcClient
.bottom
;
1621 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1622 szRebar
.cx
= rcClient
.right
;
1623 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1626 dwp
= ::DeferWindowPos(dwp
,
1633 SWP_NOZORDER
| SWP_NOACTIVATE
);
1637 EndDeferWindowPos(dwp
);
1639 if (m_TaskSwitch
!= NULL
)
1641 /* Update the task switch window configuration */
1642 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1646 void FitToRebar(PRECT pRect
)
1648 /* Get the rect of the rebar */
1649 RECT rebarRect
, taskbarRect
;
1650 ::GetWindowRect(m_Rebar
, &rebarRect
);
1651 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1652 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1654 /* Calculate the difference of size of the taskbar and the rebar */
1656 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
1657 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
1659 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1663 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1664 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1665 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1668 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1669 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1670 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1674 /* FIXME: what to do here? */
1678 CalculateValidSize(m_Position
, pRect
);
1681 void PopupStartMenu()
1683 if (m_StartMenuPopup
!= NULL
)
1689 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1694 pt
.x
= rcExclude
.left
;
1695 pt
.y
= rcExclude
.top
;
1696 dwFlags
|= MPPF_TOP
;
1699 pt
.x
= rcExclude
.left
;
1700 pt
.y
= rcExclude
.bottom
;
1701 dwFlags
|= MPPF_BOTTOM
;
1704 pt
.x
= rcExclude
.right
;
1705 pt
.y
= rcExclude
.top
;
1706 dwFlags
|= MPPF_RIGHT
;
1709 pt
.x
= rcExclude
.left
;
1710 pt
.y
= rcExclude
.top
;
1711 dwFlags
|= MPPF_LEFT
;
1715 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1717 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1722 void ProcessMouseTracking()
1727 UINT state
= m_AutoHideState
;
1730 GetWindowRect(&rcCurrent
);
1731 over
= PtInRect(&rcCurrent
, pt
);
1733 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1740 if (state
== AUTOHIDE_HIDING
)
1742 TRACE("AutoHide cancelling hide.\n");
1743 m_AutoHideState
= AUTOHIDE_SHOWING
;
1744 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1746 else if (state
== AUTOHIDE_HIDDEN
)
1748 TRACE("AutoHide starting show.\n");
1749 m_AutoHideState
= AUTOHIDE_SHOWING
;
1750 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1755 if (state
== AUTOHIDE_SHOWING
)
1757 TRACE("AutoHide cancelling show.\n");
1758 m_AutoHideState
= AUTOHIDE_HIDING
;
1759 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1761 else if (state
== AUTOHIDE_SHOWN
)
1763 TRACE("AutoHide starting hide.\n");
1764 m_AutoHideState
= AUTOHIDE_HIDING
;
1765 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1768 KillTimer(TIMER_ID_MOUSETRACK
);
1772 void ProcessAutoHide()
1774 RECT rc
= m_TrayRects
[m_Position
];
1775 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1776 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1778 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
);
1780 switch (m_AutoHideState
)
1782 case AUTOHIDE_HIDING
:
1786 m_AutoHideOffset
.cy
= 0;
1787 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1788 if (m_AutoHideOffset
.cx
< -w
)
1789 m_AutoHideOffset
.cx
= -w
;
1792 m_AutoHideOffset
.cx
= 0;
1793 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1794 if (m_AutoHideOffset
.cy
< -h
)
1795 m_AutoHideOffset
.cy
= -h
;
1798 m_AutoHideOffset
.cy
= 0;
1799 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1800 if (m_AutoHideOffset
.cx
> w
)
1801 m_AutoHideOffset
.cx
= w
;
1804 m_AutoHideOffset
.cx
= 0;
1805 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1806 if (m_AutoHideOffset
.cy
> h
)
1807 m_AutoHideOffset
.cy
= h
;
1811 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1813 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1818 case AUTOHIDE_HIDDEN
:
1823 m_AutoHideOffset
.cx
= -w
;
1824 m_AutoHideOffset
.cy
= 0;
1827 m_AutoHideOffset
.cx
= 0;
1828 m_AutoHideOffset
.cy
= -h
;
1831 m_AutoHideOffset
.cx
= w
;
1832 m_AutoHideOffset
.cy
= 0;
1835 m_AutoHideOffset
.cx
= 0;
1836 m_AutoHideOffset
.cy
= h
;
1840 KillTimer(TIMER_ID_AUTOHIDE
);
1841 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1844 case AUTOHIDE_SHOWING
:
1845 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1847 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1849 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1851 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1855 m_AutoHideOffset
.cx
= 0;
1858 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1860 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1862 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1864 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1868 m_AutoHideOffset
.cy
= 0;
1871 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1873 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1878 case AUTOHIDE_SHOWN
:
1880 KillTimer(TIMER_ID_AUTOHIDE
);
1881 m_AutoHideState
= AUTOHIDE_SHOWN
;
1885 rc
.left
+= m_AutoHideOffset
.cx
;
1886 rc
.right
+= m_AutoHideOffset
.cx
;
1887 rc
.top
+= m_AutoHideOffset
.cy
;
1888 rc
.bottom
+= m_AutoHideOffset
.cy
;
1890 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1891 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1898 /**********************************************************
1899 * ##### taskbar drawing #####
1902 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1905 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1907 ASSERT(m_Position
<= ABE_BOTTOM
);
1911 GetClientRect(&rect
);
1912 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1918 int DrawSizerWithTheme(IN HRGN hRgn
)
1922 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1925 ASSERT(m_Position
<= ABE_BOTTOM
);
1927 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
1928 if (FAILED_UNEXPECTEDLY(hr
))
1931 GetWindowRect(&rect
);
1932 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1934 hdc
= GetWindowDC();
1939 rect
.left
= rect
.right
- size
.cx
;
1942 rect
.top
= rect
.bottom
- size
.cy
;
1945 rect
.right
= rect
.left
+ size
.cx
;
1949 rect
.bottom
= rect
.top
+ size
.cy
;
1953 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
1966 HRESULT STDMETHODCALLTYPE
Open()
1970 /* Check if there's already a window created and try to show it.
1971 If it was somehow destroyed just create a new tray window. */
1972 if (m_hWnd
!= NULL
&& IsWindow())
1977 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1979 dwExStyle
|= WS_EX_TOPMOST
;
1981 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1984 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1987 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1988 if (m_Position
!= (DWORD
) -1)
1989 rcWnd
= m_TrayRects
[m_Position
];
1991 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1994 /* Align all controls on the tray window */
1995 AlignControls(NULL
);
1997 /* Move the tray window to the right position and resize it if necessary */
1998 CheckTrayWndPosition();
2003 HRESULT STDMETHODCALLTYPE
Close()
2016 HWND STDMETHODCALLTYPE
GetHWND()
2021 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2023 return (m_hWnd
== hWnd
||
2024 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2027 BOOL STDMETHODCALLTYPE
IsHorizontal()
2029 return IsPosHorizontal();
2032 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2034 BOOL bPrevLock
= Locked
;
2036 if (Locked
!= bLock
)
2040 if (m_TrayBandSite
!= NULL
)
2042 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2052 /* Update cached tray sizes */
2053 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2055 RECT rcGripper
= {0};
2056 AdjustSizerRect(&rcGripper
, Pos
);
2060 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2061 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2062 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2063 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2067 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2068 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2069 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2070 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2074 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2076 ApplyClipping(TRUE
);
2086 HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup
,
2094 HRESULT hr
= TrayWindowCtxMenuCreator(this, m_hWnd
, &m_ContextMenu
);
2095 if (FAILED_UNEXPECTEDLY(hr
))
2099 return m_ContextMenu
->QueryContextMenu(hPopup
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
2102 HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2105 return E_INVALIDARG
;
2107 return m_ContextMenu
->InvokeCommand(lpici
);
2110 HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd
,
2117 return E_INVALIDARG
;
2119 return m_ContextMenu
->GetCommandString(idCmd
, uType
, pwReserved
, pszName
, cchMax
);
2123 /**********************************************************
2124 * ##### message handling #####
2127 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2131 ((ITrayWindow
*)this)->AddRef();
2133 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2135 /* Create the Start button */
2136 m_StartButton
.Create(m_hWnd
);
2138 /* Load the saved tray window settings */
2141 /* Create and initialize the start menu */
2142 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2143 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2145 /* Create the task band */
2146 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2147 if (FAILED_UNEXPECTEDLY(hRet
))
2150 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2151 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2152 if (FAILED_UNEXPECTEDLY(hRet
))
2155 /* Get the hwnd of the rebar */
2156 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2157 if (FAILED_UNEXPECTEDLY(hRet
))
2160 /* Get the hwnd of the tasks toolbar */
2161 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2162 if (FAILED_UNEXPECTEDLY(hRet
))
2165 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2167 /* Create the tray notification window */
2168 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2172 InitShellServices(&m_ShellServices
);
2176 m_AutoHideState
= AUTOHIDE_HIDING
;
2177 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2180 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2181 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2182 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2183 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2184 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2185 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2186 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2187 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2188 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2189 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2190 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2191 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2196 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2199 CloseThemeData(m_Theme
);
2201 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2205 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2209 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2211 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2216 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2218 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2220 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2222 AlignControls(NULL
);
2223 CheckTrayWndPosition();
2229 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2231 HDC hdc
= (HDC
) wParam
;
2239 return EraseBackgroundWithTheme(hdc
);
2242 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2244 /* Move the tray window to the right position and resize it if necessary */
2245 CheckTrayWndPosition();
2250 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2254 TRACE("WM_COPYDATA notify message received. Handling...\n");
2255 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2260 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2268 return DrawSizerWithTheme((HRGN
) wParam
);
2271 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2273 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2274 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2277 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2284 /* The user may not be able to resize the tray window.
2285 Pretend like the window is not sizeable when the user
2286 clicks on the border. */
2290 SetLastError(ERROR_SUCCESS
);
2291 if (GetClientRect(&rcClient
) &&
2292 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2294 pt
.x
= (SHORT
) LOWORD(lParam
);
2295 pt
.y
= (SHORT
) HIWORD(lParam
);
2297 if (PtInRect(&rcClient
,
2300 /* The user is trying to drag the tray window */
2304 /* Depending on the position of the tray window, allow only
2305 changing the border next to the monitor working area */
2309 if (pt
.y
> rcClient
.bottom
)
2313 if (pt
.x
> rcClient
.right
)
2317 if (pt
.x
< rcClient
.left
)
2322 if (pt
.y
< rcClient
.top
)
2331 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2334 PRECT pRect
= (PRECT
) lParam
;
2336 /* We need to ensure that an application can not accidently
2337 move the tray window (using SetWindowPos). However, we still
2338 need to be able to move the window in case the user wants to
2339 drag the tray window to another position or in case the user
2340 wants to resize the tray window. */
2341 if (!Locked
&& GetCursorPos(&ptCursor
))
2344 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2348 *pRect
= m_TrayRects
[m_Position
];
2352 pRect
->left
+= m_AutoHideOffset
.cx
;
2353 pRect
->right
+= m_AutoHideOffset
.cx
;
2354 pRect
->top
+= m_AutoHideOffset
.cy
;
2355 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2361 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2363 PRECT pRect
= (PRECT
) lParam
;
2371 *pRect
= m_TrayRects
[m_Position
];
2375 pRect
->left
+= m_AutoHideOffset
.cx
;
2376 pRect
->right
+= m_AutoHideOffset
.cx
;
2377 pRect
->top
+= m_AutoHideOffset
.cy
;
2378 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2384 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2386 ChangingWinPos((LPWINDOWPOS
) lParam
);
2390 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2393 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2396 /* Clip the tray window on multi monitor systems so the edges can't
2397 overlap into another monitor */
2398 ApplyClipping(TRUE
);
2400 if (!GetClientRect(&rcClient
))
2407 rcClient
.left
= rcClient
.top
= 0;
2408 rcClient
.right
= LOWORD(lParam
);
2409 rcClient
.bottom
= HIWORD(lParam
);
2412 AlignControls(&rcClient
);
2416 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2422 /* Remove the clipping on multi monitor systems while dragging around */
2423 ApplyClipping(FALSE
);
2428 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2433 /* Apply clipping */
2434 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2439 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2445 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2446 The tray window needs to handle this specially, since it normally doesn't have
2449 static const UINT uidDisableItem
[] = {
2459 /* temporarily enable the system menu */
2460 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2462 hSysMenu
= GetSystemMenu(FALSE
);
2463 if (hSysMenu
!= NULL
)
2465 /* Disable all items that are not relevant */
2466 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2468 EnableMenuItem(hSysMenu
,
2470 MF_BYCOMMAND
| MF_GRAYED
);
2473 EnableMenuItem(hSysMenu
,
2476 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2478 /* Display the system menu */
2482 m_StartButton
.m_hWnd
,
2483 m_Position
!= ABE_TOP
,
2487 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2491 /* revert the system menu window style */
2492 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2502 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2504 /* This handler implements the trick that makes the start button to
2505 get pressed when the user clicked left or below the button */
2507 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2508 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2513 m_StartButton
.GetWindowRect(&rcStartBtn
);
2514 GetWindowInfo(m_hWnd
, &wi
);
2521 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2527 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2530 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2531 pt
.x
> rcStartBtn
.right
)
2539 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2544 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2545 pt
.y
> rcStartBtn
.bottom
)
2559 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2561 /* We want the user to be able to get a context menu even on the nonclient
2562 area (including the sizing border)! */
2563 uMsg
= WM_CONTEXTMENU
;
2564 wParam
= (WPARAM
) m_hWnd
;
2566 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2569 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2571 LRESULT Ret
= FALSE
;
2572 POINT pt
, *ppt
= NULL
;
2573 HWND hWndExclude
= NULL
;
2575 /* Check if the administrator has forbidden access to context menus */
2576 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2579 pt
.x
= (SHORT
) LOWORD(lParam
);
2580 pt
.y
= (SHORT
) HIWORD(lParam
);
2582 if (pt
.x
!= -1 || pt
.y
!= -1)
2585 hWndExclude
= m_StartButton
.m_hWnd
;
2587 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2589 /* Make sure we can't track the context menu if the start
2590 menu is currently being shown */
2591 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2593 CComPtr
<IContextMenu
> ctxMenu
;
2594 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2595 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2600 /* See if the context menu should be handled by the task band site */
2601 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2604 POINT ptClient
= *ppt
;
2606 /* Convert the coordinates to client-coordinates */
2607 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2609 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2610 if (hWndAtPt
!= NULL
&&
2611 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2613 /* Check if the user clicked on the task switch window */
2615 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2617 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2618 if (hWndAtPt
== m_TaskSwitch
)
2619 goto HandleTrayContextMenu
;
2621 /* Forward the message to the task band site */
2622 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2625 goto HandleTrayContextMenu
;
2629 HandleTrayContextMenu
:
2630 /* Tray the default tray window context menu */
2631 TrackCtxMenu(this, ppt
, NULL
, FALSE
, this);
2637 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2639 LRESULT Ret
= FALSE
;
2640 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2641 the rebar control! But we shouldn't forward messages that the band
2642 site doesn't handle, such as other controls (start button, tray window */
2644 HRESULT hr
= E_FAIL
;
2648 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2653 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2655 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2657 if (nmh
->hwndFrom
== m_TrayNotify
)
2662 /* Cause all controls to be aligned */
2663 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2671 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2673 /* We "handle" this message so users can't cause a weird maximize/restore
2674 window animation when double-clicking the tray window! */
2676 /* We should forward mouse messages to child windows here.
2677 Right now, this is only clock double-click */
2679 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2682 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2683 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2684 if (PtInRect(&rcClock
, ptClick
))
2686 //FIXME: use SHRunControlPanel
2687 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2693 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2699 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2702 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2703 if (FAILED_UNEXPECTEDLY(hr
))
2706 if (::IsWindowVisible(hwndStartMenu
))
2708 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2718 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2721 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2722 * to show the shutdown dialog. Also a WM_CLOSE message sent
2723 * by apps should show the dialog.
2725 return DoExitWindows();
2728 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2730 if (wParam
== SC_CLOSE
)
2732 return DoExitWindows();
2739 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2741 return HandleHotKey(wParam
);
2744 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2746 LRESULT Ret
= FALSE
;
2748 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2753 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2755 return HandleCommand(LOWORD(wParam
));
2760 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2764 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2770 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2772 if (wParam
== TIMER_ID_MOUSETRACK
)
2774 ProcessMouseTracking();
2776 else if (wParam
== TIMER_ID_AUTOHIDE
)
2785 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2788 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2789 if(!m_Theme
|| Locked
)
2800 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2801 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2806 rc
= &prms
->rgrc
[0];
2809 AdjustSizerRect(rc
, m_Position
);
2814 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2817 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2823 ::GetWindowRect(m_hWnd
, &rc
);
2827 rc
.bottom
- rc
.top
};
2829 as
->rcTarget
.right
- as
->rcTarget
.left
,
2830 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2832 as
->rcActual
.right
- as
->rcActual
.left
,
2833 as
->rcActual
.bottom
- as
->rcActual
.top
};
2836 szWindow
.cx
- szTarget
.cx
,
2837 szWindow
.cy
- szTarget
.cx
,
2843 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2846 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2849 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2850 rc
.left
= rc
.right
- szWindow
.cy
;
2853 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2854 rc
.top
= rc
.bottom
- szWindow
.cy
;
2858 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2865 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2867 BEGIN_MSG_MAP(CTrayWindow
)
2868 if (m_StartMenuBand
!= NULL
)
2875 Msg
.wParam
= wParam
;
2876 Msg
.lParam
= lParam
;
2878 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2883 wParam
= Msg
.wParam
;
2884 lParam
= Msg
.lParam
;
2886 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2887 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2888 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2889 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2890 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2891 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2892 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2893 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2894 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2895 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2896 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2897 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2898 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2899 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2900 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2901 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2902 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2903 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2904 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2905 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2906 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2907 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2908 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
2909 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2910 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2911 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2912 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2913 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2914 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2915 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2916 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2917 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2918 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2919 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2923 /*****************************************************************************/
2925 VOID
TrayProcessMessages()
2929 /* FIXME: We should keep a reference here... */
2931 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2933 if (Msg
.message
== WM_QUIT
)
2936 if (m_StartMenuBand
== NULL
||
2937 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2939 TranslateMessage(&Msg
);
2940 DispatchMessage(&Msg
);
2945 VOID
TrayMessageLoop()
2950 /* FIXME: We should keep a reference here... */
2954 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2956 if (!Ret
|| Ret
== -1)
2959 if (m_StartMenuBand
== NULL
||
2960 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2962 TranslateMessage(&Msg
);
2963 DispatchMessage(&Msg
);
2971 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2972 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2973 * The reason we implement it is because we have to use SHCreateDesktop() so
2974 * that the shell provides the desktop window and all the features that come
2975 * with it (especially positioning of desktop icons)
2978 virtual ULONG STDMETHODCALLTYPE
GetState()
2980 /* FIXME: Return ABS_ flags? */
2981 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2985 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2987 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2988 *phWndTray
= m_hWnd
;
2992 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2994 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2996 m_DesktopWnd
= hWndDesktop
;
3000 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
3002 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
3006 virtual HRESULT
RaiseStartButton()
3008 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
3012 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
3015 return E_INVALIDARG
;
3020 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
3027 m_Position
= (DWORD
) -1;
3030 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
3032 DECLARE_PROTECT_FINAL_CONSTRUCT()
3033 BEGIN_COM_MAP(CTrayWindow
)
3034 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3035 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
3036 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
3037 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3041 class CTrayWindowCtxMenu
:
3042 public CComCoClass
<CTrayWindowCtxMenu
>,
3043 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
3047 CComPtr
<CTrayWindow
> TrayWnd
;
3048 CComPtr
<IContextMenu
> pcm
;
3049 UINT m_idCmdCmFirst
;
3052 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3054 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3055 this->hWndOwner
= hWndOwner
;
3056 this->m_idCmdCmFirst
= 0;
3060 virtual HRESULT STDMETHODCALLTYPE
3061 QueryContextMenu(HMENU hPopup
,
3067 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3069 return HRESULT_FROM_WIN32(GetLastError());
3071 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3078 CheckMenuItem(hPopup
,
3080 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3083 idCmdNext
= Shell_MergeMenus(hPopup
, menubase
, indexMenu
, idCmdFirst
, idCmdLast
, MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
3084 m_idCmdCmFirst
= idCmdNext
- idCmdFirst
;
3086 ::DestroyMenu(menubase
);
3088 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3090 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3098 WARN("AddContextMenus failed.\n");
3106 virtual HRESULT STDMETHODCALLTYPE
3107 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3109 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3112 if (uiCmdId
>= m_idCmdCmFirst
)
3114 CMINVOKECOMMANDINFO cmici
= { 0 };
3118 /* Setup and invoke the shell command */
3119 cmici
.cbSize
= sizeof(cmici
);
3120 cmici
.hwnd
= hWndOwner
;
3121 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- m_idCmdCmFirst
);
3122 cmici
.nShow
= SW_NORMAL
;
3124 pcm
->InvokeCommand(&cmici
);
3129 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3136 virtual HRESULT STDMETHODCALLTYPE
3137 GetCommandString(UINT_PTR idCmd
,
3146 CTrayWindowCtxMenu()
3150 virtual ~CTrayWindowCtxMenu()
3154 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3155 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3159 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3161 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3162 mnu
->Initialize(TrayWnd
, hWndOwner
);
3167 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3169 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3171 return E_OUTOFMEMORY
;
3176 *ppTray
= (ITrayWindow
*) Tray
;
3182 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3184 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3185 return TrayWindow
->RaiseStartButton();
3188 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3190 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3191 TrayWindow
->TrayProcessMessages();
3194 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3196 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3197 TrayWindow
->TrayMessageLoop();