4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * this library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * this library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
26 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
28 #define TIMER_ID_AUTOHIDE 1
29 #define TIMER_ID_MOUSETRACK 2
30 #define MOUSETRACK_INTERVAL 100
31 #define AUTOHIDE_DELAY_HIDE 2000
32 #define AUTOHIDE_DELAY_SHOW 50
33 #define AUTOHIDE_INTERVAL_ANIMATING 10
35 #define AUTOHIDE_SPEED_SHOW 10
36 #define AUTOHIDE_SPEED_HIDE 1
38 #define AUTOHIDE_HIDDEN 0
39 #define AUTOHIDE_SHOWING 1
40 #define AUTOHIDE_SHOWN 2
41 #define AUTOHIDE_HIDING 3
43 #define IDHK_RUN 0x1f4
44 #define IDHK_MINIMIZE_ALL 0x1f5
45 #define IDHK_RESTORE_ALL 0x1f6
46 #define IDHK_HELP 0x1f7
47 #define IDHK_EXPLORE 0x1f8
48 #define IDHK_FIND 0x1f9
49 #define IDHK_FIND_COMPUTER 0x1fa
50 #define IDHK_NEXT_TASK 0x1fb
51 #define IDHK_PREV_TASK 0x1fc
52 #define IDHK_SYS_PROPERTIES 0x1fd
53 #define IDHK_DESKTOP 0x1fe
54 #define IDHK_PAGER 0x1ff
56 static const WCHAR szTrayWndClass
[] = L
"Shell_TrayWnd";
62 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
65 : public CWindowImpl
<CStartButton
>
67 HIMAGELIST m_ImageList
;
80 virtual ~CStartButton()
82 if (m_ImageList
!= NULL
)
83 ImageList_Destroy(m_ImageList
);
98 if (m_ImageList
== NULL
||
99 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
101 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
) + GetSystemMetrics(SM_CYCAPTION
) * 3;
104 Size
.cy
= max(Size
.cy
, GetSystemMetrics(SM_CYCAPTION
));
106 /* Save the size of the start button */
112 /* Get the system fonts, we use the caption font, always bold, though. */
113 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
114 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
118 DeleteObject(m_Font
);
120 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
121 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
123 SetFont(m_Font
, FALSE
);
128 SubclassWindow(m_hWnd
);
129 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
131 m_ImageList
= ImageList_LoadImageW(hExplorerInstance
,
132 MAKEINTRESOURCEW(IDB_START
),
135 LR_LOADTRANSPARENT
| LR_CREATEDIBSECTION
);
137 BUTTON_IMAGELIST bil
= {m_ImageList
, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT
};
138 SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
);
142 HWND
Create(HWND hwndParent
)
144 WCHAR szStartCaption
[32];
145 if (!LoadStringW(hExplorerInstance
,
148 _countof(szStartCaption
)))
150 wcscpy(szStartCaption
, L
"Start");
153 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| BS_PUSHBUTTON
| BS_LEFT
| BS_VCENTER
;
155 m_hWnd
= CreateWindowEx(
162 (HMENU
) IDC_STARTBTN
,
172 LRESULT
OnLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
174 if (uMsg
== WM_KEYUP
&& wParam
!= VK_SPACE
)
177 GetParent().PostMessage(TWM_OPENSTARTMENU
);
181 BEGIN_MSG_MAP(CStartButton
)
182 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
188 public CComCoClass
<CTrayWindow
>,
189 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
190 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
192 public IShellDesktopTray
,
196 CStartButton m_StartButton
;
198 CComPtr
<IMenuBand
> m_StartMenuBand
;
199 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
201 CComPtr
<IDeskBand
> m_TaskBand
;
202 CComPtr
<IContextMenu
> m_ContextMenu
;
212 CTrayNotifyWnd
* m_TrayNotifyInstance
;
216 HMONITOR m_PreviousMonitor
;
217 DWORD m_DraggingPosition
;
218 HMONITOR m_DraggingMonitor
;
223 HWND m_TrayPropertiesOwner
;
224 HWND m_RunFileDlgOwner
;
226 UINT m_AutoHideState
;
227 SIZE m_AutoHideOffset
;
228 TRACKMOUSEEVENT m_MouseTrackingInfo
;
230 HDPA m_ShellServices
;
233 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
241 DWORD 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 ExitWindowsDialog(m_hWnd
);
334 DWORD WINAPI
RunFileDlgThread()
339 m_StartButton
.GetWindowRect(&posRect
);
341 hwnd
= CreateWindowEx(0,
344 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
347 posRect
.right
- posRect
.left
,
348 posRect
.bottom
- posRect
.top
,
354 m_RunFileDlgOwner
= hwnd
;
356 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
358 m_RunFileDlgOwner
= NULL
;
359 ::DestroyWindow(hwnd
);
364 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
366 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
367 return This
->RunFileDlgThread();
370 void DisplayRunFileDlg()
373 if (m_RunFileDlgOwner
)
375 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
376 if (hRunDlg
!= NULL
&&
377 hRunDlg
!= m_RunFileDlgOwner
)
379 SetForegroundWindow(hRunDlg
);
384 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
387 DWORD WINAPI
TrayPropertiesThread()
392 m_StartButton
.GetWindowRect(&posRect
);
393 hwnd
= CreateWindowEx(0,
396 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
399 posRect
.right
- posRect
.left
,
400 posRect
.bottom
- posRect
.top
,
406 m_TrayPropertiesOwner
= hwnd
;
408 DisplayTrayProperties(hwnd
, m_hWnd
);
410 m_TrayPropertiesOwner
= NULL
;
411 ::DestroyWindow(hwnd
);
416 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
418 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
420 return This
->TrayPropertiesThread();
423 HWND STDMETHODCALLTYPE
DisplayProperties()
427 if (m_TrayPropertiesOwner
)
429 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
430 if (hTrayProp
!= NULL
&&
431 hTrayProp
!= m_TrayPropertiesOwner
)
433 SetForegroundWindow(hTrayProp
);
438 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
442 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
444 WCHAR szDir
[MAX_PATH
];
446 if (SHGetSpecialFolderPath(hWndOwner
,
448 CSIDL_COMMON_STARTMENU
,
451 ShellExecute(hWndOwner
,
460 VOID
OpenTaskManager(IN HWND hWndOwner
)
462 ShellExecute(hWndOwner
,
470 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
474 case ID_SHELL_CMD_PROPERTIES
:
478 case ID_SHELL_CMD_OPEN_ALL_USERS
:
479 OpenCommonStartMenuDirectory(m_hWnd
,
483 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
484 OpenCommonStartMenuDirectory(m_hWnd
,
489 if (SHRestricted(REST_CLASSICSHELL
) == 0)
491 Lock(!g_TaskbarSettings
.bLock
);
495 case ID_SHELL_CMD_OPEN_TASKMGR
:
496 OpenTaskManager(m_hWnd
);
499 case ID_SHELL_CMD_UNDO_ACTION
:
502 case ID_SHELL_CMD_SHOW_DESKTOP
:
505 case ID_SHELL_CMD_TILE_WND_H
:
506 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
509 case ID_SHELL_CMD_TILE_WND_V
:
510 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
513 case ID_SHELL_CMD_CASCADE_WND
:
514 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
517 case ID_SHELL_CMD_CUST_NOTIF
:
518 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
521 case ID_SHELL_CMD_ADJUST_DAT
:
522 //FIXME: Use SHRunControlPanel
523 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
527 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
534 LRESULT
HandleHotKey(DWORD id
)
542 ExecResourceCmd(IDS_HELP_COMMAND
);
545 //FIXME: We don't support this yet:
546 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
547 ShellExecuteW(0, NULL
, L
"explorer.exe", L
"/e ,", NULL
, 1);
550 SHFindFiles(NULL
, NULL
);
552 case IDHK_FIND_COMPUTER
:
553 SHFindComputer(NULL
, NULL
);
555 case IDHK_SYS_PROPERTIES
:
556 //FIXME: Use SHRunControlPanel
557 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
563 case IDHK_MINIMIZE_ALL
:
565 case IDHK_RESTORE_ALL
:
576 LRESULT
HandleCommand(UINT uCommand
)
580 case IDM_TASKBARANDSTARTMENU
:
585 SHFindFiles(NULL
, NULL
);
588 case IDM_HELPANDSUPPORT
:
589 ExecResourceCmd(IDS_HELP_COMMAND
);
596 /* FIXME: Handle these commands as well */
597 case IDM_SYNCHRONIZE
:
599 case IDM_UNDOCKCOMPUTER
:
603 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
617 IN POINT
*ppt OPTIONAL
,
618 IN HWND hwndExclude OPTIONAL
,
620 IN BOOL IsContextMenu
)
622 TPMPARAMS tmp
, *ptmp
= NULL
;
627 if (hwndExclude
!= NULL
)
629 /* Get the client rectangle and map it to screen coordinates */
630 if (::GetClientRect(hwndExclude
,
632 ::MapWindowPoints(hwndExclude
,
634 (LPPOINT
) &tmp
.rcExclude
,
644 GetClientRect(&tmp
.rcExclude
) &&
647 (LPPOINT
) &tmp
.rcExclude
,
655 /* NOTE: TrackPopupMenuEx will eventually align the track position
656 for us, no need to take care of it here as long as the
657 coordinates are somewhere within the exclusion rectangle */
658 pt
.x
= ptmp
->rcExclude
.left
;
659 pt
.y
= ptmp
->rcExclude
.top
;
667 tmp
.cbSize
= sizeof(tmp
);
669 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
670 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
672 fuFlags
|= TPM_RIGHTBUTTON
;
674 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
676 cmdId
= TrackPopupMenuEx(hMenu
,
686 HRESULT
TrackCtxMenu(
687 IN IContextMenu
* contextMenu
,
688 IN POINT
*ppt OPTIONAL
,
689 IN HWND hwndExclude OPTIONAL
,
691 IN PVOID Context OPTIONAL
)
697 HMENU popup
= CreatePopupMenu();
702 TRACE("Before Query\n");
703 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
704 if (FAILED_UNEXPECTEDLY(hr
))
706 TRACE("Query failed\n");
711 TRACE("Before Tracking\n");
712 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
716 TRACE("Before InvokeCommand\n");
717 CMINVOKECOMMANDINFO cmi
= { 0 };
718 cmi
.cbSize
= sizeof(cmi
);
719 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
721 hr
= contextMenu
->InvokeCommand(&cmi
);
725 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
737 /**********************************************************
738 * ##### moving and sizing handling #####
743 /* There is nothing to do if themes are enabled */
747 m_StartButton
.UpdateFont();
749 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
750 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
752 ERR("SPI_GETNONCLIENTMETRICS failed\n");
757 DeleteObject(m_Font
);
759 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
760 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
763 ERR("CreateFontIndirect failed\n");
767 SendMessage(m_Rebar
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
768 SendMessage(m_TaskSwitch
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
769 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
772 HMONITOR
GetScreenRectFromRect(
779 mi
.cbSize
= sizeof(mi
);
780 hMon
= MonitorFromRect(pRect
, dwFlags
);
782 GetMonitorInfo(hMon
, &mi
))
784 *pRect
= mi
.rcMonitor
;
790 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
791 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
799 HMONITOR
GetMonitorFromRect(
800 IN
const RECT
*pRect
)
804 /* In case the monitor sizes or saved sizes differ a bit (probably
805 not a lot, only so the tray window overlaps into another monitor
806 now), minimize the risk that we determine a wrong monitor by
807 using the center point of the tray window if we can't determine
808 it using the rectangle. */
809 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
814 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
815 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
817 /* be less error-prone, find the nearest monitor */
818 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
824 HMONITOR
GetScreenRect(
825 IN HMONITOR hMonitor
,
828 HMONITOR hMon
= NULL
;
830 if (hMonitor
!= NULL
)
834 mi
.cbSize
= sizeof(mi
);
835 if (!GetMonitorInfo(hMonitor
, &mi
))
837 /* Hm, the monitor is gone? Try to find a monitor where it
838 could be located now */
839 hMon
= GetMonitorFromRect(pRect
);
841 !GetMonitorInfo(hMon
, &mi
))
848 *pRect
= mi
.rcMonitor
;
855 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
856 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
862 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
864 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
867 if (pos
> ABE_BOTTOM
)
870 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[pos
], 0, NULL
, TS_TRUE
, &size
);
871 if (FAILED_UNEXPECTEDLY(hr
))
877 rc
->bottom
-= size
.cy
;
883 rc
->right
-= size
.cx
;
891 VOID
MakeTrayRectWithSize(IN DWORD Position
,
892 IN
const SIZE
*pTraySize
,
898 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
902 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
906 pRect
->left
= pRect
->right
- pTraySize
->cx
;
911 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
916 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
917 IN
const RECT
*pScreen
,
918 IN
const SIZE
*pTraySize OPTIONAL
,
921 if (pTraySize
== NULL
)
922 pTraySize
= &m_TraySize
;
928 /* Move the border outside of the screen */
930 GetSystemMetrics(SM_CXEDGE
),
931 GetSystemMetrics(SM_CYEDGE
));
934 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
937 BOOL
IsPosHorizontal()
939 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
942 HMONITOR
CalculateValidSize(
951 //Horizontal = IsPosHorizontal();
953 szWnd
.cx
= pRect
->right
- pRect
->left
;
954 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
957 hMon
= GetScreenRectFromRect(
959 MONITOR_DEFAULTTONEAREST
);
961 /* Calculate the maximum size of the tray window and limit the window
962 size to half of the screen's size. */
963 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
964 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
965 if (szWnd
.cx
> szMax
.cx
)
967 if (szWnd
.cy
> szMax
.cy
)
970 /* FIXME - calculate */
972 GetTrayRectFromScreenRect(Position
,
982 GetMinimumWindowSize(
987 AdjustWindowRectEx(&rcMin
,
988 GetWindowLong(m_hWnd
,
991 GetWindowLong(m_hWnd
,
999 DWORD
GetDraggingRectFromPt(
1002 OUT HMONITOR
*phMonitor
)
1004 HMONITOR hMon
, hMonNew
;
1005 DWORD PosH
, PosV
, Pos
;
1006 SIZE DeltaPt
, ScreenOffset
;
1012 /* Determine the screen rectangle */
1013 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
1018 mi
.cbSize
= sizeof(mi
);
1019 if (!GetMonitorInfo(hMon
, &mi
))
1022 goto GetPrimaryScreenRect
;
1025 /* make left top corner of the screen zero based to
1026 make calculations easier */
1027 pt
.x
-= mi
.rcMonitor
.left
;
1028 pt
.y
-= mi
.rcMonitor
.top
;
1030 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1031 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1032 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1033 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1037 GetPrimaryScreenRect
:
1038 ScreenOffset
.cx
= 0;
1039 ScreenOffset
.cy
= 0;
1040 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1041 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1044 /* Calculate the nearest screen border */
1045 if (pt
.x
< rcScreen
.right
/ 2)
1052 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1056 if (pt
.y
< rcScreen
.bottom
/ 2)
1063 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1067 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1069 /* Fix the screen origin to be relative to the primary monitor again */
1070 OffsetRect(&rcScreen
,
1074 RECT rcPos
= m_TrayRects
[Pos
];
1076 hMonNew
= GetMonitorFromRect(&rcPos
);
1077 if (hMon
!= hMonNew
)
1081 /* Recalculate the rectangle, we're dragging to another monitor.
1082 We don't need to recalculate the rect on single monitor systems. */
1083 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1084 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1086 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1091 /* The user is dragging the tray window on the same monitor. We don't need
1092 to recalculate the rectangle */
1101 DWORD
GetDraggingRectFromRect(
1103 OUT HMONITOR
*phMonitor
)
1107 /* Calculate the center of the rectangle. We call
1108 GetDraggingRectFromPt to calculate a valid
1109 dragging rectangle */
1110 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1111 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1113 return GetDraggingRectFromPt(
1119 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1125 rcTray
.left
= pwp
->x
;
1126 rcTray
.top
= pwp
->y
;
1127 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1128 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1130 if (!EqualRect(&rcTray
,
1131 &m_TrayRects
[m_DraggingPosition
]))
1133 /* Recalculate the rectangle, the user dragged the tray
1134 window to another monitor or the window was somehow else
1136 m_DraggingPosition
= GetDraggingRectFromRect(
1138 &m_DraggingMonitor
);
1139 //m_TrayRects[DraggingPosition] = rcTray;
1142 //Monitor = CalculateValidSize(DraggingPosition,
1145 m_Monitor
= m_DraggingMonitor
;
1146 m_Position
= m_DraggingPosition
;
1149 m_TrayRects
[m_Position
] = rcTray
;
1152 else if (GetWindowRect(&rcTray
))
1156 if (!(pwp
->flags
& SWP_NOMOVE
))
1158 rcTray
.left
= pwp
->x
;
1159 rcTray
.top
= pwp
->y
;
1162 if (!(pwp
->flags
& SWP_NOSIZE
))
1164 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1165 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1168 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1170 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1177 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1180 m_TrayRects
[m_Position
] = rcTray
;
1184 /* If the user isn't resizing the tray window we need to make sure the
1185 new size or position is valid. this is to prevent changes to the window
1186 without user interaction. */
1187 rcTray
= m_TrayRects
[m_Position
];
1189 if (g_TaskbarSettings
.sr
.AutoHide
)
1191 rcTray
.left
+= m_AutoHideOffset
.cx
;
1192 rcTray
.right
+= m_AutoHideOffset
.cx
;
1193 rcTray
.top
+= m_AutoHideOffset
.cy
;
1194 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1200 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1201 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1203 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1204 pwp
->x
= rcTray
.left
;
1205 pwp
->y
= rcTray
.top
;
1206 pwp
->cx
= m_TraySize
.cx
;
1207 pwp
->cy
= m_TraySize
.cy
;
1211 VOID
ApplyClipping(IN BOOL Clip
)
1213 RECT rcClip
, rcWindow
;
1216 if (GetWindowRect(&rcWindow
))
1218 /* Disable clipping on systems with only one monitor */
1219 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1226 GetScreenRect(m_Monitor
, &rcClip
);
1228 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1237 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1242 /* Set the clipping region or make sure the window isn't clipped
1243 by disabling it explicitly. */
1244 SetWindowRgn(hClipRgn
, TRUE
);
1248 VOID
ResizeWorkArea()
1250 #if !WIN7_DEBUG_MODE
1251 RECT rcTray
, rcWorkArea
;
1253 /* If monitor has changed then fix the previous monitors work area */
1254 if (m_PreviousMonitor
!= m_Monitor
)
1256 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1257 SystemParametersInfoW(SPI_SETWORKAREA
,
1263 rcTray
= m_TrayRects
[m_Position
];
1265 GetScreenRect(m_Monitor
, &rcWorkArea
);
1266 m_PreviousMonitor
= m_Monitor
;
1268 /* If AutoHide is false then change the workarea to exclude
1269 the area that the taskbar covers. */
1270 if (!g_TaskbarSettings
.sr
.AutoHide
)
1275 rcWorkArea
.top
= rcTray
.bottom
;
1278 rcWorkArea
.left
= rcTray
.right
;
1281 rcWorkArea
.right
= rcTray
.left
;
1284 rcWorkArea
.bottom
= rcTray
.top
;
1290 * Resize the current monitor work area. Win32k will also send
1291 * a WM_SIZE message to automatically resize the desktop.
1293 SystemParametersInfoW(SPI_SETWORKAREA
,
1300 VOID
CheckTrayWndPosition()
1302 /* Force the rebar bands to resize */
1303 IUnknown_Exec(m_TrayBandSite
,
1305 DBID_BANDINFOCHANGED
,
1310 /* Calculate the size of the taskbar based on the rebar */
1311 FitToRebar(&m_TrayRects
[m_Position
]);
1313 /* Move the tray window */
1314 /* The handler of WM_WINDOWPOSCHANGING will override whatever size
1315 *and position we use here with m_TrayRects */
1316 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOZORDER
| SWP_NOACTIVATE
);
1318 ApplyClipping(TRUE
);
1321 VOID
RegLoadSettings()
1325 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1326 SIZE StartBtnSize
= m_StartButton
.GetSize();
1328 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1329 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1330 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1331 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1333 m_Position
= g_TaskbarSettings
.sr
.Position
;
1334 rcScreen
= g_TaskbarSettings
.sr
.Rect
;
1335 GetScreenRectFromRect(&rcScreen
, MONITOR_DEFAULTTONEAREST
);
1337 if (!g_TaskbarSettings
.sr
.Size
.cx
|| !g_TaskbarSettings
.sr
.Size
.cy
)
1339 /* Use the minimum size of the taskbar, we'll use the start
1340 button as a minimum for now. Make sure we calculate the
1341 entire window size, not just the client size. However, we
1342 use a thinner border than a standard thick border, so that
1343 the start button and bands are not stuck to the screen border. */
1346 g_TaskbarSettings
.sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1347 g_TaskbarSettings
.sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1351 g_TaskbarSettings
.sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1352 g_TaskbarSettings
.sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1353 if(!g_TaskbarSettings
.bLock
)
1354 g_TaskbarSettings
.sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1357 /* Determine a minimum tray window rectangle. The "client" height is
1358 zero here since we cannot determine an optimal minimum width when
1359 loaded as a vertical tray window. We just need to make sure the values
1360 loaded from the registry are at least. The windows explorer behaves
1361 the same way, it allows the user to save a zero width vertical tray
1362 window, but not a zero height horizontal tray window. */
1365 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1366 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1370 WndSize
.cx
= StartBtnSize
.cx
;
1371 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1374 if (WndSize
.cx
< g_TaskbarSettings
.sr
.Size
.cx
)
1375 WndSize
.cx
= g_TaskbarSettings
.sr
.Size
.cx
;
1376 if (WndSize
.cy
< g_TaskbarSettings
.sr
.Size
.cy
)
1377 WndSize
.cy
= g_TaskbarSettings
.sr
.Size
.cy
;
1379 /* Save the calculated size */
1380 m_TraySize
= WndSize
;
1382 /* Calculate all docking rectangles. We need to do this here so they're
1383 initialized and dragging the tray window to another position gives
1385 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1387 GetTrayRectFromScreenRect(Pos
,
1391 // 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);
1394 /* Determine which monitor we are on. It shouldn't matter which docked
1395 position rectangle we use */
1396 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1399 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1402 SIZE TraySize
, StartSize
;
1403 POINT ptTrayNotify
= { 0, 0 };
1407 m_StartButton
.UpdateSize();
1408 if (prcClient
!= NULL
)
1410 rcClient
= *prcClient
;
1414 if (!GetClientRect(&rcClient
))
1416 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1421 Horizontal
= IsPosHorizontal();
1423 /* We're about to resize/move the start button, the rebar control and
1424 the tray notification control */
1425 dwp
= BeginDeferWindowPos(3);
1428 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1432 /* Limit the Start button width to the client width, if necessary */
1433 StartSize
= m_StartButton
.GetSize();
1434 if (StartSize
.cx
> rcClient
.right
)
1435 StartSize
.cx
= rcClient
.right
;
1439 HWND hwndTaskToolbar
= ::GetWindow(m_TaskSwitch
, GW_CHILD
);
1440 if (hwndTaskToolbar
)
1442 DWORD size
= SendMessageW(hwndTaskToolbar
, TB_GETBUTTONSIZE
, 0, 0);
1443 StartSize
.cy
= HIWORD(size
);
1447 if (m_StartButton
.m_hWnd
!= NULL
)
1449 /* Resize and reposition the button */
1450 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1456 SWP_NOZORDER
| SWP_NOACTIVATE
);
1459 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1464 /* Determine the size that the tray notification window needs */
1468 TraySize
.cy
= rcClient
.bottom
;
1472 TraySize
.cx
= rcClient
.right
;
1476 if (m_TrayNotify
!= NULL
&&
1477 SendMessage(m_TrayNotify
,
1478 TNWM_GETMINIMUMSIZE
,
1482 /* Move the tray notification window to the desired location */
1484 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1486 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1488 dwp
= ::DeferWindowPos(dwp
,
1495 SWP_NOZORDER
| SWP_NOACTIVATE
);
1498 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1503 /* Resize/Move the rebar control */
1504 if (m_Rebar
!= NULL
)
1506 POINT ptRebar
= { 0, 0 };
1509 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1513 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1514 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1515 szRebar
.cy
= rcClient
.bottom
;
1519 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1520 szRebar
.cx
= rcClient
.right
;
1521 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1524 dwp
= ::DeferWindowPos(dwp
,
1531 SWP_NOZORDER
| SWP_NOACTIVATE
);
1535 EndDeferWindowPos(dwp
);
1537 if (m_TaskSwitch
!= NULL
)
1539 /* Update the task switch window configuration */
1540 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1544 void FitToRebar(PRECT pRect
)
1546 /* Get the rect of the rebar */
1547 RECT rebarRect
, taskbarRect
, clientRect
;
1548 ::GetWindowRect(m_Rebar
, &rebarRect
);
1549 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1550 ::GetClientRect(m_hWnd
, &clientRect
);
1551 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1553 /* Calculate the difference of size of the taskbar and the rebar */
1555 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- clientRect
.right
+ clientRect
.left
;
1556 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- clientRect
.bottom
+ clientRect
.top
;
1558 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1562 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1563 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1564 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1567 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1568 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1569 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1572 rebarRect
.right
= rebarRect
.left
+ (pRect
->right
- pRect
->left
- margins
.cx
);
1573 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1574 pRect
->right
= pRect
->left
+ (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1577 rebarRect
.left
= rebarRect
.right
- (pRect
->right
- pRect
->left
- margins
.cx
);
1578 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1579 pRect
->left
= pRect
->right
- (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1583 CalculateValidSize(m_Position
, pRect
);
1586 void PopupStartMenu()
1588 if (m_StartMenuPopup
!= NULL
)
1594 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1599 pt
.x
= rcExclude
.left
;
1600 pt
.y
= rcExclude
.top
;
1601 dwFlags
|= MPPF_TOP
;
1604 pt
.x
= rcExclude
.left
;
1605 pt
.y
= rcExclude
.bottom
;
1606 dwFlags
|= MPPF_BOTTOM
;
1609 pt
.x
= rcExclude
.right
;
1610 pt
.y
= rcExclude
.top
;
1611 dwFlags
|= MPPF_RIGHT
;
1614 pt
.x
= rcExclude
.left
;
1615 pt
.y
= rcExclude
.top
;
1616 dwFlags
|= MPPF_LEFT
;
1620 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1622 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1627 void ProcessMouseTracking()
1632 UINT state
= m_AutoHideState
;
1635 GetWindowRect(&rcCurrent
);
1636 over
= PtInRect(&rcCurrent
, pt
);
1638 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1645 if (state
== AUTOHIDE_HIDING
)
1647 TRACE("AutoHide cancelling hide.\n");
1648 m_AutoHideState
= AUTOHIDE_SHOWING
;
1649 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1651 else if (state
== AUTOHIDE_HIDDEN
)
1653 TRACE("AutoHide starting show.\n");
1654 m_AutoHideState
= AUTOHIDE_SHOWING
;
1655 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1660 if (state
== AUTOHIDE_SHOWING
)
1662 TRACE("AutoHide cancelling show.\n");
1663 m_AutoHideState
= AUTOHIDE_HIDING
;
1664 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1666 else if (state
== AUTOHIDE_SHOWN
)
1668 TRACE("AutoHide starting hide.\n");
1669 m_AutoHideState
= AUTOHIDE_HIDING
;
1670 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1673 KillTimer(TIMER_ID_MOUSETRACK
);
1677 void ProcessAutoHide()
1679 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1680 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1682 switch (m_AutoHideState
)
1684 case AUTOHIDE_HIDING
:
1688 m_AutoHideOffset
.cy
= 0;
1689 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1690 if (m_AutoHideOffset
.cx
< -w
)
1691 m_AutoHideOffset
.cx
= -w
;
1694 m_AutoHideOffset
.cx
= 0;
1695 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1696 if (m_AutoHideOffset
.cy
< -h
)
1697 m_AutoHideOffset
.cy
= -h
;
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
;
1713 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1715 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1720 case AUTOHIDE_HIDDEN
:
1725 m_AutoHideOffset
.cx
= -w
;
1726 m_AutoHideOffset
.cy
= 0;
1729 m_AutoHideOffset
.cx
= 0;
1730 m_AutoHideOffset
.cy
= -h
;
1733 m_AutoHideOffset
.cx
= w
;
1734 m_AutoHideOffset
.cy
= 0;
1737 m_AutoHideOffset
.cx
= 0;
1738 m_AutoHideOffset
.cy
= h
;
1742 KillTimer(TIMER_ID_AUTOHIDE
);
1743 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1746 case AUTOHIDE_SHOWING
:
1747 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1749 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1751 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1753 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1757 m_AutoHideOffset
.cx
= 0;
1760 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1762 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1764 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1766 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1770 m_AutoHideOffset
.cy
= 0;
1773 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1775 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1780 case AUTOHIDE_SHOWN
:
1782 KillTimer(TIMER_ID_AUTOHIDE
);
1783 m_AutoHideState
= AUTOHIDE_SHOWN
;
1787 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOZORDER
);
1794 /**********************************************************
1795 * ##### taskbar drawing #####
1798 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1801 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1803 ASSERT(m_Position
<= ABE_BOTTOM
);
1807 GetClientRect(&rect
);
1808 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1814 int DrawSizerWithTheme(IN HRGN hRgn
)
1818 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1821 ASSERT(m_Position
<= ABE_BOTTOM
);
1823 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
1824 if (FAILED_UNEXPECTEDLY(hr
))
1827 GetWindowRect(&rect
);
1828 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1830 hdc
= GetWindowDC();
1835 rect
.left
= rect
.right
- size
.cx
;
1838 rect
.top
= rect
.bottom
- size
.cy
;
1841 rect
.right
= rect
.left
+ size
.cx
;
1845 rect
.bottom
= rect
.top
+ size
.cy
;
1849 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
1862 HRESULT STDMETHODCALLTYPE
Open()
1866 /* Check if there's already a window created and try to show it.
1867 If it was somehow destroyed just create a new tray window. */
1868 if (m_hWnd
!= NULL
&& IsWindow())
1873 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1874 if (g_TaskbarSettings
.sr
.AlwaysOnTop
)
1875 dwExStyle
|= WS_EX_TOPMOST
;
1877 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1880 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1883 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1884 if (m_Position
!= (DWORD
) -1)
1885 rcWnd
= m_TrayRects
[m_Position
];
1887 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1890 /* Align all controls on the tray window */
1891 AlignControls(NULL
);
1893 /* Move the tray window to the right position and resize it if necessary */
1894 CheckTrayWndPosition();
1899 HRESULT STDMETHODCALLTYPE
Close()
1912 HWND STDMETHODCALLTYPE
GetHWND()
1917 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1919 return (m_hWnd
== hWnd
||
1920 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1923 BOOL STDMETHODCALLTYPE
IsHorizontal()
1925 return IsPosHorizontal();
1928 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1930 BOOL bPrevLock
= g_TaskbarSettings
.bLock
;
1932 if (g_TaskbarSettings
.bLock
!= bLock
)
1934 g_TaskbarSettings
.bLock
= bLock
;
1936 if (m_TrayBandSite
!= NULL
)
1938 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1941 g_TaskbarSettings
.bLock
= bPrevLock
;
1948 /* Update cached tray sizes */
1949 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1951 RECT rcGripper
= {0};
1952 AdjustSizerRect(&rcGripper
, Pos
);
1954 if(g_TaskbarSettings
.bLock
)
1956 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
1957 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
1958 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
1959 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
1963 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
1964 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
1965 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
1966 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
1970 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1972 ApplyClipping(TRUE
);
1982 HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup
,
1990 HRESULT hr
= TrayWindowCtxMenuCreator(this, m_hWnd
, &m_ContextMenu
);
1991 if (FAILED_UNEXPECTEDLY(hr
))
1995 return m_ContextMenu
->QueryContextMenu(hPopup
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
1998 HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2001 return E_INVALIDARG
;
2003 return m_ContextMenu
->InvokeCommand(lpici
);
2006 HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd
,
2013 return E_INVALIDARG
;
2015 return m_ContextMenu
->GetCommandString(idCmd
, uType
, pwReserved
, pszName
, cchMax
);
2019 /**********************************************************
2020 * ##### message handling #####
2023 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2027 ((ITrayWindow
*)this)->AddRef();
2029 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2031 /* Create the Start button */
2032 m_StartButton
.Create(m_hWnd
);
2034 /* Load the saved tray window settings */
2037 /* Create and initialize the start menu */
2038 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2039 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2041 /* Create the task band */
2042 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2043 if (FAILED_UNEXPECTEDLY(hRet
))
2046 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2047 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2048 if (FAILED_UNEXPECTEDLY(hRet
))
2051 /* Get the hwnd of the rebar */
2052 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2053 if (FAILED_UNEXPECTEDLY(hRet
))
2056 /* Get the hwnd of the tasks toolbar */
2057 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2058 if (FAILED_UNEXPECTEDLY(hRet
))
2061 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2063 /* Create the tray notification window */
2064 m_TrayNotify
= CreateTrayNotifyWnd(m_hWnd
, &m_TrayNotifyInstance
);
2068 InitShellServices(&m_ShellServices
);
2070 if (g_TaskbarSettings
.sr
.AutoHide
)
2072 m_AutoHideState
= AUTOHIDE_HIDING
;
2073 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2076 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2077 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2078 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2079 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2080 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2081 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2082 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2083 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2084 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2085 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2086 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2087 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2092 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2095 CloseThemeData(m_Theme
);
2097 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2101 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2105 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2107 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2112 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2114 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2116 SendMessage(m_TrayNotify
, uMsg
, wParam
, lParam
);
2117 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2119 AlignControls(NULL
);
2120 CheckTrayWndPosition();
2126 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2128 HDC hdc
= (HDC
) wParam
;
2136 return EraseBackgroundWithTheme(hdc
);
2139 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2141 /* Load the saved tray window settings */
2144 /* Move the tray window to the right position and resize it if necessary */
2145 CheckTrayWndPosition();
2150 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2153 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2157 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2165 return DrawSizerWithTheme((HRGN
) wParam
);
2168 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2170 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2171 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2174 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2179 if (g_TaskbarSettings
.bLock
)
2181 /* The user may not be able to resize the tray window.
2182 Pretend like the window is not sizeable when the user
2183 clicks on the border. */
2187 SetLastError(ERROR_SUCCESS
);
2188 if (GetClientRect(&rcClient
) &&
2189 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2191 pt
.x
= (SHORT
) LOWORD(lParam
);
2192 pt
.y
= (SHORT
) HIWORD(lParam
);
2194 if (PtInRect(&rcClient
,
2197 /* The user is trying to drag the tray window */
2201 /* Depending on the position of the tray window, allow only
2202 changing the border next to the monitor working area */
2206 if (pt
.y
> rcClient
.bottom
)
2210 if (pt
.x
> rcClient
.right
)
2214 if (pt
.x
< rcClient
.left
)
2219 if (pt
.y
< rcClient
.top
)
2228 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2231 PRECT pRect
= (PRECT
) lParam
;
2233 /* We need to ensure that an application can not accidently
2234 move the tray window (using SetWindowPos). However, we still
2235 need to be able to move the window in case the user wants to
2236 drag the tray window to another position or in case the user
2237 wants to resize the tray window. */
2238 if (!g_TaskbarSettings
.bLock
&& GetCursorPos(&ptCursor
))
2241 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2245 *pRect
= m_TrayRects
[m_Position
];
2250 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2252 PRECT pRect
= (PRECT
) lParam
;
2254 if (!g_TaskbarSettings
.bLock
)
2260 *pRect
= m_TrayRects
[m_Position
];
2265 LRESULT
OnWindowPosChanging(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2267 ChangingWinPos((LPWINDOWPOS
) lParam
);
2271 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2274 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2277 /* Clip the tray window on multi monitor systems so the edges can't
2278 overlap into another monitor */
2279 ApplyClipping(TRUE
);
2281 if (!GetClientRect(&rcClient
))
2288 rcClient
.left
= rcClient
.top
= 0;
2289 rcClient
.right
= LOWORD(lParam
);
2290 rcClient
.bottom
= HIWORD(lParam
);
2293 AlignControls(&rcClient
);
2297 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2301 if (!g_TaskbarSettings
.bLock
)
2303 /* Remove the clipping on multi monitor systems while dragging around */
2304 ApplyClipping(FALSE
);
2309 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2312 if (!g_TaskbarSettings
.bLock
)
2314 FitToRebar(&m_TrayRects
[m_Position
]);
2316 /* Apply clipping */
2317 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2322 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2328 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2329 The tray window needs to handle this specially, since it normally doesn't have
2332 static const UINT uidDisableItem
[] = {
2342 /* temporarily enable the system menu */
2343 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2345 hSysMenu
= GetSystemMenu(FALSE
);
2346 if (hSysMenu
!= NULL
)
2348 /* Disable all items that are not relevant */
2349 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2351 EnableMenuItem(hSysMenu
,
2353 MF_BYCOMMAND
| MF_GRAYED
);
2356 EnableMenuItem(hSysMenu
,
2359 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2361 /* Display the system menu */
2365 m_StartButton
.m_hWnd
,
2366 m_Position
!= ABE_TOP
,
2370 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2374 /* revert the system menu window style */
2375 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2385 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2387 /* This handler implements the trick that makes the start button to
2388 get pressed when the user clicked left or below the button */
2390 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2391 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2396 m_StartButton
.GetWindowRect(&rcStartBtn
);
2397 GetWindowInfo(m_hWnd
, &wi
);
2404 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2410 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2413 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2414 pt
.x
> rcStartBtn
.right
)
2422 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2427 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2428 pt
.y
> rcStartBtn
.bottom
)
2442 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2444 /* We want the user to be able to get a context menu even on the nonclient
2445 area (including the sizing border)! */
2446 uMsg
= WM_CONTEXTMENU
;
2447 wParam
= (WPARAM
) m_hWnd
;
2449 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2452 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2454 LRESULT Ret
= FALSE
;
2455 POINT pt
, *ppt
= NULL
;
2456 HWND hWndExclude
= NULL
;
2458 /* Check if the administrator has forbidden access to context menus */
2459 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2462 pt
.x
= (SHORT
) LOWORD(lParam
);
2463 pt
.y
= (SHORT
) HIWORD(lParam
);
2465 if (pt
.x
!= -1 || pt
.y
!= -1)
2468 hWndExclude
= m_StartButton
.m_hWnd
;
2470 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2472 /* Make sure we can't track the context menu if the start
2473 menu is currently being shown */
2474 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2476 CComPtr
<IContextMenu
> ctxMenu
;
2477 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2478 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2483 /* See if the context menu should be handled by the task band site */
2484 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2487 POINT ptClient
= *ppt
;
2489 /* Convert the coordinates to client-coordinates */
2490 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2492 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2493 if (hWndAtPt
!= NULL
&&
2494 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2496 /* Check if the user clicked on the task switch window */
2498 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2500 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2501 if (hWndAtPt
== m_TaskSwitch
)
2502 goto HandleTrayContextMenu
;
2504 /* Forward the message to the task band site */
2505 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2508 goto HandleTrayContextMenu
;
2512 HandleTrayContextMenu
:
2513 /* Tray the default tray window context menu */
2514 TrackCtxMenu(this, ppt
, NULL
, FALSE
, this);
2520 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2522 LRESULT Ret
= FALSE
;
2523 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2524 the rebar control! But we shouldn't forward messages that the band
2525 site doesn't handle, such as other controls (start button, tray window */
2527 HRESULT hr
= E_FAIL
;
2531 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2536 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2538 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2540 if (nmh
->hwndFrom
== m_TrayNotify
)
2545 /* Cause all controls to be aligned */
2546 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2554 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2556 /* Let the clock handle the double click */
2557 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2559 /* We "handle" this message so users can't cause a weird maximize/restore
2560 window animation when double-clicking the tray window! */
2564 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2570 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2573 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2574 if (FAILED_UNEXPECTEDLY(hr
))
2577 if (::IsWindowVisible(hwndStartMenu
))
2579 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2589 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2592 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2593 * to show the shutdown dialog. Also a WM_CLOSE message sent
2594 * by apps should show the dialog.
2596 return DoExitWindows();
2599 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2601 if (wParam
== SC_CLOSE
)
2603 return DoExitWindows();
2610 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2612 return HandleHotKey(wParam
);
2615 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2617 LRESULT Ret
= FALSE
;
2619 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2624 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2626 return HandleCommand(LOWORD(wParam
));
2631 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2633 if (g_TaskbarSettings
.sr
.AutoHide
)
2635 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2641 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2643 if (wParam
== TIMER_ID_MOUSETRACK
)
2645 ProcessMouseTracking();
2647 else if (wParam
== TIMER_ID_AUTOHIDE
)
2656 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2659 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2660 if(!m_Theme
|| g_TaskbarSettings
.bLock
)
2671 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2672 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2677 rc
= &prms
->rgrc
[0];
2680 AdjustSizerRect(rc
, m_Position
);
2685 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2688 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2694 ::GetWindowRect(m_hWnd
, &rc
);
2698 rc
.bottom
- rc
.top
};
2700 as
->rcTarget
.right
- as
->rcTarget
.left
,
2701 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2703 as
->rcActual
.right
- as
->rcActual
.left
,
2704 as
->rcActual
.bottom
- as
->rcActual
.top
};
2707 szWindow
.cx
- szTarget
.cx
,
2708 szWindow
.cy
- szTarget
.cx
,
2714 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2717 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2720 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2721 rc
.left
= rc
.right
- szWindow
.cy
;
2724 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2725 rc
.top
= rc
.bottom
- szWindow
.cy
;
2729 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2736 LRESULT
OnTaskbarSettingsChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2738 TaskbarSettings
* newSettings
= (TaskbarSettings
*)lParam
;
2740 /* Propagate the new settings to the children */
2741 ::SendMessageW(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2742 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2744 /* Toggle autohide */
2745 if (newSettings
->sr
.AutoHide
!= g_TaskbarSettings
.sr
.AutoHide
)
2747 g_TaskbarSettings
.sr
.AutoHide
= newSettings
->sr
.AutoHide
;
2748 memset(&m_AutoHideOffset
, 0, sizeof(m_AutoHideOffset
));
2749 m_AutoHideState
= AUTOHIDE_SHOWN
;
2750 if (!newSettings
->sr
.AutoHide
)
2751 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOZORDER
);
2753 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2756 /* Toggle lock state */
2757 Lock(newSettings
->bLock
);
2759 /* Toggle OnTop state */
2760 if (newSettings
->sr
.AlwaysOnTop
!= g_TaskbarSettings
.sr
.AlwaysOnTop
)
2762 g_TaskbarSettings
.sr
.AlwaysOnTop
= newSettings
->sr
.AlwaysOnTop
;
2763 HWND hWndInsertAfter
= newSettings
->sr
.AlwaysOnTop
? HWND_TOPMOST
: HWND_BOTTOM
;
2764 SetWindowPos(hWndInsertAfter
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_SHOWWINDOW
);
2767 g_TaskbarSettings
.Save();
2771 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2773 BEGIN_MSG_MAP(CTrayWindow
)
2774 if (m_StartMenuBand
!= NULL
)
2781 Msg
.wParam
= wParam
;
2782 Msg
.lParam
= lParam
;
2784 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2789 wParam
= Msg
.wParam
;
2790 lParam
= Msg
.lParam
;
2792 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2793 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2794 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2795 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2796 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2797 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2798 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2799 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2800 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2801 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2802 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2803 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2804 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2805 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2806 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2807 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2808 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2809 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2810 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2811 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChanging
)
2812 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2813 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2814 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
2815 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2816 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2817 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2818 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2819 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2820 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2821 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2822 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2823 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2824 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2825 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2826 MESSAGE_HANDLER(TWM_SETTINGSCHANGED
, OnTaskbarSettingsChanged
)
2830 /*****************************************************************************/
2832 VOID
TrayProcessMessages()
2836 /* FIXME: We should keep a reference here... */
2838 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2840 if (Msg
.message
== WM_QUIT
)
2843 if (m_StartMenuBand
== NULL
||
2844 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2846 TranslateMessage(&Msg
);
2847 DispatchMessage(&Msg
);
2852 VOID
TrayMessageLoop()
2857 /* FIXME: We should keep a reference here... */
2861 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2863 if (!Ret
|| Ret
== -1)
2866 if (m_StartMenuBand
== NULL
||
2867 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2869 TranslateMessage(&Msg
);
2870 DispatchMessage(&Msg
);
2878 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2879 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2880 * The reason we implement it is because we have to use SHCreateDesktop() so
2881 * that the shell provides the desktop window and all the features that come
2882 * with it (especially positioning of desktop icons)
2885 virtual ULONG STDMETHODCALLTYPE
GetState()
2887 /* FIXME: Return ABS_ flags? */
2888 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2892 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2894 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2895 *phWndTray
= m_hWnd
;
2899 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2901 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2903 m_DesktopWnd
= hWndDesktop
;
2907 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2909 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2913 virtual HRESULT
RaiseStartButton()
2915 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2919 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
2922 return E_INVALIDARG
;
2927 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
2934 m_Position
= (DWORD
) -1;
2937 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2939 DECLARE_PROTECT_FINAL_CONSTRUCT()
2940 BEGIN_COM_MAP(CTrayWindow
)
2941 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2942 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2943 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
2944 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
2948 class CTrayWindowCtxMenu
:
2949 public CComCoClass
<CTrayWindowCtxMenu
>,
2950 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2954 CComPtr
<CTrayWindow
> TrayWnd
;
2955 CComPtr
<IContextMenu
> pcm
;
2956 UINT m_idCmdCmFirst
;
2959 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2961 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2962 this->hWndOwner
= hWndOwner
;
2963 this->m_idCmdCmFirst
= 0;
2967 virtual HRESULT STDMETHODCALLTYPE
2968 QueryContextMenu(HMENU hPopup
,
2974 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
2976 return HRESULT_FROM_WIN32(GetLastError());
2978 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2985 CheckMenuItem(hPopup
,
2987 MF_BYCOMMAND
| (g_TaskbarSettings
.bLock
? MF_CHECKED
: MF_UNCHECKED
));
2990 idCmdNext
= Shell_MergeMenus(hPopup
, menubase
, indexMenu
, idCmdFirst
, idCmdLast
, MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
2991 m_idCmdCmFirst
= idCmdNext
- idCmdFirst
;
2993 ::DestroyMenu(menubase
);
2995 if (TrayWnd
->m_TrayBandSite
!= NULL
)
2997 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3005 WARN("AddContextMenus failed.\n");
3013 virtual HRESULT STDMETHODCALLTYPE
3014 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3016 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3019 if (uiCmdId
>= m_idCmdCmFirst
)
3021 CMINVOKECOMMANDINFO cmici
= { 0 };
3025 /* Setup and invoke the shell command */
3026 cmici
.cbSize
= sizeof(cmici
);
3027 cmici
.hwnd
= hWndOwner
;
3028 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- m_idCmdCmFirst
);
3029 cmici
.nShow
= SW_NORMAL
;
3031 pcm
->InvokeCommand(&cmici
);
3036 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3043 virtual HRESULT STDMETHODCALLTYPE
3044 GetCommandString(UINT_PTR idCmd
,
3053 CTrayWindowCtxMenu()
3057 virtual ~CTrayWindowCtxMenu()
3061 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3062 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3066 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3068 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3069 mnu
->Initialize(TrayWnd
, hWndOwner
);
3074 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3076 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3078 return E_OUTOFMEMORY
;
3083 *ppTray
= (ITrayWindow
*) Tray
;
3089 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3091 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3092 return TrayWindow
->RaiseStartButton();
3095 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3097 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3098 TrayWindow
->TrayProcessMessages();
3101 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3103 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3104 TrayWindow
->TrayMessageLoop();