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
,
195 CStartButton m_StartButton
;
197 CComPtr
<IMenuBand
> m_StartMenuBand
;
198 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
200 CComPtr
<IDeskBand
> m_TaskBand
;
210 CTrayNotifyWnd
* m_TrayNotifyInstance
;
214 HMONITOR m_PreviousMonitor
;
215 DWORD m_DraggingPosition
;
216 HMONITOR m_DraggingMonitor
;
221 HWND m_TrayPropertiesOwner
;
222 HWND m_RunFileDlgOwner
;
224 UINT m_AutoHideState
;
225 SIZE m_AutoHideOffset
;
226 TRACKMOUSEEVENT m_MouseTrackingInfo
;
228 HDPA m_ShellServices
;
231 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
239 DWORD AlwaysOnTop
: 1;
240 DWORD SmSmallIcons
: 1;
245 DWORD InSizeMove
: 1;
246 DWORD IsDragging
: 1;
247 DWORD NewPosSize
: 1;
262 m_PreviousMonitor(NULL
),
263 m_DraggingPosition(0),
264 m_DraggingMonitor(NULL
),
265 m_TrayPropertiesOwner(NULL
),
266 m_RunFileDlgOwner(NULL
),
267 m_AutoHideState(NULL
),
268 m_ShellServices(NULL
),
271 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
272 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
273 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
274 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
277 virtual ~CTrayWindow()
279 if (m_ShellServices
!= NULL
)
281 ShutdownShellServices(m_ShellServices
);
282 m_ShellServices
= NULL
;
287 DeleteObject(m_Font
);
293 CloseThemeData(m_Theme
);
304 /**********************************************************
305 * ##### command handling #####
308 HRESULT
ExecResourceCmd(int id
)
310 WCHAR szCommand
[256];
311 WCHAR
*pszParameters
;
313 if (!LoadStringW(hExplorerInstance
,
316 _countof(szCommand
)))
321 pszParameters
= wcschr(szCommand
, L
'>');
328 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
332 LRESULT
DoExitWindows()
334 ExitWindowsDialog(m_hWnd
);
338 DWORD WINAPI
RunFileDlgThread()
343 m_StartButton
.GetWindowRect(&posRect
);
345 hwnd
= CreateWindowEx(0,
348 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
351 posRect
.right
- posRect
.left
,
352 posRect
.bottom
- posRect
.top
,
358 m_RunFileDlgOwner
= hwnd
;
360 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
362 m_RunFileDlgOwner
= NULL
;
363 ::DestroyWindow(hwnd
);
368 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
370 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
371 return This
->RunFileDlgThread();
374 void DisplayRunFileDlg()
377 if (m_RunFileDlgOwner
)
379 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
380 if (hRunDlg
!= NULL
&&
381 hRunDlg
!= m_RunFileDlgOwner
)
383 SetForegroundWindow(hRunDlg
);
388 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
391 DWORD WINAPI
TrayPropertiesThread()
396 m_StartButton
.GetWindowRect(&posRect
);
397 hwnd
= CreateWindowEx(0,
400 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
403 posRect
.right
- posRect
.left
,
404 posRect
.bottom
- posRect
.top
,
410 m_TrayPropertiesOwner
= hwnd
;
412 DisplayTrayProperties(hwnd
);
414 m_TrayPropertiesOwner
= NULL
;
415 ::DestroyWindow(hwnd
);
420 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
422 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
424 return This
->TrayPropertiesThread();
427 HWND STDMETHODCALLTYPE
DisplayProperties()
431 if (m_TrayPropertiesOwner
)
433 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
434 if (hTrayProp
!= NULL
&&
435 hTrayProp
!= m_TrayPropertiesOwner
)
437 SetForegroundWindow(hTrayProp
);
442 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
446 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
448 WCHAR szDir
[MAX_PATH
];
450 if (SHGetSpecialFolderPath(hWndOwner
,
452 CSIDL_COMMON_STARTMENU
,
455 ShellExecute(hWndOwner
,
464 VOID
OpenTaskManager(IN HWND hWndOwner
)
466 ShellExecute(hWndOwner
,
474 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
478 case ID_SHELL_CMD_PROPERTIES
:
482 case ID_SHELL_CMD_OPEN_ALL_USERS
:
483 OpenCommonStartMenuDirectory(m_hWnd
,
487 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
488 OpenCommonStartMenuDirectory(m_hWnd
,
493 if (SHRestricted(REST_CLASSICSHELL
) == 0)
499 case ID_SHELL_CMD_OPEN_TASKMGR
:
500 OpenTaskManager(m_hWnd
);
503 case ID_SHELL_CMD_UNDO_ACTION
:
506 case ID_SHELL_CMD_SHOW_DESKTOP
:
509 case ID_SHELL_CMD_TILE_WND_H
:
510 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
513 case ID_SHELL_CMD_TILE_WND_V
:
514 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
517 case ID_SHELL_CMD_CASCADE_WND
:
518 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
521 case ID_SHELL_CMD_CUST_NOTIF
:
522 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
525 case ID_SHELL_CMD_ADJUST_DAT
:
526 //FIXME: Use SHRunControlPanel
527 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
531 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
538 LRESULT
HandleHotKey(DWORD id
)
546 ExecResourceCmd(IDS_HELP_COMMAND
);
549 //FIXME: We don't support this yet:
550 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
551 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
554 SHFindFiles(NULL
, NULL
);
556 case IDHK_FIND_COMPUTER
:
557 SHFindComputer(NULL
, NULL
);
559 case IDHK_SYS_PROPERTIES
:
560 //FIXME: Use SHRunControlPanel
561 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
567 case IDHK_MINIMIZE_ALL
:
569 case IDHK_RESTORE_ALL
:
580 LRESULT
HandleCommand(UINT uCommand
)
584 case IDM_TASKBARANDSTARTMENU
:
589 SHFindFiles(NULL
, NULL
);
592 case IDM_HELPANDSUPPORT
:
593 ExecResourceCmd(IDS_HELP_COMMAND
);
600 /* FIXME: Handle these commands as well */
601 case IDM_SYNCHRONIZE
:
603 case IDM_UNDOCKCOMPUTER
:
607 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
621 IN POINT
*ppt OPTIONAL
,
622 IN HWND hwndExclude OPTIONAL
,
624 IN BOOL IsContextMenu
)
626 TPMPARAMS tmp
, *ptmp
= NULL
;
631 if (hwndExclude
!= NULL
)
633 /* Get the client rectangle and map it to screen coordinates */
634 if (::GetClientRect(hwndExclude
,
636 ::MapWindowPoints(hwndExclude
,
638 (LPPOINT
) &tmp
.rcExclude
,
648 GetClientRect(&tmp
.rcExclude
) &&
651 (LPPOINT
) &tmp
.rcExclude
,
659 /* NOTE: TrackPopupMenuEx will eventually align the track position
660 for us, no need to take care of it here as long as the
661 coordinates are somewhere within the exclusion rectangle */
662 pt
.x
= ptmp
->rcExclude
.left
;
663 pt
.y
= ptmp
->rcExclude
.top
;
671 tmp
.cbSize
= sizeof(tmp
);
673 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
674 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
676 fuFlags
|= TPM_RIGHTBUTTON
;
678 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
680 cmdId
= TrackPopupMenuEx(hMenu
,
690 HRESULT
TrackCtxMenu(
691 IN IContextMenu
* contextMenu
,
692 IN POINT
*ppt OPTIONAL
,
693 IN HWND hwndExclude OPTIONAL
,
695 IN PVOID Context OPTIONAL
)
701 HMENU popup
= CreatePopupMenu();
706 TRACE("Before Query\n");
707 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
708 if (FAILED_UNEXPECTEDLY(hr
))
710 TRACE("Query failed\n");
715 TRACE("Before Tracking\n");
716 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
720 TRACE("Before InvokeCommand\n");
721 CMINVOKECOMMANDINFO cmi
= { 0 };
722 cmi
.cbSize
= sizeof(cmi
);
723 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
725 hr
= contextMenu
->InvokeCommand(&cmi
);
729 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
741 /**********************************************************
742 * ##### moving and sizing handling #####
747 /* There is nothing to do if themes are not enabled */
751 m_StartButton
.UpdateFont();
753 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
754 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
756 ERR("SPI_GETNONCLIENTMETRICS failed\n");
761 DeleteObject(m_Font
);
763 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
764 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
767 ERR("CreateFontIndirect failed\n");
771 SendMessage(m_Rebar
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
772 SendMessage(m_TaskSwitch
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
773 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
776 HMONITOR
GetScreenRectFromRect(
783 mi
.cbSize
= sizeof(mi
);
784 hMon
= MonitorFromRect(pRect
, dwFlags
);
786 GetMonitorInfo(hMon
, &mi
))
788 *pRect
= mi
.rcMonitor
;
794 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
795 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
803 HMONITOR
GetMonitorFromRect(
804 IN
const RECT
*pRect
)
808 /* In case the monitor sizes or saved sizes differ a bit (probably
809 not a lot, only so the tray window overlaps into another monitor
810 now), minimize the risk that we determine a wrong monitor by
811 using the center point of the tray window if we can't determine
812 it using the rectangle. */
813 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
818 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
819 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
821 /* be less error-prone, find the nearest monitor */
822 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
828 HMONITOR
GetScreenRect(
829 IN HMONITOR hMonitor
,
832 HMONITOR hMon
= NULL
;
834 if (hMonitor
!= NULL
)
838 mi
.cbSize
= sizeof(mi
);
839 if (!GetMonitorInfo(hMonitor
, &mi
))
841 /* Hm, the monitor is gone? Try to find a monitor where it
842 could be located now */
843 hMon
= GetMonitorFromRect(pRect
);
845 !GetMonitorInfo(hMon
, &mi
))
852 *pRect
= mi
.rcMonitor
;
859 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
860 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
866 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
868 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
871 if (pos
> ABE_BOTTOM
)
874 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[pos
], 0, NULL
, TS_TRUE
, &size
);
875 if (FAILED_UNEXPECTEDLY(hr
))
881 rc
->bottom
-= size
.cy
;
887 rc
->right
-= size
.cx
;
895 VOID
MakeTrayRectWithSize(IN DWORD Position
,
896 IN
const SIZE
*pTraySize
,
902 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
906 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
910 pRect
->left
= pRect
->right
- pTraySize
->cx
;
915 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
920 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
921 IN
const RECT
*pScreen
,
922 IN
const SIZE
*pTraySize OPTIONAL
,
925 if (pTraySize
== NULL
)
926 pTraySize
= &m_TraySize
;
932 /* Move the border outside of the screen */
934 GetSystemMetrics(SM_CXEDGE
),
935 GetSystemMetrics(SM_CYEDGE
));
938 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
941 BOOL
IsPosHorizontal()
943 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
946 HMONITOR
CalculateValidSize(
955 //Horizontal = IsPosHorizontal();
957 szWnd
.cx
= pRect
->right
- pRect
->left
;
958 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
961 hMon
= GetScreenRectFromRect(
963 MONITOR_DEFAULTTONEAREST
);
965 /* Calculate the maximum size of the tray window and limit the window
966 size to half of the screen's size. */
967 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
968 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
969 if (szWnd
.cx
> szMax
.cx
)
971 if (szWnd
.cy
> szMax
.cy
)
974 /* FIXME - calculate */
976 GetTrayRectFromScreenRect(Position
,
986 GetMinimumWindowSize(
991 AdjustWindowRectEx(&rcMin
,
992 GetWindowLong(m_hWnd
,
995 GetWindowLong(m_hWnd
,
1003 DWORD
GetDraggingRectFromPt(
1006 OUT HMONITOR
*phMonitor
)
1008 HMONITOR hMon
, hMonNew
;
1009 DWORD PosH
, PosV
, Pos
;
1010 SIZE DeltaPt
, ScreenOffset
;
1016 /* Determine the screen rectangle */
1017 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
1022 mi
.cbSize
= sizeof(mi
);
1023 if (!GetMonitorInfo(hMon
, &mi
))
1026 goto GetPrimaryScreenRect
;
1029 /* make left top corner of the screen zero based to
1030 make calculations easier */
1031 pt
.x
-= mi
.rcMonitor
.left
;
1032 pt
.y
-= mi
.rcMonitor
.top
;
1034 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1035 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1036 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1037 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1041 GetPrimaryScreenRect
:
1042 ScreenOffset
.cx
= 0;
1043 ScreenOffset
.cy
= 0;
1044 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1045 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1048 /* Calculate the nearest screen border */
1049 if (pt
.x
< rcScreen
.right
/ 2)
1056 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1060 if (pt
.y
< rcScreen
.bottom
/ 2)
1067 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1071 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1073 /* Fix the screen origin to be relative to the primary monitor again */
1074 OffsetRect(&rcScreen
,
1078 RECT rcPos
= m_TrayRects
[Pos
];
1080 hMonNew
= GetMonitorFromRect(&rcPos
);
1081 if (hMon
!= hMonNew
)
1085 /* Recalculate the rectangle, we're dragging to another monitor.
1086 We don't need to recalculate the rect on single monitor systems. */
1087 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1088 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1090 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1093 pRect
->left
+= m_AutoHideOffset
.cx
;
1094 pRect
->right
+= m_AutoHideOffset
.cx
;
1095 pRect
->top
+= m_AutoHideOffset
.cy
;
1096 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1102 /* The user is dragging the tray window on the same monitor. We don't need
1103 to recalculate the rectangle */
1107 pRect
->left
+= m_AutoHideOffset
.cx
;
1108 pRect
->right
+= m_AutoHideOffset
.cx
;
1109 pRect
->top
+= m_AutoHideOffset
.cy
;
1110 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1119 DWORD
GetDraggingRectFromRect(
1121 OUT HMONITOR
*phMonitor
)
1125 /* Calculate the center of the rectangle. We call
1126 GetDraggingRectFromPt to calculate a valid
1127 dragging rectangle */
1128 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1129 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1131 return GetDraggingRectFromPt(
1137 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1143 rcTray
.left
= pwp
->x
;
1144 rcTray
.top
= pwp
->y
;
1145 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1146 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1149 rcTray
.left
-= m_AutoHideOffset
.cx
;
1150 rcTray
.right
-= m_AutoHideOffset
.cx
;
1151 rcTray
.top
-= m_AutoHideOffset
.cy
;
1152 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1155 if (!EqualRect(&rcTray
,
1156 &m_TrayRects
[m_DraggingPosition
]))
1158 /* Recalculate the rectangle, the user dragged the tray
1159 window to another monitor or the window was somehow else
1161 m_DraggingPosition
= GetDraggingRectFromRect(
1163 &m_DraggingMonitor
);
1164 //m_TrayRects[DraggingPosition] = rcTray;
1167 //Monitor = CalculateValidSize(DraggingPosition,
1170 m_Monitor
= m_DraggingMonitor
;
1171 m_Position
= m_DraggingPosition
;
1174 m_TrayRects
[m_Position
] = rcTray
;
1177 else if (GetWindowRect(&rcTray
))
1181 if (!(pwp
->flags
& SWP_NOMOVE
))
1183 rcTray
.left
= pwp
->x
;
1184 rcTray
.top
= pwp
->y
;
1187 if (!(pwp
->flags
& SWP_NOSIZE
))
1189 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1190 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1193 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1195 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1202 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1207 rcTray
.left
-= m_AutoHideOffset
.cx
;
1208 rcTray
.right
-= m_AutoHideOffset
.cx
;
1209 rcTray
.top
-= m_AutoHideOffset
.cy
;
1210 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1212 m_TrayRects
[m_Position
] = rcTray
;
1216 /* If the user isn't resizing the tray window we need to make sure the
1217 new size or position is valid. this is to prevent changes to the window
1218 without user interaction. */
1219 rcTray
= m_TrayRects
[m_Position
];
1223 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1224 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1228 rcTray
.left
+= m_AutoHideOffset
.cx
;
1229 rcTray
.right
+= m_AutoHideOffset
.cx
;
1230 rcTray
.top
+= m_AutoHideOffset
.cy
;
1231 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1234 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1235 pwp
->x
= rcTray
.left
;
1236 pwp
->y
= rcTray
.top
;
1237 pwp
->cx
= m_TraySize
.cx
;
1238 pwp
->cy
= m_TraySize
.cy
;
1242 VOID
ApplyClipping(IN BOOL Clip
)
1244 RECT rcClip
, rcWindow
;
1247 if (GetWindowRect(&rcWindow
))
1249 /* Disable clipping on systems with only one monitor */
1250 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1257 GetScreenRect(m_Monitor
, &rcClip
);
1259 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1268 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1273 /* Set the clipping region or make sure the window isn't clipped
1274 by disabling it explicitly. */
1275 SetWindowRgn(hClipRgn
, TRUE
);
1279 VOID
ResizeWorkArea()
1281 #if !WIN7_DEBUG_MODE
1282 RECT rcTray
, rcWorkArea
;
1284 /* If monitor has changed then fix the previous monitors work area */
1285 if (m_PreviousMonitor
!= m_Monitor
)
1287 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1288 SystemParametersInfoW(SPI_SETWORKAREA
,
1294 rcTray
= m_TrayRects
[m_Position
];
1296 GetScreenRect(m_Monitor
, &rcWorkArea
);
1297 m_PreviousMonitor
= m_Monitor
;
1299 /* If AutoHide is false then change the workarea to exclude
1300 the area that the taskbar covers. */
1306 rcWorkArea
.top
= rcTray
.bottom
;
1309 rcWorkArea
.left
= rcTray
.right
;
1312 rcWorkArea
.right
= rcTray
.left
;
1315 rcWorkArea
.bottom
= rcTray
.top
;
1321 * Resize the current monitor work area. Win32k will also send
1322 * a WM_SIZE message to automatically resize the desktop.
1324 SystemParametersInfoW(SPI_SETWORKAREA
,
1331 VOID
CheckTrayWndPosition()
1335 rcTray
= m_TrayRects
[m_Position
];
1339 rcTray
.left
+= m_AutoHideOffset
.cx
;
1340 rcTray
.right
+= m_AutoHideOffset
.cx
;
1341 rcTray
.top
+= m_AutoHideOffset
.cy
;
1342 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1345 IUnknown_Exec(m_TrayBandSite
,
1347 DBID_BANDINFOCHANGED
,
1352 FitToRebar(&rcTray
);
1353 m_TrayRects
[m_Position
] = rcTray
;
1355 /* Move the tray window */
1359 rcTray
.right
- rcTray
.left
,
1360 rcTray
.bottom
- rcTray
.top
,
1361 SWP_NOZORDER
| SWP_NOACTIVATE
);
1365 ApplyClipping(TRUE
);
1368 typedef struct _TW_STUCKRECTS2
1376 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1378 VOID
RegLoadSettings()
1383 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1384 DWORD cbSize
= sizeof(sr
);
1385 SIZE StartBtnSize
= m_StartButton
.GetSize();
1387 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1388 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1389 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1390 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1392 if (SHGetValue(hkExplorer
,
1393 TEXT("StuckRects2"),
1397 &cbSize
) == ERROR_SUCCESS
&&
1398 sr
.cbSize
== sizeof(sr
))
1400 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1401 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1402 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1403 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1405 /* FIXME: Are there more flags? */
1408 m_Position
= ABE_LEFT
;
1410 if (sr
.Position
> ABE_BOTTOM
)
1411 m_Position
= ABE_BOTTOM
;
1413 m_Position
= sr
.Position
;
1416 /* Try to find out which monitor the tray window was located on last.
1417 Here we're only interested in the monitor screen that we think
1418 is the last one used. We're going to determine on which monitor
1419 we really are after calculating the docked position. */
1421 GetScreenRectFromRect(
1423 MONITOR_DEFAULTTONEAREST
);
1427 m_Position
= ABE_BOTTOM
;
1430 /* Use the minimum size of the taskbar, we'll use the start
1431 button as a minimum for now. Make sure we calculate the
1432 entire window size, not just the client size. However, we
1433 use a thinner border than a standard thick border, so that
1434 the start button and bands are not stuck to the screen border. */
1437 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1438 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1442 sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1443 sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1445 sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1448 /* Use the primary screen by default */
1451 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1452 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1453 GetScreenRectFromRect(
1455 MONITOR_DEFAULTTOPRIMARY
);
1460 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1465 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1467 /* Determine a minimum tray window rectangle. The "client" height is
1468 zero here since we cannot determine an optimal minimum width when
1469 loaded as a vertical tray window. We just need to make sure the values
1470 loaded from the registry are at least. The windows explorer behaves
1471 the same way, it allows the user to save a zero width vertical tray
1472 window, but not a zero height horizontal tray window. */
1475 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1476 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1480 WndSize
.cx
= StartBtnSize
.cx
;
1481 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1484 if (WndSize
.cx
< sr
.Size
.cx
)
1485 WndSize
.cx
= sr
.Size
.cx
;
1486 if (WndSize
.cy
< sr
.Size
.cy
)
1487 WndSize
.cy
= sr
.Size
.cy
;
1489 /* Save the calculated size */
1490 m_TraySize
= WndSize
;
1492 /* Calculate all docking rectangles. We need to do this here so they're
1493 initialized and dragging the tray window to another position gives
1495 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1497 GetTrayRectFromScreenRect(Pos
,
1501 // 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);
1504 /* Determine which monitor we are on. It shouldn't matter which docked
1505 position rectangle we use */
1506 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1509 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1512 SIZE TraySize
, StartSize
;
1513 POINT ptTrayNotify
= { 0, 0 };
1517 m_StartButton
.UpdateSize();
1518 if (prcClient
!= NULL
)
1520 rcClient
= *prcClient
;
1524 if (!GetClientRect(&rcClient
))
1526 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1531 Horizontal
= IsPosHorizontal();
1533 /* We're about to resize/move the start button, the rebar control and
1534 the tray notification control */
1535 dwp
= BeginDeferWindowPos(3);
1538 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1542 /* Limit the Start button width to the client width, if necessary */
1543 StartSize
= m_StartButton
.GetSize();
1544 if (StartSize
.cx
> rcClient
.right
)
1545 StartSize
.cx
= rcClient
.right
;
1547 if (m_StartButton
.m_hWnd
!= NULL
)
1549 /* Resize and reposition the button */
1550 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1556 SWP_NOZORDER
| SWP_NOACTIVATE
);
1559 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1564 /* Determine the size that the tray notification window needs */
1568 TraySize
.cy
= rcClient
.bottom
;
1572 TraySize
.cx
= rcClient
.right
;
1576 if (m_TrayNotify
!= NULL
&&
1577 SendMessage(m_TrayNotify
,
1578 TNWM_GETMINIMUMSIZE
,
1582 /* Move the tray notification window to the desired location */
1584 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1586 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1588 dwp
= ::DeferWindowPos(dwp
,
1595 SWP_NOZORDER
| SWP_NOACTIVATE
);
1598 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1603 /* Resize/Move the rebar control */
1604 if (m_Rebar
!= NULL
)
1606 POINT ptRebar
= { 0, 0 };
1609 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1613 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1614 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1615 szRebar
.cy
= rcClient
.bottom
;
1619 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1620 szRebar
.cx
= rcClient
.right
;
1621 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1624 dwp
= ::DeferWindowPos(dwp
,
1631 SWP_NOZORDER
| SWP_NOACTIVATE
);
1635 EndDeferWindowPos(dwp
);
1637 if (m_TaskSwitch
!= NULL
)
1639 /* Update the task switch window configuration */
1640 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1644 void FitToRebar(PRECT pRect
)
1646 /* Get the rect of the rebar */
1647 RECT rebarRect
, taskbarRect
;
1648 ::GetWindowRect(m_Rebar
, &rebarRect
);
1649 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1650 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1652 /* Calculate the difference of size of the taskbar and the rebar */
1654 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
1655 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
1657 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1661 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1662 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1663 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1666 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1667 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1668 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1672 /* FIXME: what to do here? */
1676 CalculateValidSize(m_Position
, pRect
);
1679 void PopupStartMenu()
1681 if (m_StartMenuPopup
!= NULL
)
1687 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1692 pt
.x
= rcExclude
.left
;
1693 pt
.y
= rcExclude
.top
;
1694 dwFlags
|= MPPF_TOP
;
1697 pt
.x
= rcExclude
.left
;
1698 pt
.y
= rcExclude
.bottom
;
1699 dwFlags
|= MPPF_BOTTOM
;
1702 pt
.x
= rcExclude
.right
;
1703 pt
.y
= rcExclude
.top
;
1704 dwFlags
|= MPPF_RIGHT
;
1707 pt
.x
= rcExclude
.left
;
1708 pt
.y
= rcExclude
.top
;
1709 dwFlags
|= MPPF_LEFT
;
1713 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1715 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1720 void ProcessMouseTracking()
1725 UINT state
= m_AutoHideState
;
1728 GetWindowRect(&rcCurrent
);
1729 over
= PtInRect(&rcCurrent
, pt
);
1731 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1738 if (state
== AUTOHIDE_HIDING
)
1740 TRACE("AutoHide cancelling hide.\n");
1741 m_AutoHideState
= AUTOHIDE_SHOWING
;
1742 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1744 else if (state
== AUTOHIDE_HIDDEN
)
1746 TRACE("AutoHide starting show.\n");
1747 m_AutoHideState
= AUTOHIDE_SHOWING
;
1748 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1753 if (state
== AUTOHIDE_SHOWING
)
1755 TRACE("AutoHide cancelling show.\n");
1756 m_AutoHideState
= AUTOHIDE_HIDING
;
1757 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1759 else if (state
== AUTOHIDE_SHOWN
)
1761 TRACE("AutoHide starting hide.\n");
1762 m_AutoHideState
= AUTOHIDE_HIDING
;
1763 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1766 KillTimer(TIMER_ID_MOUSETRACK
);
1770 void ProcessAutoHide()
1772 RECT rc
= m_TrayRects
[m_Position
];
1773 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1774 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1776 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
);
1778 switch (m_AutoHideState
)
1780 case AUTOHIDE_HIDING
:
1784 m_AutoHideOffset
.cy
= 0;
1785 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1786 if (m_AutoHideOffset
.cx
< -w
)
1787 m_AutoHideOffset
.cx
= -w
;
1790 m_AutoHideOffset
.cx
= 0;
1791 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1792 if (m_AutoHideOffset
.cy
< -h
)
1793 m_AutoHideOffset
.cy
= -h
;
1796 m_AutoHideOffset
.cy
= 0;
1797 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1798 if (m_AutoHideOffset
.cx
> w
)
1799 m_AutoHideOffset
.cx
= w
;
1802 m_AutoHideOffset
.cx
= 0;
1803 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1804 if (m_AutoHideOffset
.cy
> h
)
1805 m_AutoHideOffset
.cy
= h
;
1809 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1811 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1816 case AUTOHIDE_HIDDEN
:
1821 m_AutoHideOffset
.cx
= -w
;
1822 m_AutoHideOffset
.cy
= 0;
1825 m_AutoHideOffset
.cx
= 0;
1826 m_AutoHideOffset
.cy
= -h
;
1829 m_AutoHideOffset
.cx
= w
;
1830 m_AutoHideOffset
.cy
= 0;
1833 m_AutoHideOffset
.cx
= 0;
1834 m_AutoHideOffset
.cy
= h
;
1838 KillTimer(TIMER_ID_AUTOHIDE
);
1839 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1842 case AUTOHIDE_SHOWING
:
1843 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1845 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1847 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1849 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1853 m_AutoHideOffset
.cx
= 0;
1856 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1858 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1860 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1862 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1866 m_AutoHideOffset
.cy
= 0;
1869 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1871 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1876 case AUTOHIDE_SHOWN
:
1878 KillTimer(TIMER_ID_AUTOHIDE
);
1879 m_AutoHideState
= AUTOHIDE_SHOWN
;
1883 rc
.left
+= m_AutoHideOffset
.cx
;
1884 rc
.right
+= m_AutoHideOffset
.cx
;
1885 rc
.top
+= m_AutoHideOffset
.cy
;
1886 rc
.bottom
+= m_AutoHideOffset
.cy
;
1888 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1889 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1896 /**********************************************************
1897 * ##### taskbar drawing #####
1900 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1903 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1905 ASSERT(m_Position
<= ABE_BOTTOM
);
1909 GetClientRect(&rect
);
1910 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1916 int DrawSizerWithTheme(IN HRGN hRgn
)
1920 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1923 ASSERT(m_Position
<= ABE_BOTTOM
);
1925 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
1926 if (FAILED_UNEXPECTEDLY(hr
))
1929 GetWindowRect(&rect
);
1930 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1932 hdc
= GetWindowDC();
1937 rect
.left
= rect
.right
- size
.cx
;
1940 rect
.top
= rect
.bottom
- size
.cy
;
1943 rect
.right
= rect
.left
+ size
.cx
;
1947 rect
.bottom
= rect
.top
+ size
.cy
;
1951 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
1964 HRESULT STDMETHODCALLTYPE
Open()
1968 /* Check if there's already a window created and try to show it.
1969 If it was somehow destroyed just create a new tray window. */
1970 if (m_hWnd
!= NULL
&& IsWindow())
1975 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1977 dwExStyle
|= WS_EX_TOPMOST
;
1979 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1982 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1985 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1986 if (m_Position
!= (DWORD
) -1)
1987 rcWnd
= m_TrayRects
[m_Position
];
1989 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1992 /* Align all controls on the tray window */
1993 AlignControls(NULL
);
1995 /* Move the tray window to the right position and resize it if necessary */
1996 CheckTrayWndPosition();
2001 HRESULT STDMETHODCALLTYPE
Close()
2014 HWND STDMETHODCALLTYPE
GetHWND()
2019 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2021 return (m_hWnd
== hWnd
||
2022 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2025 BOOL STDMETHODCALLTYPE
IsHorizontal()
2027 return IsPosHorizontal();
2030 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2032 BOOL bPrevLock
= Locked
;
2034 if (Locked
!= bLock
)
2038 if (m_TrayBandSite
!= NULL
)
2040 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2050 /* Update cached tray sizes */
2051 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2053 RECT rcGripper
= {0};
2054 AdjustSizerRect(&rcGripper
, Pos
);
2058 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2059 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2060 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2061 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2065 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2066 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2067 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2068 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2072 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2074 ApplyClipping(TRUE
);
2085 /**********************************************************
2086 * ##### message handling #####
2089 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2093 ((ITrayWindow
*)this)->AddRef();
2095 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2097 /* Create the Start button */
2098 m_StartButton
.Create(m_hWnd
);
2100 /* Load the saved tray window settings */
2103 /* Create and initialize the start menu */
2104 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2105 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2107 /* Create the task band */
2108 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2109 if (FAILED_UNEXPECTEDLY(hRet
))
2112 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2113 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2114 if (FAILED_UNEXPECTEDLY(hRet
))
2117 /* Get the hwnd of the rebar */
2118 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2119 if (FAILED_UNEXPECTEDLY(hRet
))
2122 /* Get the hwnd of the tasks toolbar */
2123 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2124 if (FAILED_UNEXPECTEDLY(hRet
))
2127 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2129 /* Create the tray notification window */
2130 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2134 InitShellServices(&m_ShellServices
);
2138 m_AutoHideState
= AUTOHIDE_HIDING
;
2139 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2142 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2143 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2144 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2145 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2146 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2147 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2148 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2149 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2150 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2151 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2152 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2153 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2158 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2161 CloseThemeData(m_Theme
);
2163 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2167 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2171 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2173 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2178 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2180 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2182 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2184 AlignControls(NULL
);
2185 CheckTrayWndPosition();
2191 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2193 HDC hdc
= (HDC
) wParam
;
2201 return EraseBackgroundWithTheme(hdc
);
2204 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2206 /* Move the tray window to the right position and resize it if necessary */
2207 CheckTrayWndPosition();
2212 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2216 TRACE("WM_COPYDATA notify message received. Handling...\n");
2217 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2222 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2230 return DrawSizerWithTheme((HRGN
) wParam
);
2233 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2235 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2236 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2239 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2246 /* The user may not be able to resize the tray window.
2247 Pretend like the window is not sizeable when the user
2248 clicks on the border. */
2252 SetLastError(ERROR_SUCCESS
);
2253 if (GetClientRect(&rcClient
) &&
2254 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2256 pt
.x
= (SHORT
) LOWORD(lParam
);
2257 pt
.y
= (SHORT
) HIWORD(lParam
);
2259 if (PtInRect(&rcClient
,
2262 /* The user is trying to drag the tray window */
2266 /* Depending on the position of the tray window, allow only
2267 changing the border next to the monitor working area */
2271 if (pt
.y
> rcClient
.bottom
)
2275 if (pt
.x
> rcClient
.right
)
2279 if (pt
.x
< rcClient
.left
)
2284 if (pt
.y
< rcClient
.top
)
2293 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2296 PRECT pRect
= (PRECT
) lParam
;
2298 /* We need to ensure that an application can not accidently
2299 move the tray window (using SetWindowPos). However, we still
2300 need to be able to move the window in case the user wants to
2301 drag the tray window to another position or in case the user
2302 wants to resize the tray window. */
2303 if (!Locked
&& GetCursorPos(&ptCursor
))
2306 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2310 *pRect
= m_TrayRects
[m_Position
];
2314 pRect
->left
+= m_AutoHideOffset
.cx
;
2315 pRect
->right
+= m_AutoHideOffset
.cx
;
2316 pRect
->top
+= m_AutoHideOffset
.cy
;
2317 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2323 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2325 PRECT pRect
= (PRECT
) lParam
;
2333 *pRect
= m_TrayRects
[m_Position
];
2337 pRect
->left
+= m_AutoHideOffset
.cx
;
2338 pRect
->right
+= m_AutoHideOffset
.cx
;
2339 pRect
->top
+= m_AutoHideOffset
.cy
;
2340 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2346 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2348 ChangingWinPos((LPWINDOWPOS
) lParam
);
2352 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2355 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2358 /* Clip the tray window on multi monitor systems so the edges can't
2359 overlap into another monitor */
2360 ApplyClipping(TRUE
);
2362 if (!GetClientRect(&rcClient
))
2369 rcClient
.left
= rcClient
.top
= 0;
2370 rcClient
.right
= LOWORD(lParam
);
2371 rcClient
.bottom
= HIWORD(lParam
);
2374 AlignControls(&rcClient
);
2378 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2384 /* Remove the clipping on multi monitor systems while dragging around */
2385 ApplyClipping(FALSE
);
2390 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2395 /* Apply clipping */
2396 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2401 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2407 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2408 The tray window needs to handle this specially, since it normally doesn't have
2411 static const UINT uidDisableItem
[] = {
2421 /* temporarily enable the system menu */
2422 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2424 hSysMenu
= GetSystemMenu(FALSE
);
2425 if (hSysMenu
!= NULL
)
2427 /* Disable all items that are not relevant */
2428 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2430 EnableMenuItem(hSysMenu
,
2432 MF_BYCOMMAND
| MF_GRAYED
);
2435 EnableMenuItem(hSysMenu
,
2438 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2440 /* Display the system menu */
2444 m_StartButton
.m_hWnd
,
2445 m_Position
!= ABE_TOP
,
2449 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2453 /* revert the system menu window style */
2454 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2464 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2466 /* This handler implements the trick that makes the start button to
2467 get pressed when the user clicked left or below the button */
2469 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2470 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2475 m_StartButton
.GetWindowRect(&rcStartBtn
);
2476 GetWindowInfo(m_hWnd
, &wi
);
2483 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2489 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2492 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2493 pt
.x
> rcStartBtn
.right
)
2501 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2506 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2507 pt
.y
> rcStartBtn
.bottom
)
2521 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2523 /* We want the user to be able to get a context menu even on the nonclient
2524 area (including the sizing border)! */
2525 uMsg
= WM_CONTEXTMENU
;
2526 wParam
= (WPARAM
) m_hWnd
;
2528 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2531 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2533 LRESULT Ret
= FALSE
;
2534 POINT pt
, *ppt
= NULL
;
2535 HWND hWndExclude
= NULL
;
2537 /* Check if the administrator has forbidden access to context menus */
2538 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2541 pt
.x
= (SHORT
) LOWORD(lParam
);
2542 pt
.y
= (SHORT
) HIWORD(lParam
);
2544 if (pt
.x
!= -1 || pt
.y
!= -1)
2547 hWndExclude
= m_StartButton
.m_hWnd
;
2549 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2551 /* Make sure we can't track the context menu if the start
2552 menu is currently being shown */
2553 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2555 CComPtr
<IContextMenu
> ctxMenu
;
2556 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2557 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2562 /* See if the context menu should be handled by the task band site */
2563 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2566 POINT ptClient
= *ppt
;
2568 /* Convert the coordinates to client-coordinates */
2569 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2571 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2572 if (hWndAtPt
!= NULL
&&
2573 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2575 /* Check if the user clicked on the task switch window */
2577 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2579 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2580 if (hWndAtPt
== m_TaskSwitch
)
2581 goto HandleTrayContextMenu
;
2583 /* Forward the message to the task band site */
2584 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2587 goto HandleTrayContextMenu
;
2591 HandleTrayContextMenu
:
2592 /* Tray the default tray window context menu */
2593 CComPtr
<IContextMenu
> ctxMenu
;
2594 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2595 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2601 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2603 LRESULT Ret
= FALSE
;
2604 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2605 the rebar control! But we shouldn't forward messages that the band
2606 site doesn't handle, such as other controls (start button, tray window */
2608 HRESULT hr
= E_FAIL
;
2612 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2617 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2619 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2621 if (nmh
->hwndFrom
== m_TrayNotify
)
2626 /* Cause all controls to be aligned */
2627 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2635 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2637 /* We "handle" this message so users can't cause a weird maximize/restore
2638 window animation when double-clicking the tray window! */
2640 /* We should forward mouse messages to child windows here.
2641 Right now, this is only clock double-click */
2643 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2646 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2647 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2648 if (PtInRect(&rcClock
, ptClick
))
2650 //FIXME: use SHRunControlPanel
2651 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2657 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2663 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2666 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2667 if (FAILED_UNEXPECTEDLY(hr
))
2670 if (::IsWindowVisible(hwndStartMenu
))
2672 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2682 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2685 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2686 * to show the shutdown dialog. Also a WM_CLOSE message sent
2687 * by apps should show the dialog.
2689 return DoExitWindows();
2692 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2694 if (wParam
== SC_CLOSE
)
2696 return DoExitWindows();
2703 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2705 return HandleHotKey(wParam
);
2708 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2710 LRESULT Ret
= FALSE
;
2712 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2717 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2719 return HandleCommand(LOWORD(wParam
));
2724 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2728 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2734 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2736 if (wParam
== TIMER_ID_MOUSETRACK
)
2738 ProcessMouseTracking();
2740 else if (wParam
== TIMER_ID_AUTOHIDE
)
2749 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2752 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2753 if(!m_Theme
|| Locked
)
2764 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2765 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2770 rc
= &prms
->rgrc
[0];
2773 AdjustSizerRect(rc
, m_Position
);
2778 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2781 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2787 ::GetWindowRect(m_hWnd
, &rc
);
2791 rc
.bottom
- rc
.top
};
2793 as
->rcTarget
.right
- as
->rcTarget
.left
,
2794 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2796 as
->rcActual
.right
- as
->rcActual
.left
,
2797 as
->rcActual
.bottom
- as
->rcActual
.top
};
2800 szWindow
.cx
- szTarget
.cx
,
2801 szWindow
.cy
- szTarget
.cx
,
2807 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2810 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2813 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2814 rc
.left
= rc
.right
- szWindow
.cy
;
2817 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2818 rc
.top
= rc
.bottom
- szWindow
.cy
;
2822 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2829 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2831 BEGIN_MSG_MAP(CTrayWindow
)
2832 if (m_StartMenuBand
!= NULL
)
2839 Msg
.wParam
= wParam
;
2840 Msg
.lParam
= lParam
;
2842 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2847 wParam
= Msg
.wParam
;
2848 lParam
= Msg
.lParam
;
2850 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2851 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2852 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2853 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2854 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2855 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2856 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2857 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2858 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2859 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2860 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2861 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2862 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2863 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2864 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2865 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2866 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2867 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2868 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2869 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2870 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2871 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2872 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
2873 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2874 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2875 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2876 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2877 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2878 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2879 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2880 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2881 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2882 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2883 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2887 /*****************************************************************************/
2889 VOID
TrayProcessMessages()
2893 /* FIXME: We should keep a reference here... */
2895 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2897 if (Msg
.message
== WM_QUIT
)
2900 if (m_StartMenuBand
== NULL
||
2901 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2903 TranslateMessage(&Msg
);
2904 DispatchMessage(&Msg
);
2909 VOID
TrayMessageLoop()
2914 /* FIXME: We should keep a reference here... */
2918 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2920 if (!Ret
|| Ret
== -1)
2923 if (m_StartMenuBand
== NULL
||
2924 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2926 TranslateMessage(&Msg
);
2927 DispatchMessage(&Msg
);
2935 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2936 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2937 * The reason we implement it is because we have to use SHCreateDesktop() so
2938 * that the shell provides the desktop window and all the features that come
2939 * with it (especially positioning of desktop icons)
2942 virtual ULONG STDMETHODCALLTYPE
GetState()
2944 /* FIXME: Return ABS_ flags? */
2945 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2949 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2951 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2952 *phWndTray
= m_hWnd
;
2956 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2958 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2960 m_DesktopWnd
= hWndDesktop
;
2964 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2966 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2970 virtual HRESULT
RaiseStartButton()
2972 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2976 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
2979 return E_INVALIDARG
;
2984 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
2991 m_Position
= (DWORD
) -1;
2994 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2996 DECLARE_PROTECT_FINAL_CONSTRUCT()
2997 BEGIN_COM_MAP(CTrayWindow
)
2998 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2999 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
3000 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
3004 class CTrayWindowCtxMenu
:
3005 public CComCoClass
<CTrayWindowCtxMenu
>,
3006 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
3010 CComPtr
<CTrayWindow
> TrayWnd
;
3011 CComPtr
<IContextMenu
> pcm
;
3014 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3016 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3017 this->hWndOwner
= hWndOwner
;
3021 virtual HRESULT STDMETHODCALLTYPE
3022 QueryContextMenu(HMENU hPopup
,
3028 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3031 return HRESULT_FROM_WIN32(GetLastError());
3033 int count
= ::GetMenuItemCount(menubase
);
3035 for (int i
= 0; i
< count
; i
++)
3039 MENUITEMINFOW mii
= { 0 };
3040 mii
.cbSize
= sizeof(mii
);
3041 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3042 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3043 mii
.dwTypeData
= label
;
3044 mii
.cch
= _countof(label
);
3045 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3047 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3049 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3052 ::DestroyMenu(menubase
);
3054 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3061 CheckMenuItem(hPopup
,
3063 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3065 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3067 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3075 WARN("AddContextMenus failed.\n");
3083 virtual HRESULT STDMETHODCALLTYPE
3084 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3086 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3089 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3091 CMINVOKECOMMANDINFO cmici
= { 0 };
3095 /* Setup and invoke the shell command */
3096 cmici
.cbSize
= sizeof(cmici
);
3097 cmici
.hwnd
= hWndOwner
;
3098 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- ID_SHELL_CMD_FIRST
);
3099 cmici
.nShow
= SW_NORMAL
;
3101 pcm
->InvokeCommand(&cmici
);
3106 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3113 virtual HRESULT STDMETHODCALLTYPE
3114 GetCommandString(UINT_PTR idCmd
,
3123 CTrayWindowCtxMenu()
3127 virtual ~CTrayWindowCtxMenu()
3131 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3132 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3136 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3138 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3139 mnu
->Initialize(TrayWnd
, hWndOwner
);
3144 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3146 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3148 return E_OUTOFMEMORY
;
3153 *ppTray
= (ITrayWindow
*) Tray
;
3159 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3161 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3162 return TrayWindow
->RaiseStartButton();
3165 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3167 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3168 TrayWindow
->TrayProcessMessages();
3171 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3173 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3174 TrayWindow
->TrayMessageLoop();