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 CComPtr
<IUnknown
> 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 InSizeMove
: 1;
242 DWORD IsDragging
: 1;
243 DWORD NewPosSize
: 1;
258 m_PreviousMonitor(NULL
),
259 m_DraggingPosition(0),
260 m_DraggingMonitor(NULL
),
261 m_TrayPropertiesOwner(NULL
),
262 m_RunFileDlgOwner(NULL
),
263 m_AutoHideState(NULL
),
264 m_ShellServices(NULL
),
267 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
268 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
269 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
270 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
273 virtual ~CTrayWindow()
275 if (m_ShellServices
!= NULL
)
277 ShutdownShellServices(m_ShellServices
);
278 m_ShellServices
= NULL
;
283 DeleteObject(m_Font
);
289 CloseThemeData(m_Theme
);
300 /**********************************************************
301 * ##### command handling #####
304 HRESULT
ExecResourceCmd(int id
)
306 WCHAR szCommand
[256];
307 WCHAR
*pszParameters
;
309 if (!LoadStringW(hExplorerInstance
,
312 _countof(szCommand
)))
317 pszParameters
= wcschr(szCommand
, L
'>');
324 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
328 LRESULT
DoExitWindows()
330 /* Display the ReactOS Shutdown Dialog */
331 ExitWindowsDialog(m_hWnd
);
334 * If the user presses CTRL+ALT+SHIFT while exiting
335 * the shutdown dialog, exit the shell cleanly.
337 if ((GetKeyState(VK_CONTROL
) & 0x8000) &&
338 (GetKeyState(VK_SHIFT
) & 0x8000) &&
339 (GetKeyState(VK_MENU
) & 0x8000))
341 PostMessage(WM_QUIT
, 0, 0);
346 DWORD WINAPI
RunFileDlgThread()
351 m_StartButton
.GetWindowRect(&posRect
);
353 hwnd
= CreateWindowEx(0,
356 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
359 posRect
.right
- posRect
.left
,
360 posRect
.bottom
- posRect
.top
,
366 m_RunFileDlgOwner
= hwnd
;
368 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
370 m_RunFileDlgOwner
= NULL
;
371 ::DestroyWindow(hwnd
);
376 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
378 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
379 return This
->RunFileDlgThread();
382 void DisplayRunFileDlg()
385 if (m_RunFileDlgOwner
)
387 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
388 if (hRunDlg
!= NULL
&&
389 hRunDlg
!= m_RunFileDlgOwner
)
391 SetForegroundWindow(hRunDlg
);
396 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
399 DWORD WINAPI
TrayPropertiesThread()
404 m_StartButton
.GetWindowRect(&posRect
);
405 hwnd
= CreateWindowEx(0,
408 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
411 posRect
.right
- posRect
.left
,
412 posRect
.bottom
- posRect
.top
,
418 m_TrayPropertiesOwner
= hwnd
;
420 DisplayTrayProperties(hwnd
, m_hWnd
);
422 m_TrayPropertiesOwner
= NULL
;
423 ::DestroyWindow(hwnd
);
428 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
430 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
432 return This
->TrayPropertiesThread();
435 HWND STDMETHODCALLTYPE
DisplayProperties()
439 if (m_TrayPropertiesOwner
)
441 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
442 if (hTrayProp
!= NULL
&&
443 hTrayProp
!= m_TrayPropertiesOwner
)
445 SetForegroundWindow(hTrayProp
);
450 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
454 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
456 WCHAR szDir
[MAX_PATH
];
458 if (SHGetSpecialFolderPath(hWndOwner
,
460 CSIDL_COMMON_STARTMENU
,
463 ShellExecute(hWndOwner
,
472 VOID
OpenTaskManager(IN HWND hWndOwner
)
474 ShellExecute(hWndOwner
,
482 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
486 case ID_SHELL_CMD_PROPERTIES
:
490 case ID_SHELL_CMD_OPEN_ALL_USERS
:
491 OpenCommonStartMenuDirectory(m_hWnd
,
495 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
496 OpenCommonStartMenuDirectory(m_hWnd
,
501 if (SHRestricted(REST_CLASSICSHELL
) == 0)
503 Lock(!g_TaskbarSettings
.bLock
);
507 case ID_SHELL_CMD_OPEN_TASKMGR
:
508 OpenTaskManager(m_hWnd
);
511 case ID_SHELL_CMD_UNDO_ACTION
:
514 case ID_SHELL_CMD_SHOW_DESKTOP
:
517 case ID_SHELL_CMD_TILE_WND_H
:
518 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
521 case ID_SHELL_CMD_TILE_WND_V
:
522 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
525 case ID_SHELL_CMD_CASCADE_WND
:
526 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
529 case ID_SHELL_CMD_CUST_NOTIF
:
530 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
533 case ID_SHELL_CMD_ADJUST_DAT
:
534 //FIXME: Use SHRunControlPanel
535 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
539 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
546 LRESULT
HandleHotKey(DWORD id
)
554 ExecResourceCmd(IDS_HELP_COMMAND
);
557 //FIXME: We don't support this yet:
558 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
559 ShellExecuteW(0, NULL
, L
"explorer.exe", L
"/e ,", NULL
, 1);
562 SHFindFiles(NULL
, NULL
);
564 case IDHK_FIND_COMPUTER
:
565 SHFindComputer(NULL
, NULL
);
567 case IDHK_SYS_PROPERTIES
:
568 //FIXME: Use SHRunControlPanel
569 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
575 case IDHK_MINIMIZE_ALL
:
577 case IDHK_RESTORE_ALL
:
588 LRESULT
HandleCommand(UINT uCommand
)
592 case IDM_TASKBARANDSTARTMENU
:
597 SHFindFiles(NULL
, NULL
);
600 case IDM_HELPANDSUPPORT
:
601 ExecResourceCmd(IDS_HELP_COMMAND
);
608 /* FIXME: Handle these commands as well */
609 case IDM_SYNCHRONIZE
:
611 case IDM_UNDOCKCOMPUTER
:
615 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
629 IN POINT
*ppt OPTIONAL
,
630 IN HWND hwndExclude OPTIONAL
,
632 IN BOOL IsContextMenu
)
634 TPMPARAMS tmp
, *ptmp
= NULL
;
639 if (hwndExclude
!= NULL
)
641 /* Get the client rectangle and map it to screen coordinates */
642 if (::GetClientRect(hwndExclude
,
644 ::MapWindowPoints(hwndExclude
,
646 (LPPOINT
) &tmp
.rcExclude
,
656 GetClientRect(&tmp
.rcExclude
) &&
659 (LPPOINT
) &tmp
.rcExclude
,
667 /* NOTE: TrackPopupMenuEx will eventually align the track position
668 for us, no need to take care of it here as long as the
669 coordinates are somewhere within the exclusion rectangle */
670 pt
.x
= ptmp
->rcExclude
.left
;
671 pt
.y
= ptmp
->rcExclude
.top
;
679 tmp
.cbSize
= sizeof(tmp
);
681 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
682 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
684 fuFlags
|= TPM_RIGHTBUTTON
;
686 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
688 cmdId
= TrackPopupMenuEx(hMenu
,
698 HRESULT
TrackCtxMenu(
699 IN IContextMenu
* contextMenu
,
700 IN POINT
*ppt OPTIONAL
,
701 IN HWND hwndExclude OPTIONAL
,
703 IN PVOID Context OPTIONAL
)
709 HMENU popup
= CreatePopupMenu();
714 TRACE("Before Query\n");
715 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
716 if (FAILED_UNEXPECTEDLY(hr
))
718 TRACE("Query failed\n");
723 TRACE("Before Tracking\n");
724 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
728 TRACE("Before InvokeCommand\n");
729 CMINVOKECOMMANDINFO cmi
= { 0 };
730 cmi
.cbSize
= sizeof(cmi
);
731 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
733 hr
= contextMenu
->InvokeCommand(&cmi
);
737 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
749 /**********************************************************
750 * ##### moving and sizing handling #####
755 /* There is nothing to do if themes are enabled */
759 m_StartButton
.UpdateFont();
761 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
762 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
764 ERR("SPI_GETNONCLIENTMETRICS failed\n");
769 DeleteObject(m_Font
);
771 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
772 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
775 ERR("CreateFontIndirect failed\n");
779 SendMessage(m_Rebar
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
780 SendMessage(m_TaskSwitch
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
781 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
784 HMONITOR
GetScreenRectFromRect(
791 mi
.cbSize
= sizeof(mi
);
792 hMon
= MonitorFromRect(pRect
, dwFlags
);
794 GetMonitorInfo(hMon
, &mi
))
796 *pRect
= mi
.rcMonitor
;
802 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
803 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
811 HMONITOR
GetMonitorFromRect(
812 IN
const RECT
*pRect
)
816 /* In case the monitor sizes or saved sizes differ a bit (probably
817 not a lot, only so the tray window overlaps into another monitor
818 now), minimize the risk that we determine a wrong monitor by
819 using the center point of the tray window if we can't determine
820 it using the rectangle. */
821 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
826 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
827 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
829 /* be less error-prone, find the nearest monitor */
830 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
836 HMONITOR
GetScreenRect(
837 IN HMONITOR hMonitor
,
840 HMONITOR hMon
= NULL
;
842 if (hMonitor
!= NULL
)
846 mi
.cbSize
= sizeof(mi
);
847 if (!GetMonitorInfo(hMonitor
, &mi
))
849 /* Hm, the monitor is gone? Try to find a monitor where it
850 could be located now */
851 hMon
= GetMonitorFromRect(pRect
);
853 !GetMonitorInfo(hMon
, &mi
))
860 *pRect
= mi
.rcMonitor
;
867 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
868 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
874 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
876 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
879 if (pos
> ABE_BOTTOM
)
882 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[pos
], 0, NULL
, TS_TRUE
, &size
);
883 if (FAILED_UNEXPECTEDLY(hr
))
889 rc
->bottom
-= size
.cy
;
895 rc
->right
-= size
.cx
;
903 VOID
MakeTrayRectWithSize(IN DWORD Position
,
904 IN
const SIZE
*pTraySize
,
910 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
914 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
918 pRect
->left
= pRect
->right
- pTraySize
->cx
;
923 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
928 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
929 IN
const RECT
*pScreen
,
930 IN
const SIZE
*pTraySize OPTIONAL
,
933 if (pTraySize
== NULL
)
934 pTraySize
= &m_TraySize
;
940 /* Move the border outside of the screen */
942 GetSystemMetrics(SM_CXEDGE
),
943 GetSystemMetrics(SM_CYEDGE
));
946 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
949 BOOL
IsPosHorizontal()
951 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
954 HMONITOR
CalculateValidSize(
963 //Horizontal = IsPosHorizontal();
965 szWnd
.cx
= pRect
->right
- pRect
->left
;
966 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
969 hMon
= GetScreenRectFromRect(
971 MONITOR_DEFAULTTONEAREST
);
973 /* Calculate the maximum size of the tray window and limit the window
974 size to half of the screen's size. */
975 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
976 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
977 if (szWnd
.cx
> szMax
.cx
)
979 if (szWnd
.cy
> szMax
.cy
)
982 /* FIXME - calculate */
984 GetTrayRectFromScreenRect(Position
,
994 GetMinimumWindowSize(
999 AdjustWindowRectEx(&rcMin
,
1000 GetWindowLong(m_hWnd
,
1003 GetWindowLong(m_hWnd
,
1011 DWORD
GetDraggingRectFromPt(
1014 OUT HMONITOR
*phMonitor
)
1016 HMONITOR hMon
, hMonNew
;
1017 DWORD PosH
, PosV
, Pos
;
1018 SIZE DeltaPt
, ScreenOffset
;
1024 /* Determine the screen rectangle */
1025 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
1030 mi
.cbSize
= sizeof(mi
);
1031 if (!GetMonitorInfo(hMon
, &mi
))
1034 goto GetPrimaryScreenRect
;
1037 /* make left top corner of the screen zero based to
1038 make calculations easier */
1039 pt
.x
-= mi
.rcMonitor
.left
;
1040 pt
.y
-= mi
.rcMonitor
.top
;
1042 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1043 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1044 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1045 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1049 GetPrimaryScreenRect
:
1050 ScreenOffset
.cx
= 0;
1051 ScreenOffset
.cy
= 0;
1052 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1053 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1056 /* Calculate the nearest screen border */
1057 if (pt
.x
< rcScreen
.right
/ 2)
1064 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1068 if (pt
.y
< rcScreen
.bottom
/ 2)
1075 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1079 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1081 /* Fix the screen origin to be relative to the primary monitor again */
1082 OffsetRect(&rcScreen
,
1086 RECT rcPos
= m_TrayRects
[Pos
];
1088 hMonNew
= GetMonitorFromRect(&rcPos
);
1089 if (hMon
!= hMonNew
)
1093 /* Recalculate the rectangle, we're dragging to another monitor.
1094 We don't need to recalculate the rect on single monitor systems. */
1095 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1096 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1098 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1103 /* The user is dragging the tray window on the same monitor. We don't need
1104 to recalculate the rectangle */
1113 DWORD
GetDraggingRectFromRect(
1115 OUT HMONITOR
*phMonitor
)
1119 /* Calculate the center of the rectangle. We call
1120 GetDraggingRectFromPt to calculate a valid
1121 dragging rectangle */
1122 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1123 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1125 return GetDraggingRectFromPt(
1131 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1137 rcTray
.left
= pwp
->x
;
1138 rcTray
.top
= pwp
->y
;
1139 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1140 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1142 if (!EqualRect(&rcTray
,
1143 &m_TrayRects
[m_DraggingPosition
]))
1145 /* Recalculate the rectangle, the user dragged the tray
1146 window to another monitor or the window was somehow else
1148 m_DraggingPosition
= GetDraggingRectFromRect(
1150 &m_DraggingMonitor
);
1151 //m_TrayRects[DraggingPosition] = rcTray;
1154 //Monitor = CalculateValidSize(DraggingPosition,
1157 m_Monitor
= m_DraggingMonitor
;
1158 m_Position
= m_DraggingPosition
;
1161 m_TrayRects
[m_Position
] = rcTray
;
1164 else if (GetWindowRect(&rcTray
))
1168 if (!(pwp
->flags
& SWP_NOMOVE
))
1170 rcTray
.left
= pwp
->x
;
1171 rcTray
.top
= pwp
->y
;
1174 if (!(pwp
->flags
& SWP_NOSIZE
))
1176 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1177 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1180 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1182 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1189 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1192 m_TrayRects
[m_Position
] = rcTray
;
1196 /* If the user isn't resizing the tray window we need to make sure the
1197 new size or position is valid. this is to prevent changes to the window
1198 without user interaction. */
1199 rcTray
= m_TrayRects
[m_Position
];
1201 if (g_TaskbarSettings
.sr
.AutoHide
)
1203 rcTray
.left
+= m_AutoHideOffset
.cx
;
1204 rcTray
.right
+= m_AutoHideOffset
.cx
;
1205 rcTray
.top
+= m_AutoHideOffset
.cy
;
1206 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1212 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1213 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1215 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1216 pwp
->x
= rcTray
.left
;
1217 pwp
->y
= rcTray
.top
;
1218 pwp
->cx
= m_TraySize
.cx
;
1219 pwp
->cy
= m_TraySize
.cy
;
1223 VOID
ApplyClipping(IN BOOL Clip
)
1225 RECT rcClip
, rcWindow
;
1228 if (GetWindowRect(&rcWindow
))
1230 /* Disable clipping on systems with only one monitor */
1231 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1238 GetScreenRect(m_Monitor
, &rcClip
);
1240 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1249 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1254 /* Set the clipping region or make sure the window isn't clipped
1255 by disabling it explicitly. */
1256 SetWindowRgn(hClipRgn
, TRUE
);
1260 VOID
ResizeWorkArea()
1262 #if !WIN7_DEBUG_MODE
1263 RECT rcTray
, rcWorkArea
;
1265 /* If monitor has changed then fix the previous monitors work area */
1266 if (m_PreviousMonitor
!= m_Monitor
)
1268 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1269 SystemParametersInfoW(SPI_SETWORKAREA
,
1275 rcTray
= m_TrayRects
[m_Position
];
1277 GetScreenRect(m_Monitor
, &rcWorkArea
);
1278 m_PreviousMonitor
= m_Monitor
;
1280 /* If AutoHide is false then change the workarea to exclude
1281 the area that the taskbar covers. */
1282 if (!g_TaskbarSettings
.sr
.AutoHide
)
1287 rcWorkArea
.top
= rcTray
.bottom
;
1290 rcWorkArea
.left
= rcTray
.right
;
1293 rcWorkArea
.right
= rcTray
.left
;
1296 rcWorkArea
.bottom
= rcTray
.top
;
1302 * Resize the current monitor work area. Win32k will also send
1303 * a WM_SIZE message to automatically resize the desktop.
1305 SystemParametersInfoW(SPI_SETWORKAREA
,
1312 VOID
CheckTrayWndPosition()
1314 /* Force the rebar bands to resize */
1315 IUnknown_Exec(m_TrayBandSite
,
1317 DBID_BANDINFOCHANGED
,
1322 /* Calculate the size of the taskbar based on the rebar */
1323 FitToRebar(&m_TrayRects
[m_Position
]);
1325 /* Move the tray window */
1326 /* The handler of WM_WINDOWPOSCHANGING will override whatever size
1327 * and position we use here with m_TrayRects */
1328 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOZORDER
| SWP_NOACTIVATE
);
1330 ApplyClipping(TRUE
);
1333 VOID
RegLoadSettings()
1337 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1338 SIZE StartBtnSize
= m_StartButton
.GetSize();
1340 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1341 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1342 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1343 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1345 m_Position
= g_TaskbarSettings
.sr
.Position
;
1346 rcScreen
= g_TaskbarSettings
.sr
.Rect
;
1347 GetScreenRectFromRect(&rcScreen
, MONITOR_DEFAULTTONEAREST
);
1349 if (!g_TaskbarSettings
.sr
.Size
.cx
|| !g_TaskbarSettings
.sr
.Size
.cy
)
1351 /* Use the minimum size of the taskbar, we'll use the start
1352 button as a minimum for now. Make sure we calculate the
1353 entire window size, not just the client size. However, we
1354 use a thinner border than a standard thick border, so that
1355 the start button and bands are not stuck to the screen border. */
1358 g_TaskbarSettings
.sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1359 g_TaskbarSettings
.sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1363 g_TaskbarSettings
.sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1364 g_TaskbarSettings
.sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1365 if(!g_TaskbarSettings
.bLock
)
1366 g_TaskbarSettings
.sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1369 /* Determine a minimum tray window rectangle. The "client" height is
1370 zero here since we cannot determine an optimal minimum width when
1371 loaded as a vertical tray window. We just need to make sure the values
1372 loaded from the registry are at least. The windows explorer behaves
1373 the same way, it allows the user to save a zero width vertical tray
1374 window, but not a zero height horizontal tray window. */
1377 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1378 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1382 WndSize
.cx
= StartBtnSize
.cx
;
1383 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1386 if (WndSize
.cx
< g_TaskbarSettings
.sr
.Size
.cx
)
1387 WndSize
.cx
= g_TaskbarSettings
.sr
.Size
.cx
;
1388 if (WndSize
.cy
< g_TaskbarSettings
.sr
.Size
.cy
)
1389 WndSize
.cy
= g_TaskbarSettings
.sr
.Size
.cy
;
1391 /* Save the calculated size */
1392 m_TraySize
= WndSize
;
1394 /* Calculate all docking rectangles. We need to do this here so they're
1395 initialized and dragging the tray window to another position gives
1397 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1399 GetTrayRectFromScreenRect(Pos
,
1403 // 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);
1406 /* Determine which monitor we are on. It shouldn't matter which docked
1407 position rectangle we use */
1408 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1411 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1414 SIZE TraySize
, StartSize
;
1415 POINT ptTrayNotify
= { 0, 0 };
1419 m_StartButton
.UpdateSize();
1420 if (prcClient
!= NULL
)
1422 rcClient
= *prcClient
;
1426 if (!GetClientRect(&rcClient
))
1428 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1433 Horizontal
= IsPosHorizontal();
1435 /* We're about to resize/move the start button, the rebar control and
1436 the tray notification control */
1437 dwp
= BeginDeferWindowPos(3);
1440 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1444 /* Limit the Start button width to the client width, if necessary */
1445 StartSize
= m_StartButton
.GetSize();
1446 if (StartSize
.cx
> rcClient
.right
)
1447 StartSize
.cx
= rcClient
.right
;
1451 HWND hwndTaskToolbar
= ::GetWindow(m_TaskSwitch
, GW_CHILD
);
1452 if (hwndTaskToolbar
)
1454 DWORD size
= SendMessageW(hwndTaskToolbar
, TB_GETBUTTONSIZE
, 0, 0);
1455 StartSize
.cy
= HIWORD(size
);
1459 if (m_StartButton
.m_hWnd
!= NULL
)
1461 /* Resize and reposition the button */
1462 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1468 SWP_NOZORDER
| SWP_NOACTIVATE
);
1471 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1476 /* Determine the size that the tray notification window needs */
1480 TraySize
.cy
= rcClient
.bottom
;
1484 TraySize
.cx
= rcClient
.right
;
1488 if (m_TrayNotify
!= NULL
&&
1489 SendMessage(m_TrayNotify
,
1490 TNWM_GETMINIMUMSIZE
,
1494 /* Move the tray notification window to the desired location */
1496 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1498 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1500 dwp
= ::DeferWindowPos(dwp
,
1507 SWP_NOZORDER
| SWP_NOACTIVATE
);
1510 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1515 /* Resize/Move the rebar control */
1516 if (m_Rebar
!= NULL
)
1518 POINT ptRebar
= { 0, 0 };
1521 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1525 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1526 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1527 szRebar
.cy
= rcClient
.bottom
;
1531 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1532 szRebar
.cx
= rcClient
.right
;
1533 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1536 dwp
= ::DeferWindowPos(dwp
,
1543 SWP_NOZORDER
| SWP_NOACTIVATE
);
1547 EndDeferWindowPos(dwp
);
1549 if (m_TaskSwitch
!= NULL
)
1551 /* Update the task switch window configuration */
1552 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1556 void FitToRebar(PRECT pRect
)
1558 /* Get the rect of the rebar */
1559 RECT rebarRect
, taskbarRect
, clientRect
;
1560 ::GetWindowRect(m_Rebar
, &rebarRect
);
1561 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1562 ::GetClientRect(m_hWnd
, &clientRect
);
1563 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1565 /* Calculate the difference of size of the taskbar and the rebar */
1567 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- clientRect
.right
+ clientRect
.left
;
1568 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- clientRect
.bottom
+ clientRect
.top
;
1570 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1574 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1575 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1576 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1579 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1580 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1581 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1584 rebarRect
.right
= rebarRect
.left
+ (pRect
->right
- pRect
->left
- margins
.cx
);
1585 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1586 pRect
->right
= pRect
->left
+ (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1589 rebarRect
.left
= rebarRect
.right
- (pRect
->right
- pRect
->left
- margins
.cx
);
1590 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1591 pRect
->left
= pRect
->right
- (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1595 CalculateValidSize(m_Position
, pRect
);
1598 void PopupStartMenu()
1600 if (m_StartMenuPopup
!= NULL
)
1606 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1611 pt
.x
= rcExclude
.left
;
1612 pt
.y
= rcExclude
.top
;
1613 dwFlags
|= MPPF_TOP
;
1616 pt
.x
= rcExclude
.left
;
1617 pt
.y
= rcExclude
.bottom
;
1618 dwFlags
|= MPPF_BOTTOM
;
1621 pt
.x
= rcExclude
.right
;
1622 pt
.y
= rcExclude
.top
;
1623 dwFlags
|= MPPF_RIGHT
;
1626 pt
.x
= rcExclude
.left
;
1627 pt
.y
= rcExclude
.top
;
1628 dwFlags
|= MPPF_LEFT
;
1632 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1634 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1639 void ProcessMouseTracking()
1644 UINT state
= m_AutoHideState
;
1647 GetWindowRect(&rcCurrent
);
1648 over
= PtInRect(&rcCurrent
, pt
);
1650 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1657 if (state
== AUTOHIDE_HIDING
)
1659 TRACE("AutoHide cancelling hide.\n");
1660 m_AutoHideState
= AUTOHIDE_SHOWING
;
1661 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1663 else if (state
== AUTOHIDE_HIDDEN
)
1665 TRACE("AutoHide starting show.\n");
1666 m_AutoHideState
= AUTOHIDE_SHOWING
;
1667 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1672 if (state
== AUTOHIDE_SHOWING
)
1674 TRACE("AutoHide cancelling show.\n");
1675 m_AutoHideState
= AUTOHIDE_HIDING
;
1676 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1678 else if (state
== AUTOHIDE_SHOWN
)
1680 TRACE("AutoHide starting hide.\n");
1681 m_AutoHideState
= AUTOHIDE_HIDING
;
1682 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1685 KillTimer(TIMER_ID_MOUSETRACK
);
1689 void ProcessAutoHide()
1691 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1692 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1694 switch (m_AutoHideState
)
1696 case AUTOHIDE_HIDING
:
1700 m_AutoHideOffset
.cy
= 0;
1701 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1702 if (m_AutoHideOffset
.cx
< -w
)
1703 m_AutoHideOffset
.cx
= -w
;
1706 m_AutoHideOffset
.cx
= 0;
1707 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1708 if (m_AutoHideOffset
.cy
< -h
)
1709 m_AutoHideOffset
.cy
= -h
;
1712 m_AutoHideOffset
.cy
= 0;
1713 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1714 if (m_AutoHideOffset
.cx
> w
)
1715 m_AutoHideOffset
.cx
= w
;
1718 m_AutoHideOffset
.cx
= 0;
1719 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1720 if (m_AutoHideOffset
.cy
> h
)
1721 m_AutoHideOffset
.cy
= h
;
1725 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1727 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1732 case AUTOHIDE_HIDDEN
:
1737 m_AutoHideOffset
.cx
= -w
;
1738 m_AutoHideOffset
.cy
= 0;
1741 m_AutoHideOffset
.cx
= 0;
1742 m_AutoHideOffset
.cy
= -h
;
1745 m_AutoHideOffset
.cx
= w
;
1746 m_AutoHideOffset
.cy
= 0;
1749 m_AutoHideOffset
.cx
= 0;
1750 m_AutoHideOffset
.cy
= h
;
1754 KillTimer(TIMER_ID_AUTOHIDE
);
1755 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1758 case AUTOHIDE_SHOWING
:
1759 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1761 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1763 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1765 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1769 m_AutoHideOffset
.cx
= 0;
1772 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1774 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1776 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1778 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1782 m_AutoHideOffset
.cy
= 0;
1785 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1787 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1792 case AUTOHIDE_SHOWN
:
1794 KillTimer(TIMER_ID_AUTOHIDE
);
1795 m_AutoHideState
= AUTOHIDE_SHOWN
;
1799 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOZORDER
);
1806 /**********************************************************
1807 * ##### taskbar drawing #####
1810 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1813 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1815 ASSERT(m_Position
<= ABE_BOTTOM
);
1819 GetClientRect(&rect
);
1820 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1826 int DrawSizerWithTheme(IN HRGN hRgn
)
1830 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1833 ASSERT(m_Position
<= ABE_BOTTOM
);
1835 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
1836 if (FAILED_UNEXPECTEDLY(hr
))
1839 GetWindowRect(&rect
);
1840 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1842 hdc
= GetWindowDC();
1847 rect
.left
= rect
.right
- size
.cx
;
1850 rect
.top
= rect
.bottom
- size
.cy
;
1853 rect
.right
= rect
.left
+ size
.cx
;
1857 rect
.bottom
= rect
.top
+ size
.cy
;
1861 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
1874 HRESULT STDMETHODCALLTYPE
Open()
1878 /* Check if there's already a window created and try to show it.
1879 If it was somehow destroyed just create a new tray window. */
1880 if (m_hWnd
!= NULL
&& IsWindow())
1885 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1886 if (g_TaskbarSettings
.sr
.AlwaysOnTop
)
1887 dwExStyle
|= WS_EX_TOPMOST
;
1889 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1892 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1895 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1896 if (m_Position
!= (DWORD
) -1)
1897 rcWnd
= m_TrayRects
[m_Position
];
1899 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1902 /* Align all controls on the tray window */
1903 AlignControls(NULL
);
1905 /* Move the tray window to the right position and resize it if necessary */
1906 CheckTrayWndPosition();
1911 HRESULT STDMETHODCALLTYPE
Close()
1924 HWND STDMETHODCALLTYPE
GetHWND()
1929 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1931 return (m_hWnd
== hWnd
||
1932 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1935 BOOL STDMETHODCALLTYPE
IsHorizontal()
1937 return IsPosHorizontal();
1940 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1942 BOOL bPrevLock
= g_TaskbarSettings
.bLock
;
1944 if (g_TaskbarSettings
.bLock
!= bLock
)
1946 g_TaskbarSettings
.bLock
= bLock
;
1948 if (m_TrayBandSite
!= NULL
)
1950 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1953 g_TaskbarSettings
.bLock
= bPrevLock
;
1960 /* Update cached tray sizes */
1961 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1963 RECT rcGripper
= {0};
1964 AdjustSizerRect(&rcGripper
, Pos
);
1966 if(g_TaskbarSettings
.bLock
)
1968 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
1969 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
1970 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
1971 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
1975 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
1976 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
1977 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
1978 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
1982 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1984 ApplyClipping(TRUE
);
1994 HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup
,
2002 HRESULT hr
= TrayWindowCtxMenuCreator(this, m_hWnd
, &m_ContextMenu
);
2003 if (FAILED_UNEXPECTEDLY(hr
))
2007 return m_ContextMenu
->QueryContextMenu(hPopup
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
2010 HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2013 return E_INVALIDARG
;
2015 return m_ContextMenu
->InvokeCommand(lpici
);
2018 HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd
,
2025 return E_INVALIDARG
;
2027 return m_ContextMenu
->GetCommandString(idCmd
, uType
, pwReserved
, pszName
, cchMax
);
2031 /**********************************************************
2032 * ##### message handling #####
2035 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2039 ((ITrayWindow
*)this)->AddRef();
2041 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2043 /* Create the Start button */
2044 m_StartButton
.Create(m_hWnd
);
2046 /* Load the saved tray window settings */
2049 /* Create and initialize the start menu */
2050 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2051 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2053 /* Create the task band */
2054 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2055 if (FAILED_UNEXPECTEDLY(hRet
))
2058 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2059 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2060 if (FAILED_UNEXPECTEDLY(hRet
))
2063 /* Create the tray notification window */
2064 hRet
= CTrayNotifyWnd_CreateInstance(m_hWnd
, IID_PPV_ARG(IUnknown
, &m_TrayNotifyInstance
));
2065 if (FAILED_UNEXPECTEDLY(hRet
))
2068 /* Get the hwnd of the rebar */
2069 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2070 if (FAILED_UNEXPECTEDLY(hRet
))
2073 /* Get the hwnd of the tasks toolbar */
2074 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2075 if (FAILED_UNEXPECTEDLY(hRet
))
2078 /* Get the hwnd of the tray notification window */
2079 hRet
= IUnknown_GetWindow(m_TrayNotifyInstance
, &m_TrayNotify
);
2080 if (FAILED_UNEXPECTEDLY(hRet
))
2083 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2087 InitShellServices(&m_ShellServices
);
2089 if (g_TaskbarSettings
.sr
.AutoHide
)
2091 m_AutoHideState
= AUTOHIDE_HIDING
;
2092 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2095 /* Set the initial lock state in the band site */
2096 m_TrayBandSite
->Lock(g_TaskbarSettings
.bLock
);
2098 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2099 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2100 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2101 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2102 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2103 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2104 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2105 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2106 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2107 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2108 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2109 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2114 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2117 CloseThemeData(m_Theme
);
2119 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2123 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2127 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2129 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2134 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2136 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2138 SendMessage(m_TrayNotify
, uMsg
, wParam
, lParam
);
2139 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2141 AlignControls(NULL
);
2142 CheckTrayWndPosition();
2148 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2150 HDC hdc
= (HDC
) wParam
;
2158 return EraseBackgroundWithTheme(hdc
);
2161 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2163 /* Load the saved tray window settings */
2166 /* Move the tray window to the right position and resize it if necessary */
2167 CheckTrayWndPosition();
2172 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2175 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2179 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2186 else if (g_TaskbarSettings
.bLock
)
2191 return DrawSizerWithTheme((HRGN
) wParam
);
2194 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2196 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2197 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2200 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2205 if (g_TaskbarSettings
.bLock
)
2207 /* The user may not be able to resize the tray window.
2208 Pretend like the window is not sizeable when the user
2209 clicks on the border. */
2213 SetLastError(ERROR_SUCCESS
);
2214 if (GetClientRect(&rcClient
) &&
2215 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2217 pt
.x
= (SHORT
) LOWORD(lParam
);
2218 pt
.y
= (SHORT
) HIWORD(lParam
);
2220 if (PtInRect(&rcClient
, pt
))
2222 /* The user is trying to drag the tray window */
2226 /* Depending on the position of the tray window, allow only
2227 changing the border next to the monitor working area */
2231 if (pt
.y
> rcClient
.bottom
)
2235 if (pt
.x
> rcClient
.right
)
2239 if (pt
.x
< rcClient
.left
)
2244 if (pt
.y
< rcClient
.top
)
2252 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2255 PRECT pRect
= (PRECT
) lParam
;
2257 /* We need to ensure that an application can not accidently
2258 move the tray window (using SetWindowPos). However, we still
2259 need to be able to move the window in case the user wants to
2260 drag the tray window to another position or in case the user
2261 wants to resize the tray window. */
2262 if (!g_TaskbarSettings
.bLock
&& GetCursorPos(&ptCursor
))
2265 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2269 *pRect
= m_TrayRects
[m_Position
];
2274 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2276 PRECT pRect
= (PRECT
) lParam
;
2278 if (!g_TaskbarSettings
.bLock
)
2284 *pRect
= m_TrayRects
[m_Position
];
2289 LRESULT
OnWindowPosChanging(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2291 ChangingWinPos((LPWINDOWPOS
) lParam
);
2295 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2298 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2301 /* Clip the tray window on multi monitor systems so the edges can't
2302 overlap into another monitor */
2303 ApplyClipping(TRUE
);
2305 if (!GetClientRect(&rcClient
))
2312 rcClient
.left
= rcClient
.top
= 0;
2313 rcClient
.right
= LOWORD(lParam
);
2314 rcClient
.bottom
= HIWORD(lParam
);
2317 AlignControls(&rcClient
);
2321 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2325 if (!g_TaskbarSettings
.bLock
)
2327 /* Remove the clipping on multi monitor systems while dragging around */
2328 ApplyClipping(FALSE
);
2333 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2336 if (!g_TaskbarSettings
.bLock
)
2338 FitToRebar(&m_TrayRects
[m_Position
]);
2340 /* Apply clipping */
2341 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2346 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2352 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2353 The tray window needs to handle this specially, since it normally doesn't have
2356 static const UINT uidDisableItem
[] = {
2366 /* temporarily enable the system menu */
2367 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2369 hSysMenu
= GetSystemMenu(FALSE
);
2370 if (hSysMenu
!= NULL
)
2372 /* Disable all items that are not relevant */
2373 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2375 EnableMenuItem(hSysMenu
,
2377 MF_BYCOMMAND
| MF_GRAYED
);
2380 EnableMenuItem(hSysMenu
,
2383 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2385 /* Display the system menu */
2389 m_StartButton
.m_hWnd
,
2390 m_Position
!= ABE_TOP
,
2394 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2398 /* revert the system menu window style */
2399 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2409 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2411 /* This handler implements the trick that makes the start button to
2412 get pressed when the user clicked left or below the button */
2414 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2415 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2420 m_StartButton
.GetWindowRect(&rcStartBtn
);
2421 GetWindowInfo(m_hWnd
, &wi
);
2428 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2434 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2437 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2438 pt
.x
> rcStartBtn
.right
)
2446 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2451 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2452 pt
.y
> rcStartBtn
.bottom
)
2466 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2468 /* We want the user to be able to get a context menu even on the nonclient
2469 area (including the sizing border)! */
2470 uMsg
= WM_CONTEXTMENU
;
2471 wParam
= (WPARAM
) m_hWnd
;
2473 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2476 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2478 LRESULT Ret
= FALSE
;
2479 POINT pt
, *ppt
= NULL
;
2480 HWND hWndExclude
= NULL
;
2482 /* Check if the administrator has forbidden access to context menus */
2483 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2486 pt
.x
= (SHORT
) LOWORD(lParam
);
2487 pt
.y
= (SHORT
) HIWORD(lParam
);
2489 if (pt
.x
!= -1 || pt
.y
!= -1)
2492 hWndExclude
= m_StartButton
.m_hWnd
;
2494 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2496 /* Make sure we can't track the context menu if the start
2497 menu is currently being shown */
2498 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2500 CComPtr
<IContextMenu
> ctxMenu
;
2501 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2502 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2507 /* See if the context menu should be handled by the task band site */
2508 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2511 POINT ptClient
= *ppt
;
2513 /* Convert the coordinates to client-coordinates */
2514 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2516 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2517 if (hWndAtPt
!= NULL
&&
2518 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2520 /* Check if the user clicked on the task switch window */
2522 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2524 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2525 if (hWndAtPt
== m_TaskSwitch
)
2526 goto HandleTrayContextMenu
;
2528 /* Forward the message to the task band site */
2529 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2532 goto HandleTrayContextMenu
;
2536 HandleTrayContextMenu
:
2537 /* Tray the default tray window context menu */
2538 TrackCtxMenu(this, ppt
, NULL
, FALSE
, this);
2544 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2546 LRESULT Ret
= FALSE
;
2547 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2548 the rebar control! But we shouldn't forward messages that the band
2549 site doesn't handle, such as other controls (start button, tray window */
2551 HRESULT hr
= E_FAIL
;
2555 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2560 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2562 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2564 if (nmh
->hwndFrom
== m_TrayNotify
)
2569 /* Cause all controls to be aligned */
2570 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2578 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2580 /* Let the clock handle the double click */
2581 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2583 /* We "handle" this message so users can't cause a weird maximize/restore
2584 window animation when double-clicking the tray window! */
2588 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2594 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2597 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2598 if (FAILED_UNEXPECTEDLY(hr
))
2601 if (::IsWindowVisible(hwndStartMenu
))
2603 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2613 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2616 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2617 * to show the shutdown dialog. Also a WM_CLOSE message sent
2618 * by apps should show the dialog.
2620 return DoExitWindows();
2623 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2625 if (wParam
== SC_CLOSE
)
2627 return DoExitWindows();
2634 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2636 return HandleHotKey(wParam
);
2639 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2641 LRESULT Ret
= FALSE
;
2643 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2648 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2650 return HandleCommand(LOWORD(wParam
));
2655 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2657 if (g_TaskbarSettings
.sr
.AutoHide
)
2659 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2665 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2667 if (wParam
== TIMER_ID_MOUSETRACK
)
2669 ProcessMouseTracking();
2671 else if (wParam
== TIMER_ID_AUTOHIDE
)
2680 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2683 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2684 if(!m_Theme
|| g_TaskbarSettings
.bLock
)
2695 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2696 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2701 rc
= &prms
->rgrc
[0];
2704 AdjustSizerRect(rc
, m_Position
);
2709 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2712 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2718 ::GetWindowRect(m_hWnd
, &rc
);
2722 rc
.bottom
- rc
.top
};
2724 as
->rcTarget
.right
- as
->rcTarget
.left
,
2725 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2727 as
->rcActual
.right
- as
->rcActual
.left
,
2728 as
->rcActual
.bottom
- as
->rcActual
.top
};
2731 szWindow
.cx
- szTarget
.cx
,
2732 szWindow
.cy
- szTarget
.cx
,
2738 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2741 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2744 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2745 rc
.left
= rc
.right
- szWindow
.cy
;
2748 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2749 rc
.top
= rc
.bottom
- szWindow
.cy
;
2753 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2760 LRESULT
OnTaskbarSettingsChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2762 TaskbarSettings
* newSettings
= (TaskbarSettings
*)lParam
;
2764 /* Propagate the new settings to the children */
2765 ::SendMessageW(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2766 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2768 /* Toggle autohide */
2769 if (newSettings
->sr
.AutoHide
!= g_TaskbarSettings
.sr
.AutoHide
)
2771 g_TaskbarSettings
.sr
.AutoHide
= newSettings
->sr
.AutoHide
;
2772 memset(&m_AutoHideOffset
, 0, sizeof(m_AutoHideOffset
));
2773 m_AutoHideState
= AUTOHIDE_SHOWN
;
2774 if (!newSettings
->sr
.AutoHide
)
2775 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOZORDER
);
2777 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2780 /* Toggle lock state */
2781 Lock(newSettings
->bLock
);
2783 /* Toggle OnTop state */
2784 if (newSettings
->sr
.AlwaysOnTop
!= g_TaskbarSettings
.sr
.AlwaysOnTop
)
2786 g_TaskbarSettings
.sr
.AlwaysOnTop
= newSettings
->sr
.AlwaysOnTop
;
2787 HWND hWndInsertAfter
= newSettings
->sr
.AlwaysOnTop
? HWND_TOPMOST
: HWND_BOTTOM
;
2788 SetWindowPos(hWndInsertAfter
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_SHOWWINDOW
);
2791 g_TaskbarSettings
.Save();
2795 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2797 BEGIN_MSG_MAP(CTrayWindow
)
2798 if (m_StartMenuBand
!= NULL
)
2805 Msg
.wParam
= wParam
;
2806 Msg
.lParam
= lParam
;
2808 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2813 wParam
= Msg
.wParam
;
2814 lParam
= Msg
.lParam
;
2816 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2817 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2818 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2819 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2820 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2821 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2822 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2823 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2824 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2825 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2826 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2827 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2828 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2829 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2830 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2831 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2832 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2833 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2834 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2835 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChanging
)
2836 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2837 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2838 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
2839 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2840 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2841 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2842 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2843 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2844 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2845 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2846 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2847 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2848 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2849 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2850 MESSAGE_HANDLER(TWM_SETTINGSCHANGED
, OnTaskbarSettingsChanged
)
2854 /*****************************************************************************/
2856 VOID
TrayProcessMessages()
2860 /* FIXME: We should keep a reference here... */
2862 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2864 if (Msg
.message
== WM_QUIT
)
2867 if (m_StartMenuBand
== NULL
||
2868 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2870 TranslateMessage(&Msg
);
2871 DispatchMessage(&Msg
);
2876 VOID
TrayMessageLoop()
2881 /* FIXME: We should keep a reference here... */
2885 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2887 if (!Ret
|| Ret
== -1)
2890 if (m_StartMenuBand
== NULL
||
2891 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2893 TranslateMessage(&Msg
);
2894 DispatchMessage(&Msg
);
2902 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2903 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2904 * The reason we implement it is because we have to use SHCreateDesktop() so
2905 * that the shell provides the desktop window and all the features that come
2906 * with it (especially positioning of desktop icons)
2909 virtual ULONG STDMETHODCALLTYPE
GetState()
2911 /* FIXME: Return ABS_ flags? */
2912 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2916 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2918 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2919 *phWndTray
= m_hWnd
;
2923 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2925 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2927 m_DesktopWnd
= hWndDesktop
;
2931 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2933 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2937 virtual HRESULT
RaiseStartButton()
2939 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2943 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
2946 return E_INVALIDARG
;
2951 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
2958 m_Position
= (DWORD
) -1;
2961 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2963 DECLARE_PROTECT_FINAL_CONSTRUCT()
2964 BEGIN_COM_MAP(CTrayWindow
)
2965 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2966 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2967 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
2968 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
2972 class CTrayWindowCtxMenu
:
2973 public CComCoClass
<CTrayWindowCtxMenu
>,
2974 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2978 CComPtr
<CTrayWindow
> TrayWnd
;
2979 CComPtr
<IContextMenu
> pcm
;
2980 UINT m_idCmdCmFirst
;
2983 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2985 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2986 this->hWndOwner
= hWndOwner
;
2987 this->m_idCmdCmFirst
= 0;
2991 virtual HRESULT STDMETHODCALLTYPE
2992 QueryContextMenu(HMENU hPopup
,
2998 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3000 return HRESULT_FROM_WIN32(GetLastError());
3002 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3009 CheckMenuItem(menubase
,
3011 MF_BYCOMMAND
| (g_TaskbarSettings
.bLock
? MF_CHECKED
: MF_UNCHECKED
));
3014 idCmdNext
= Shell_MergeMenus(hPopup
, menubase
, indexMenu
, idCmdFirst
, idCmdLast
, MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
3015 m_idCmdCmFirst
= idCmdNext
- idCmdFirst
;
3017 ::DestroyMenu(menubase
);
3019 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3021 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3029 WARN("AddContextMenus failed.\n");
3037 virtual HRESULT STDMETHODCALLTYPE
3038 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3040 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3043 if (uiCmdId
>= m_idCmdCmFirst
)
3045 CMINVOKECOMMANDINFO cmici
= { 0 };
3049 /* Setup and invoke the shell command */
3050 cmici
.cbSize
= sizeof(cmici
);
3051 cmici
.hwnd
= hWndOwner
;
3052 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- m_idCmdCmFirst
);
3053 cmici
.nShow
= SW_NORMAL
;
3055 pcm
->InvokeCommand(&cmici
);
3060 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3067 virtual HRESULT STDMETHODCALLTYPE
3068 GetCommandString(UINT_PTR idCmd
,
3077 CTrayWindowCtxMenu()
3081 virtual ~CTrayWindowCtxMenu()
3085 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3086 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3090 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3092 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3093 mnu
->Initialize(TrayWnd
, hWndOwner
);
3098 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3100 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3102 return E_OUTOFMEMORY
;
3107 *ppTray
= (ITrayWindow
*) Tray
;
3113 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3115 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3116 return TrayWindow
->RaiseStartButton();
3119 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3121 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3122 TrayWindow
->TrayProcessMessages();
3125 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3127 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3128 TrayWindow
->TrayMessageLoop();