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 LONG TrayWndCount
= 0;
58 static const WCHAR szTrayWndClass
[] = L
"Shell_TrayWnd";
64 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
69 HIMAGELIST m_ImageList
;
82 virtual ~CStartButton()
84 if (m_ImageList
!= NULL
)
85 ImageList_Destroy(m_ImageList
);
101 VOID
UpdateSize(IN HBITMAP hbmStart
= NULL
)
103 SIZE Size
= { 0, 0 };
105 if (m_ImageList
== NULL
||
106 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
108 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
) + GetSystemMetrics(SM_CYCAPTION
) * 3;
109 Size
.cy
= 2 * GetSystemMetrics(SM_CYEDGE
) + GetSystemMetrics(SM_CYCAPTION
);
112 /* Save the size of the start button */
118 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
120 /* Get the system fonts, we use the caption font, always bold, though. */
121 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
122 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
124 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
125 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
128 SetFont(m_Font
, FALSE
);
130 m_ImageList
= ImageList_LoadImageW(hExplorerInstance
,
131 MAKEINTRESOURCEW(IDB_START
),
134 LR_LOADTRANSPARENT
| LR_CREATEDIBSECTION
);
136 BUTTON_IMAGELIST bil
= {m_ImageList
, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT
};
137 SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
);
141 HWND
Create(HWND hwndParent
)
143 WCHAR szStartCaption
[32];
144 if (!LoadStringW(hExplorerInstance
,
147 _countof(szStartCaption
)))
149 wcscpy(szStartCaption
, L
"Start");
152 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| BS_PUSHBUTTON
| BS_LEFT
| BS_VCENTER
;
154 m_hWnd
= CreateWindowEx(
161 (HMENU
) IDC_STARTBTN
,
173 public CComCoClass
<CTrayWindow
>,
174 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
175 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
177 public IShellDesktopTray
179 CStartButton m_StartButton
;
181 CComPtr
<IMenuBand
> m_StartMenuBand
;
182 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
194 CTrayNotifyWnd
* m_TrayNotifyInstance
;
198 HMONITOR m_PreviousMonitor
;
199 DWORD m_DraggingPosition
;
200 HMONITOR m_DraggingMonitor
;
205 HWND m_TrayPropertiesOwner
;
206 HWND m_RunFileDlgOwner
;
208 UINT m_AutoHideState
;
209 SIZE m_AutoHideOffset
;
210 TRACKMOUSEEVENT m_MouseTrackingInfo
;
212 HDPA m_ShellServices
;
215 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
223 DWORD AlwaysOnTop
: 1;
224 DWORD SmSmallIcons
: 1;
229 DWORD InSizeMove
: 1;
230 DWORD IsDragging
: 1;
231 DWORD NewPosSize
: 1;
247 m_PreviousMonitor(NULL
),
248 m_DraggingPosition(0),
249 m_DraggingMonitor(NULL
),
250 m_TrayPropertiesOwner(NULL
),
251 m_RunFileDlgOwner(NULL
),
252 m_AutoHideState(NULL
),
253 m_ShellServices(NULL
),
256 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
257 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
258 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
259 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
262 virtual ~CTrayWindow()
264 if (m_ShellServices
!= NULL
)
266 ShutdownShellServices(m_ShellServices
);
267 m_ShellServices
= NULL
;
270 if (m_CaptionFont
!= NULL
)
272 DeleteObject(m_CaptionFont
);
273 m_CaptionFont
= NULL
;
278 DeleteObject(m_Font
);
284 CloseThemeData(m_Theme
);
288 if (InterlockedDecrement(&TrayWndCount
) == 0)
296 /**********************************************************
297 * ##### command handling #####
300 HRESULT
ExecResourceCmd(int id
)
302 WCHAR szCommand
[256];
303 WCHAR
*pszParameters
;
305 if (!LoadStringW(hExplorerInstance
,
308 _countof(szCommand
)))
313 pszParameters
= wcschr(szCommand
, L
'>');
320 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
324 LRESULT
DoExitWindows()
326 ExitWindowsDialog(m_hWnd
);
330 DWORD WINAPI
RunFileDlgThread()
335 m_StartButton
.GetWindowRect(&posRect
);
337 hwnd
= CreateWindowEx(0,
340 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
343 posRect
.right
- posRect
.left
,
344 posRect
.bottom
- posRect
.top
,
350 m_RunFileDlgOwner
= hwnd
;
352 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
354 m_RunFileDlgOwner
= NULL
;
355 ::DestroyWindow(hwnd
);
360 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
362 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
363 return This
->RunFileDlgThread();
366 void DisplayRunFileDlg()
369 if (m_RunFileDlgOwner
)
371 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
372 if (hRunDlg
!= NULL
&&
373 hRunDlg
!= m_RunFileDlgOwner
)
375 SetForegroundWindow(hRunDlg
);
380 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
383 DWORD WINAPI
TrayPropertiesThread()
388 m_StartButton
.GetWindowRect(&posRect
);
389 hwnd
= CreateWindowEx(0,
392 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
395 posRect
.right
- posRect
.left
,
396 posRect
.bottom
- posRect
.top
,
402 m_TrayPropertiesOwner
= hwnd
;
404 DisplayTrayProperties(hwnd
);
406 m_TrayPropertiesOwner
= NULL
;
407 ::DestroyWindow(hwnd
);
412 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
414 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
416 return This
->TrayPropertiesThread();
419 HWND STDMETHODCALLTYPE
DisplayProperties()
423 if (m_TrayPropertiesOwner
)
425 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
426 if (hTrayProp
!= NULL
&&
427 hTrayProp
!= m_TrayPropertiesOwner
)
429 SetForegroundWindow(hTrayProp
);
434 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
438 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
440 WCHAR szDir
[MAX_PATH
];
442 if (SHGetSpecialFolderPath(hWndOwner
,
444 CSIDL_COMMON_STARTMENU
,
447 ShellExecute(hWndOwner
,
456 VOID
OpenTaskManager(IN HWND hWndOwner
)
458 ShellExecute(hWndOwner
,
466 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
470 case ID_SHELL_CMD_PROPERTIES
:
474 case ID_SHELL_CMD_OPEN_ALL_USERS
:
475 OpenCommonStartMenuDirectory(m_hWnd
,
479 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
480 OpenCommonStartMenuDirectory(m_hWnd
,
485 if (SHRestricted(REST_CLASSICSHELL
) == 0)
491 case ID_SHELL_CMD_OPEN_TASKMGR
:
492 OpenTaskManager(m_hWnd
);
495 case ID_SHELL_CMD_UNDO_ACTION
:
498 case ID_SHELL_CMD_SHOW_DESKTOP
:
501 case ID_SHELL_CMD_TILE_WND_H
:
502 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
505 case ID_SHELL_CMD_TILE_WND_V
:
506 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
509 case ID_SHELL_CMD_CASCADE_WND
:
510 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
513 case ID_SHELL_CMD_CUST_NOTIF
:
514 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
517 case ID_SHELL_CMD_ADJUST_DAT
:
518 //FIXME: Use SHRunControlPanel
519 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
523 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
530 LRESULT
HandleHotKey(DWORD id
)
538 ExecResourceCmd(IDS_HELP_COMMAND
);
541 //FIXME: We don't support this yet:
542 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
543 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
546 SHFindFiles(NULL
, NULL
);
548 case IDHK_FIND_COMPUTER
:
549 SHFindComputer(NULL
, NULL
);
551 case IDHK_SYS_PROPERTIES
:
552 //FIXME: Use SHRunControlPanel
553 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
559 case IDHK_MINIMIZE_ALL
:
561 case IDHK_RESTORE_ALL
:
572 LRESULT
HandleCommand(UINT uCommand
)
576 case IDM_TASKBARANDSTARTMENU
:
581 SHFindFiles(NULL
, NULL
);
584 case IDM_HELPANDSUPPORT
:
585 ExecResourceCmd(IDS_HELP_COMMAND
);
592 /* FIXME: Handle these commands as well */
593 case IDM_SYNCHRONIZE
:
595 case IDM_UNDOCKCOMPUTER
:
599 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
613 IN POINT
*ppt OPTIONAL
,
614 IN HWND hwndExclude OPTIONAL
,
616 IN BOOL IsContextMenu
)
618 TPMPARAMS tmp
, *ptmp
= NULL
;
623 if (hwndExclude
!= NULL
)
625 /* Get the client rectangle and map it to screen coordinates */
626 if (::GetClientRect(hwndExclude
,
628 ::MapWindowPoints(hwndExclude
,
630 (LPPOINT
) &tmp
.rcExclude
,
640 GetClientRect(&tmp
.rcExclude
) &&
643 (LPPOINT
) &tmp
.rcExclude
,
651 /* NOTE: TrackPopupMenuEx will eventually align the track position
652 for us, no need to take care of it here as long as the
653 coordinates are somewhere within the exclusion rectangle */
654 pt
.x
= ptmp
->rcExclude
.left
;
655 pt
.y
= ptmp
->rcExclude
.top
;
663 tmp
.cbSize
= sizeof(tmp
);
665 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
666 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
668 fuFlags
|= TPM_RIGHTBUTTON
;
670 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
672 cmdId
= TrackPopupMenuEx(hMenu
,
682 HRESULT
TrackCtxMenu(
683 IN IContextMenu
* contextMenu
,
684 IN POINT
*ppt OPTIONAL
,
685 IN HWND hwndExclude OPTIONAL
,
687 IN PVOID Context OPTIONAL
)
693 HMENU popup
= CreatePopupMenu();
698 TRACE("Before Query\n");
699 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
700 if (FAILED_UNEXPECTEDLY(hr
))
702 TRACE("Query failed\n");
707 TRACE("Before Tracking\n");
708 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
712 TRACE("Before InvokeCommand\n");
713 CMINVOKECOMMANDINFO cmi
= { 0 };
714 cmi
.cbSize
= sizeof(cmi
);
715 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
717 hr
= contextMenu
->InvokeCommand(&cmi
);
721 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
733 /**********************************************************
734 * ##### moving and sizing handling #####
737 BOOL
UpdateNonClientMetrics()
739 NONCLIENTMETRICS ncm
;
740 ncm
.cbSize
= sizeof(ncm
);
741 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
744 DeleteObject(m_Font
);
746 m_Font
= CreateFontIndirect(&ncm
.lfMessageFont
);
753 VOID
SetWindowsFont()
755 if (m_TrayNotify
!= NULL
)
757 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
761 HMONITOR
GetScreenRectFromRect(
768 mi
.cbSize
= sizeof(mi
);
769 hMon
= MonitorFromRect(pRect
, dwFlags
);
771 GetMonitorInfo(hMon
, &mi
))
773 *pRect
= mi
.rcMonitor
;
779 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
780 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
788 HMONITOR
GetMonitorFromRect(
789 IN
const RECT
*pRect
)
793 /* In case the monitor sizes or saved sizes differ a bit (probably
794 not a lot, only so the tray window overlaps into another monitor
795 now), minimize the risk that we determine a wrong monitor by
796 using the center point of the tray window if we can't determine
797 it using the rectangle. */
798 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
803 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
804 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
806 /* be less error-prone, find the nearest monitor */
807 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
813 HMONITOR
GetScreenRect(
814 IN HMONITOR hMonitor
,
817 HMONITOR hMon
= NULL
;
819 if (hMonitor
!= NULL
)
823 mi
.cbSize
= sizeof(mi
);
824 if (!GetMonitorInfo(hMonitor
, &mi
))
826 /* Hm, the monitor is gone? Try to find a monitor where it
827 could be located now */
828 hMon
= GetMonitorFromRect(pRect
);
830 !GetMonitorInfo(hMon
, &mi
))
837 *pRect
= mi
.rcMonitor
;
844 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
845 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
851 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
856 rc
->bottom
-= GetSystemMetrics(SM_CXSIZEFRAME
);
859 rc
->top
+= GetSystemMetrics(SM_CXSIZEFRAME
);
862 rc
->right
-= GetSystemMetrics(SM_CYSIZEFRAME
);
865 rc
->left
+= GetSystemMetrics(SM_CYSIZEFRAME
);
871 VOID
MakeTrayRectWithSize(IN DWORD Position
,
872 IN
const SIZE
*pTraySize
,
878 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
882 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
886 pRect
->left
= pRect
->right
- pTraySize
->cx
;
891 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
896 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
897 IN
const RECT
*pScreen
,
898 IN
const SIZE
*pTraySize OPTIONAL
,
901 if (pTraySize
== NULL
)
902 pTraySize
= &m_TraySize
;
908 /* Move the border outside of the screen */
910 GetSystemMetrics(SM_CXEDGE
),
911 GetSystemMetrics(SM_CYEDGE
));
914 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
917 BOOL
IsPosHorizontal()
919 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
922 HMONITOR
CalculateValidSize(
931 //Horizontal = IsPosHorizontal();
933 szWnd
.cx
= pRect
->right
- pRect
->left
;
934 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
937 hMon
= GetScreenRectFromRect(
939 MONITOR_DEFAULTTONEAREST
);
941 /* Calculate the maximum size of the tray window and limit the window
942 size to half of the screen's size. */
943 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
944 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
945 if (szWnd
.cx
> szMax
.cx
)
947 if (szWnd
.cy
> szMax
.cy
)
950 /* FIXME - calculate */
952 GetTrayRectFromScreenRect(Position
,
962 GetMinimumWindowSize(
967 AdjustWindowRectEx(&rcMin
,
968 GetWindowLong(m_hWnd
,
971 GetWindowLong(m_hWnd
,
979 DWORD
GetDraggingRectFromPt(
982 OUT HMONITOR
*phMonitor
)
984 HMONITOR hMon
, hMonNew
;
985 DWORD PosH
, PosV
, Pos
;
986 SIZE DeltaPt
, ScreenOffset
;
992 /* Determine the screen rectangle */
993 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
998 mi
.cbSize
= sizeof(mi
);
999 if (!GetMonitorInfo(hMon
, &mi
))
1002 goto GetPrimaryScreenRect
;
1005 /* make left top corner of the screen zero based to
1006 make calculations easier */
1007 pt
.x
-= mi
.rcMonitor
.left
;
1008 pt
.y
-= mi
.rcMonitor
.top
;
1010 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1011 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1012 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1013 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1017 GetPrimaryScreenRect
:
1018 ScreenOffset
.cx
= 0;
1019 ScreenOffset
.cy
= 0;
1020 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1021 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1024 /* Calculate the nearest screen border */
1025 if (pt
.x
< rcScreen
.right
/ 2)
1032 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1036 if (pt
.y
< rcScreen
.bottom
/ 2)
1043 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1047 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1049 /* Fix the screen origin to be relative to the primary monitor again */
1050 OffsetRect(&rcScreen
,
1054 RECT rcPos
= m_TrayRects
[Pos
];
1056 hMonNew
= GetMonitorFromRect(&rcPos
);
1057 if (hMon
!= hMonNew
)
1061 /* Recalculate the rectangle, we're dragging to another monitor.
1062 We don't need to recalculate the rect on single monitor systems. */
1063 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1064 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1066 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1069 pRect
->left
+= m_AutoHideOffset
.cx
;
1070 pRect
->right
+= m_AutoHideOffset
.cx
;
1071 pRect
->top
+= m_AutoHideOffset
.cy
;
1072 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1078 /* The user is dragging the tray window on the same monitor. We don't need
1079 to recalculate the rectangle */
1083 pRect
->left
+= m_AutoHideOffset
.cx
;
1084 pRect
->right
+= m_AutoHideOffset
.cx
;
1085 pRect
->top
+= m_AutoHideOffset
.cy
;
1086 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1095 DWORD
GetDraggingRectFromRect(
1097 OUT HMONITOR
*phMonitor
)
1101 /* Calculate the center of the rectangle. We call
1102 GetDraggingRectFromPt to calculate a valid
1103 dragging rectangle */
1104 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1105 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1107 return GetDraggingRectFromPt(
1113 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1119 rcTray
.left
= pwp
->x
;
1120 rcTray
.top
= pwp
->y
;
1121 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1122 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1125 rcTray
.left
-= m_AutoHideOffset
.cx
;
1126 rcTray
.right
-= m_AutoHideOffset
.cx
;
1127 rcTray
.top
-= m_AutoHideOffset
.cy
;
1128 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1131 if (!EqualRect(&rcTray
,
1132 &m_TrayRects
[m_DraggingPosition
]))
1134 /* Recalculate the rectangle, the user dragged the tray
1135 window to another monitor or the window was somehow else
1137 m_DraggingPosition
= GetDraggingRectFromRect(
1139 &m_DraggingMonitor
);
1140 //m_TrayRects[DraggingPosition] = rcTray;
1143 //Monitor = CalculateValidSize(DraggingPosition,
1146 m_Monitor
= m_DraggingMonitor
;
1147 m_Position
= m_DraggingPosition
;
1150 m_TrayRects
[m_Position
] = rcTray
;
1153 else if (GetWindowRect(&rcTray
))
1157 if (!(pwp
->flags
& SWP_NOMOVE
))
1159 rcTray
.left
= pwp
->x
;
1160 rcTray
.top
= pwp
->y
;
1163 if (!(pwp
->flags
& SWP_NOSIZE
))
1165 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1166 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1169 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1171 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1178 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1183 rcTray
.left
-= m_AutoHideOffset
.cx
;
1184 rcTray
.right
-= m_AutoHideOffset
.cx
;
1185 rcTray
.top
-= m_AutoHideOffset
.cy
;
1186 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1188 m_TrayRects
[m_Position
] = rcTray
;
1192 /* If the user isn't resizing the tray window we need to make sure the
1193 new size or position is valid. this is to prevent changes to the window
1194 without user interaction. */
1195 rcTray
= m_TrayRects
[m_Position
];
1199 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1200 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1204 rcTray
.left
+= m_AutoHideOffset
.cx
;
1205 rcTray
.right
+= m_AutoHideOffset
.cx
;
1206 rcTray
.top
+= m_AutoHideOffset
.cy
;
1207 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1210 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1211 pwp
->x
= rcTray
.left
;
1212 pwp
->y
= rcTray
.top
;
1213 pwp
->cx
= m_TraySize
.cx
;
1214 pwp
->cy
= m_TraySize
.cy
;
1218 VOID
ApplyClipping(IN BOOL Clip
)
1220 RECT rcClip
, rcWindow
;
1223 if (GetWindowRect(&rcWindow
))
1225 /* Disable clipping on systems with only one monitor */
1226 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1233 GetScreenRect(m_Monitor
, &rcClip
);
1235 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1244 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1249 /* Set the clipping region or make sure the window isn't clipped
1250 by disabling it explicitly. */
1251 SetWindowRgn(hClipRgn
, TRUE
);
1255 VOID
ResizeWorkArea()
1257 #if !WIN7_DEBUG_MODE
1258 RECT rcTray
, rcWorkArea
;
1260 /* If monitor has changed then fix the previous monitors work area */
1261 if (m_PreviousMonitor
!= m_Monitor
)
1263 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1264 SystemParametersInfoW(SPI_SETWORKAREA
,
1270 rcTray
= m_TrayRects
[m_Position
];
1272 GetScreenRect(m_Monitor
, &rcWorkArea
);
1273 m_PreviousMonitor
= m_Monitor
;
1275 /* If AutoHide is false then change the workarea to exclude
1276 the area that the taskbar covers. */
1282 rcWorkArea
.top
= rcTray
.bottom
;
1285 rcWorkArea
.left
= rcTray
.right
;
1288 rcWorkArea
.right
= rcTray
.left
;
1291 rcWorkArea
.bottom
= rcTray
.top
;
1297 * Resize the current monitor work area. Win32k will also send
1298 * a WM_SIZE message to automatically resize the desktop.
1300 SystemParametersInfoW(SPI_SETWORKAREA
,
1307 VOID
CheckTrayWndPosition()
1311 rcTray
= m_TrayRects
[m_Position
];
1315 rcTray
.left
+= m_AutoHideOffset
.cx
;
1316 rcTray
.right
+= m_AutoHideOffset
.cx
;
1317 rcTray
.top
+= m_AutoHideOffset
.cy
;
1318 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1321 /* Move the tray window */
1325 rcTray
.right
- rcTray
.left
,
1326 rcTray
.bottom
- rcTray
.top
,
1327 SWP_NOZORDER
| SWP_NOACTIVATE
);
1331 ApplyClipping(TRUE
);
1334 typedef struct _TW_STUCKRECTS2
1342 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1344 VOID
RegLoadSettings()
1349 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1350 DWORD cbSize
= sizeof(sr
);
1351 SIZE StartBtnSize
= m_StartButton
.GetSize();
1353 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1354 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1355 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1356 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1358 if (SHGetValue(hkExplorer
,
1359 TEXT("StuckRects2"),
1363 &cbSize
) == ERROR_SUCCESS
&&
1364 sr
.cbSize
== sizeof(sr
))
1366 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1367 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1368 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1369 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1371 /* FIXME: Are there more flags? */
1374 m_Position
= ABE_LEFT
;
1376 if (sr
.Position
> ABE_BOTTOM
)
1377 m_Position
= ABE_BOTTOM
;
1379 m_Position
= sr
.Position
;
1382 /* Try to find out which monitor the tray window was located on last.
1383 Here we're only interested in the monitor screen that we think
1384 is the last one used. We're going to determine on which monitor
1385 we really are after calculating the docked position. */
1387 GetScreenRectFromRect(
1389 MONITOR_DEFAULTTONEAREST
);
1393 m_Position
= ABE_BOTTOM
;
1396 /* Use the minimum size of the taskbar, we'll use the start
1397 button as a minimum for now. Make sure we calculate the
1398 entire window size, not just the client size. However, we
1399 use a thinner border than a standard thick border, so that
1400 the start button and bands are not stuck to the screen border. */
1401 if(!IsThemeActive())
1403 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1404 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1408 sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1409 sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1411 sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1414 /* Use the primary screen by default */
1417 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1418 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1419 GetScreenRectFromRect(
1421 MONITOR_DEFAULTTOPRIMARY
);
1426 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1431 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1433 /* Determine a minimum tray window rectangle. The "client" height is
1434 zero here since we cannot determine an optimal minimum width when
1435 loaded as a vertical tray window. We just need to make sure the values
1436 loaded from the registry are at least. The windows explorer behaves
1437 the same way, it allows the user to save a zero width vertical tray
1438 window, but not a zero height horizontal tray window. */
1439 if(!IsThemeActive())
1441 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1442 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1446 WndSize
.cx
= StartBtnSize
.cx
;
1447 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1450 if (WndSize
.cx
< sr
.Size
.cx
)
1451 WndSize
.cx
= sr
.Size
.cx
;
1452 if (WndSize
.cy
< sr
.Size
.cy
)
1453 WndSize
.cy
= sr
.Size
.cy
;
1455 /* Save the calculated size */
1456 m_TraySize
= WndSize
;
1458 /* Calculate all docking rectangles. We need to do this here so they're
1459 initialized and dragging the tray window to another position gives
1461 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1463 GetTrayRectFromScreenRect(Pos
,
1467 // 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);
1470 /* Determine which monitor we are on. It shouldn't matter which docked
1471 position rectangle we use */
1472 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1475 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1478 SIZE TraySize
, StartSize
;
1479 POINT ptTrayNotify
= { 0, 0 };
1483 m_StartButton
.UpdateSize();
1484 if (prcClient
!= NULL
)
1486 rcClient
= *prcClient
;
1490 if (!GetClientRect(&rcClient
))
1492 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1497 Horizontal
= IsPosHorizontal();
1499 /* We're about to resize/move the start button, the rebar control and
1500 the tray notification control */
1501 dwp
= BeginDeferWindowPos(3);
1504 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1508 /* Limit the Start button width to the client width, if necessary */
1509 StartSize
= m_StartButton
.GetSize();
1510 if (StartSize
.cx
> rcClient
.right
)
1511 StartSize
.cx
= rcClient
.right
;
1513 if (m_StartButton
.m_hWnd
!= NULL
)
1515 /* Resize and reposition the button */
1516 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1522 SWP_NOZORDER
| SWP_NOACTIVATE
);
1525 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1530 /* Determine the size that the tray notification window needs */
1534 TraySize
.cy
= rcClient
.bottom
;
1538 TraySize
.cx
= rcClient
.right
;
1542 if (m_TrayNotify
!= NULL
&&
1543 SendMessage(m_TrayNotify
,
1544 TNWM_GETMINIMUMSIZE
,
1548 /* Move the tray notification window to the desired location */
1550 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1552 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1554 dwp
= ::DeferWindowPos(dwp
,
1561 SWP_NOZORDER
| SWP_NOACTIVATE
);
1564 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1569 /* Resize/Move the rebar control */
1570 if (m_Rebar
!= NULL
)
1572 POINT ptRebar
= { 0, 0 };
1575 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1579 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1580 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1581 szRebar
.cy
= rcClient
.bottom
;
1585 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1586 szRebar
.cx
= rcClient
.right
;
1587 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1590 dwp
= ::DeferWindowPos(dwp
,
1597 SWP_NOZORDER
| SWP_NOACTIVATE
);
1601 EndDeferWindowPos(dwp
);
1603 if (m_TaskSwitch
!= NULL
)
1605 /* Update the task switch window configuration */
1606 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1610 void PopupStartMenu()
1612 if (m_StartMenuPopup
!= NULL
)
1618 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1623 pt
.x
= rcExclude
.left
;
1624 pt
.y
= rcExclude
.top
;
1625 dwFlags
|= MPPF_TOP
;
1628 pt
.x
= rcExclude
.left
;
1629 pt
.y
= rcExclude
.bottom
;
1630 dwFlags
|= MPPF_BOTTOM
;
1633 pt
.x
= rcExclude
.right
;
1634 pt
.y
= rcExclude
.top
;
1635 dwFlags
|= MPPF_RIGHT
;
1638 pt
.x
= rcExclude
.left
;
1639 pt
.y
= rcExclude
.top
;
1640 dwFlags
|= MPPF_LEFT
;
1644 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1646 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1651 void ProcessMouseTracking()
1656 UINT state
= m_AutoHideState
;
1659 GetWindowRect(&rcCurrent
);
1660 over
= PtInRect(&rcCurrent
, pt
);
1662 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1669 if (state
== AUTOHIDE_HIDING
)
1671 TRACE("AutoHide cancelling hide.\n");
1672 m_AutoHideState
= AUTOHIDE_SHOWING
;
1673 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1675 else if (state
== AUTOHIDE_HIDDEN
)
1677 TRACE("AutoHide starting show.\n");
1678 m_AutoHideState
= AUTOHIDE_SHOWING
;
1679 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1684 if (state
== AUTOHIDE_SHOWING
)
1686 TRACE("AutoHide cancelling show.\n");
1687 m_AutoHideState
= AUTOHIDE_HIDING
;
1688 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1690 else if (state
== AUTOHIDE_SHOWN
)
1692 TRACE("AutoHide starting hide.\n");
1693 m_AutoHideState
= AUTOHIDE_HIDING
;
1694 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1697 KillTimer(TIMER_ID_MOUSETRACK
);
1701 void ProcessAutoHide()
1703 RECT rc
= m_TrayRects
[m_Position
];
1704 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1705 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1707 TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", m_AutoHideState
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, w
, h
);
1709 switch (m_AutoHideState
)
1711 case AUTOHIDE_HIDING
:
1715 m_AutoHideOffset
.cy
= 0;
1716 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1717 if (m_AutoHideOffset
.cx
< -w
)
1718 m_AutoHideOffset
.cx
= -w
;
1721 m_AutoHideOffset
.cx
= 0;
1722 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1723 if (m_AutoHideOffset
.cy
< -h
)
1724 m_AutoHideOffset
.cy
= -h
;
1727 m_AutoHideOffset
.cy
= 0;
1728 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1729 if (m_AutoHideOffset
.cx
> w
)
1730 m_AutoHideOffset
.cx
= w
;
1733 m_AutoHideOffset
.cx
= 0;
1734 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1735 if (m_AutoHideOffset
.cy
> h
)
1736 m_AutoHideOffset
.cy
= h
;
1740 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1742 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1747 case AUTOHIDE_HIDDEN
:
1752 m_AutoHideOffset
.cx
= -w
;
1753 m_AutoHideOffset
.cy
= 0;
1756 m_AutoHideOffset
.cx
= 0;
1757 m_AutoHideOffset
.cy
= -h
;
1760 m_AutoHideOffset
.cx
= w
;
1761 m_AutoHideOffset
.cy
= 0;
1764 m_AutoHideOffset
.cx
= 0;
1765 m_AutoHideOffset
.cy
= h
;
1769 KillTimer(TIMER_ID_AUTOHIDE
);
1770 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1773 case AUTOHIDE_SHOWING
:
1774 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1776 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1778 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1780 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1784 m_AutoHideOffset
.cx
= 0;
1787 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1789 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1791 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1793 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1797 m_AutoHideOffset
.cy
= 0;
1800 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1802 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1807 case AUTOHIDE_SHOWN
:
1809 KillTimer(TIMER_ID_AUTOHIDE
);
1810 m_AutoHideState
= AUTOHIDE_SHOWN
;
1814 rc
.left
+= m_AutoHideOffset
.cx
;
1815 rc
.right
+= m_AutoHideOffset
.cx
;
1816 rc
.top
+= m_AutoHideOffset
.cy
;
1817 rc
.bottom
+= m_AutoHideOffset
.cy
;
1819 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1820 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1827 /**********************************************************
1828 * ##### taskbar drawing #####
1831 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1837 GetClientRect(&rect
);
1841 GetClientRect(&rect
);
1845 partId
= TBP_BACKGROUNDLEFT
;
1848 partId
= TBP_BACKGROUNDTOP
;
1851 partId
= TBP_BACKGROUNDRIGHT
;
1855 partId
= TBP_BACKGROUNDBOTTOM
;
1858 res
= DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1864 int DrawSizerWithTheme(IN HRGN hRgn
)
1870 GetWindowRect(&rect
);
1871 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1873 hdc
= GetWindowDC();
1878 backgroundPart
= TBP_SIZINGBARLEFT
;
1879 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1882 backgroundPart
= TBP_SIZINGBARTOP
;
1883 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1886 backgroundPart
= TBP_SIZINGBARRIGHT
;
1887 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1891 backgroundPart
= TBP_SIZINGBARBOTTOM
;
1892 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1895 if (IsThemeBackgroundPartiallyTransparent(m_Theme
, backgroundPart
, 0))
1897 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1899 DrawThemeBackground(m_Theme
, hdc
, backgroundPart
, 0, &rect
, 0);
1912 HRESULT STDMETHODCALLTYPE
Open()
1916 /* Check if there's already a window created and try to show it.
1917 If it was somehow destroyed just create a new tray window. */
1918 if (m_hWnd
!= NULL
&& IsWindow())
1920 if (!IsWindowVisible())
1922 CheckTrayWndPosition();
1924 ShowWindow(SW_SHOW
);
1930 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1932 dwExStyle
|= WS_EX_TOPMOST
;
1934 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1935 if(!IsThemeActive())
1937 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1940 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1941 if (m_Position
!= (DWORD
) -1)
1942 rcWnd
= m_TrayRects
[m_Position
];
1944 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1950 HRESULT STDMETHODCALLTYPE
Close()
1963 HWND STDMETHODCALLTYPE
GetHWND()
1968 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1970 return (m_hWnd
== hWnd
||
1971 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1974 BOOL STDMETHODCALLTYPE
IsHorizontal()
1976 return IsPosHorizontal();
1979 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1981 if (phBoldCaption
!= NULL
)
1982 *phBoldCaption
= m_StartButton
.GetFont();
1984 return m_CaptionFont
;
1987 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1989 BOOL bPrevLock
= Locked
;
1991 if (Locked
!= bLock
)
1995 if (m_TrayBandSite
!= NULL
)
1997 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2007 /* Update cached tray sizes */
2008 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2010 RECT rcGripper
= {0};
2011 AdjustSizerRect(&rcGripper
, Pos
);
2015 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2016 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2017 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2018 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2022 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2023 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2024 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2025 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2029 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2040 /**********************************************************
2041 * ##### message handling #####
2044 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2046 ((ITrayWindow
*)this)->AddRef();
2048 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2050 InterlockedIncrement(&TrayWndCount
);
2052 if (m_CaptionFont
== NULL
)
2054 NONCLIENTMETRICS ncm
;
2056 /* Get the system fonts, we use the caption font,
2057 always bold, though. */
2058 ncm
.cbSize
= sizeof(ncm
);
2059 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
2061 if (m_CaptionFont
== NULL
)
2063 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
2064 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
2069 /* Create the Start button */
2070 m_StartButton
.Create(m_hWnd
);
2072 /* Load the saved tray window settings */
2075 /* Create and initialize the start menu */
2076 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2077 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2079 /* Load the tray band site */
2080 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
2081 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2083 /* Create the tray notification window */
2084 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2086 if (UpdateNonClientMetrics())
2091 /* Move the tray window to the right position and resize it if necessary */
2092 CheckTrayWndPosition();
2094 /* Align all controls on the tray window */
2095 AlignControls(NULL
);
2097 InitShellServices(&m_ShellServices
);
2101 m_AutoHideState
= AUTOHIDE_HIDING
;
2102 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2105 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2106 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2107 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2108 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2109 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2110 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2111 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2112 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2113 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2114 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2115 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2116 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2121 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2124 CloseThemeData(m_Theme
);
2126 if (IsThemeActive())
2127 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2133 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2137 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2139 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2144 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2146 HDC hdc
= (HDC
) wParam
;
2154 return EraseBackgroundWithTheme(hdc
);
2157 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2159 /* Load the saved tray window settings */
2162 /* Move the tray window to the right position and resize it if necessary */
2163 CheckTrayWndPosition();
2165 /* Align all controls on the tray window */
2166 AlignControls(NULL
);
2171 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2175 TRACE("WM_COPYDATA notify message received. Handling...\n");
2176 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2181 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2189 return DrawSizerWithTheme((HRGN
) wParam
);
2192 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2194 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2195 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2198 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2205 /* The user may not be able to resize the tray window.
2206 Pretend like the window is not sizeable when the user
2207 clicks on the border. */
2211 SetLastError(ERROR_SUCCESS
);
2212 if (GetClientRect(&rcClient
) &&
2213 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2215 pt
.x
= (SHORT
) LOWORD(lParam
);
2216 pt
.y
= (SHORT
) HIWORD(lParam
);
2218 if (PtInRect(&rcClient
,
2221 /* The user is trying to drag the tray window */
2225 /* Depending on the position of the tray window, allow only
2226 changing the border next to the monitor working area */
2230 if (pt
.y
> rcClient
.bottom
)
2234 if (pt
.x
> rcClient
.right
)
2238 if (pt
.x
< rcClient
.left
)
2243 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 (!Locked
&& GetCursorPos(&ptCursor
))
2265 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2269 *pRect
= m_TrayRects
[m_Position
];
2273 pRect
->left
+= m_AutoHideOffset
.cx
;
2274 pRect
->right
+= m_AutoHideOffset
.cx
;
2275 pRect
->top
+= m_AutoHideOffset
.cy
;
2276 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2282 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2284 PRECT pRect
= (PRECT
) lParam
;
2288 /* Get the rect of the rebar */
2289 RECT rebarRect
, taskbarRect
;
2290 ::GetWindowRect(m_Rebar
, &rebarRect
);
2291 ::GetWindowRect(m_hWnd
, &taskbarRect
);
2292 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
2294 /* Calculate the difference of size of the taskbar and the rebar */
2296 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
2297 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
2299 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
2303 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
2304 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2305 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
2308 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
2309 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2310 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
2314 /* FIXME: what to do here? */
2318 CalculateValidSize(m_Position
, pRect
);
2322 *pRect
= m_TrayRects
[m_Position
];
2326 pRect
->left
+= m_AutoHideOffset
.cx
;
2327 pRect
->right
+= m_AutoHideOffset
.cx
;
2328 pRect
->top
+= m_AutoHideOffset
.cy
;
2329 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2335 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2337 ChangingWinPos((LPWINDOWPOS
) lParam
);
2341 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2344 InvalidateRect(NULL
, TRUE
);
2345 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2348 /* Clip the tray window on multi monitor systems so the edges can't
2349 overlap into another monitor */
2350 ApplyClipping(TRUE
);
2352 if (!GetClientRect(&rcClient
))
2359 rcClient
.left
= rcClient
.top
= 0;
2360 rcClient
.right
= LOWORD(lParam
);
2361 rcClient
.bottom
= HIWORD(lParam
);
2364 AlignControls(&rcClient
);
2368 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2374 /* Remove the clipping on multi monitor systems while dragging around */
2375 ApplyClipping(FALSE
);
2380 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2385 /* Apply clipping */
2386 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2391 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2397 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2398 The tray window needs to handle this specially, since it normally doesn't have
2401 static const UINT uidDisableItem
[] = {
2411 /* temporarily enable the system menu */
2412 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2414 hSysMenu
= GetSystemMenu(FALSE
);
2415 if (hSysMenu
!= NULL
)
2417 /* Disable all items that are not relevant */
2418 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2420 EnableMenuItem(hSysMenu
,
2422 MF_BYCOMMAND
| MF_GRAYED
);
2425 EnableMenuItem(hSysMenu
,
2428 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2430 /* Display the system menu */
2434 m_StartButton
.m_hWnd
,
2435 m_Position
!= ABE_TOP
,
2439 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2443 /* revert the system menu window style */
2444 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2454 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2456 /* We want the user to be able to get a context menu even on the nonclient
2457 area (including the sizing border)! */
2458 uMsg
= WM_CONTEXTMENU
;
2459 wParam
= (WPARAM
) m_hWnd
;
2461 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2464 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2466 LRESULT Ret
= FALSE
;
2467 POINT pt
, *ppt
= NULL
;
2468 HWND hWndExclude
= NULL
;
2470 /* Check if the administrator has forbidden access to context menus */
2471 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2474 pt
.x
= (SHORT
) LOWORD(lParam
);
2475 pt
.y
= (SHORT
) HIWORD(lParam
);
2477 if (pt
.x
!= -1 || pt
.y
!= -1)
2480 hWndExclude
= m_StartButton
.m_hWnd
;
2482 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2484 /* Make sure we can't track the context menu if the start
2485 menu is currently being shown */
2486 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2488 CComPtr
<IContextMenu
> ctxMenu
;
2489 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2490 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2495 /* See if the context menu should be handled by the task band site */
2496 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2499 POINT ptClient
= *ppt
;
2501 /* Convert the coordinates to client-coordinates */
2502 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2504 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2505 if (hWndAtPt
!= NULL
&&
2506 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2508 /* Check if the user clicked on the task switch window */
2510 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2512 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2513 if (hWndAtPt
== m_TaskSwitch
)
2514 goto HandleTrayContextMenu
;
2516 /* Forward the message to the task band site */
2517 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2520 goto HandleTrayContextMenu
;
2524 HandleTrayContextMenu
:
2525 /* Tray the default tray window context menu */
2526 CComPtr
<IContextMenu
> ctxMenu
;
2527 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2528 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2534 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2536 LRESULT Ret
= FALSE
;
2537 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2538 the rebar control! But we shouldn't forward messages that the band
2539 site doesn't handle, such as other controls (start button, tray window */
2541 HRESULT hr
= E_FAIL
;
2545 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2550 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2552 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2554 if (nmh
->hwndFrom
== m_TrayNotify
)
2559 /* Cause all controls to be aligned */
2560 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2568 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2570 /* We "handle" this message so users can't cause a weird maximize/restore
2571 window animation when double-clicking the tray window! */
2573 /* We should forward mouse messages to child windows here.
2574 Right now, this is only clock double-click */
2576 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2579 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2580 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2581 if (PtInRect(&rcClock
, ptClick
))
2583 //FIXME: use SHRunControlPanel
2584 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2590 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2596 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2599 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2600 if (FAILED_UNEXPECTEDLY(hr
))
2603 if (::IsWindowVisible(hwndStartMenu
))
2605 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2615 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2618 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2619 * to show the shutdown dialog. Also a WM_CLOSE message sent
2620 * by apps should show the dialog.
2622 return DoExitWindows();
2625 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2627 if (wParam
== SC_CLOSE
)
2629 return DoExitWindows();
2636 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2638 return HandleHotKey(wParam
);
2641 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2643 LRESULT Ret
= FALSE
;
2645 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2651 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2653 return HandleCommand(LOWORD(wParam
));
2658 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2662 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2668 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2670 if (wParam
== TIMER_ID_MOUSETRACK
)
2672 ProcessMouseTracking();
2674 else if (wParam
== TIMER_ID_AUTOHIDE
)
2683 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2686 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2687 if(!IsThemeActive() || Locked
)
2698 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2699 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2704 rc
= &prms
->rgrc
[0];
2707 AdjustSizerRect(rc
, m_Position
);
2712 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2715 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2721 ::GetWindowRect(m_hWnd
, &rc
);
2725 rc
.bottom
- rc
.top
};
2727 as
->rcTarget
.right
- as
->rcTarget
.left
,
2728 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2730 as
->rcActual
.right
- as
->rcActual
.left
,
2731 as
->rcActual
.bottom
- as
->rcActual
.top
};
2734 szWindow
.cx
- szTarget
.cx
,
2735 szWindow
.cy
- szTarget
.cx
,
2741 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2744 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2747 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2748 rc
.left
= rc
.right
- szWindow
.cy
;
2751 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2752 rc
.top
= rc
.bottom
- szWindow
.cy
;
2756 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2763 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2765 BEGIN_MSG_MAP(CTrayWindow
)
2766 if (m_StartMenuBand
!= NULL
)
2773 Msg
.wParam
= wParam
;
2774 Msg
.lParam
= lParam
;
2776 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2781 wParam
= Msg
.wParam
;
2782 lParam
= Msg
.lParam
;
2784 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2785 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2786 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2787 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2788 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2789 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2790 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2791 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2792 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2793 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2794 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2795 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2796 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2797 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2798 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2799 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2800 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2801 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2802 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2803 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2804 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2805 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2806 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2807 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2808 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2809 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2810 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2811 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2812 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2813 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2814 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2815 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2819 /*****************************************************************************/
2821 VOID
TrayProcessMessages()
2825 /* FIXME: We should keep a reference here... */
2827 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2829 if (Msg
.message
== WM_QUIT
)
2832 if (m_StartMenuBand
== NULL
||
2833 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2835 TranslateMessage(&Msg
);
2836 DispatchMessage(&Msg
);
2841 VOID
TrayMessageLoop()
2846 /* FIXME: We should keep a reference here... */
2850 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2852 if (!Ret
|| Ret
== -1)
2855 if (m_StartMenuBand
== NULL
||
2856 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2858 TranslateMessage(&Msg
);
2859 DispatchMessage(&Msg
);
2867 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2868 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2869 * The reason we implement it is because we have to use SHCreateDesktop() so
2870 * that the shell provides the desktop window and all the features that come
2871 * with it (especially positioning of desktop icons)
2874 virtual ULONG STDMETHODCALLTYPE
GetState()
2876 /* FIXME: Return ABS_ flags? */
2877 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2881 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2883 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2884 *phWndTray
= m_hWnd
;
2888 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2890 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2892 m_DesktopWnd
= hWndDesktop
;
2896 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2898 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2902 virtual HRESULT
RaiseStartButton()
2904 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2910 m_Position
= (DWORD
) -1;
2913 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2915 DECLARE_PROTECT_FINAL_CONSTRUCT()
2916 BEGIN_COM_MAP(CTrayWindow
)
2917 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2918 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2922 class CTrayWindowCtxMenu
:
2923 public CComCoClass
<CTrayWindowCtxMenu
>,
2924 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2928 CComPtr
<CTrayWindow
> TrayWnd
;
2929 CComPtr
<IContextMenu
> pcm
;
2932 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2934 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2935 this->hWndOwner
= hWndOwner
;
2939 virtual HRESULT STDMETHODCALLTYPE
2940 QueryContextMenu(HMENU hPopup
,
2946 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
2949 return HRESULT_FROM_WIN32(GetLastError());
2951 int count
= ::GetMenuItemCount(menubase
);
2953 for (int i
= 0; i
< count
; i
++)
2957 MENUITEMINFOW mii
= { 0 };
2958 mii
.cbSize
= sizeof(mii
);
2959 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2960 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2961 mii
.dwTypeData
= label
;
2962 mii
.cch
= _countof(label
);
2963 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2965 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
2967 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
2970 ::DestroyMenu(menubase
);
2972 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2979 CheckMenuItem(hPopup
,
2981 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
2983 if (TrayWnd
->m_TrayBandSite
!= NULL
)
2985 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
2993 WARN("AddContextMenus failed.\n");
3001 virtual HRESULT STDMETHODCALLTYPE
3002 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3004 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3007 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3009 CMINVOKECOMMANDINFO cmici
= { 0 };
3013 /* Setup and invoke the shell command */
3014 cmici
.cbSize
= sizeof(cmici
);
3015 cmici
.hwnd
= hWndOwner
;
3016 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- ID_SHELL_CMD_FIRST
);
3017 cmici
.nShow
= SW_NORMAL
;
3019 pcm
->InvokeCommand(&cmici
);
3024 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3031 virtual HRESULT STDMETHODCALLTYPE
3032 GetCommandString(UINT_PTR idCmd
,
3041 CTrayWindowCtxMenu()
3045 virtual ~CTrayWindowCtxMenu()
3049 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3050 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3054 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3056 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3057 mnu
->Initialize(TrayWnd
, hWndOwner
);
3062 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3064 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3066 return E_OUTOFMEMORY
;
3071 *ppTray
= (ITrayWindow
*) Tray
;
3077 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3079 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3080 return TrayWindow
->RaiseStartButton();
3083 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3085 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3086 TrayWindow
->TrayProcessMessages();
3089 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3091 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3092 TrayWindow
->TrayMessageLoop();