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
);
109 Size
.cy
= 2 * GetSystemMetrics(SM_CYEDGE
);
111 if (hbmStart
== NULL
)
113 hbmStart
= (HBITMAP
) SendMessageW(BM_GETIMAGE
, IMAGE_BITMAP
, 0);
116 if (hbmStart
!= NULL
)
120 if (GetObject(hbmStart
, sizeof(bmp
), &bmp
) != 0)
122 Size
.cx
+= bmp
.bmWidth
;
123 Size
.cy
+= max(bmp
.bmHeight
, GetSystemMetrics(SM_CYCAPTION
));
127 /* Huh?! Shouldn't happen... */
134 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
135 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
139 /* Save the size of the start button */
143 BOOL
CreateImageList()
148 if (m_ImageList
!= NULL
)
151 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
152 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
154 /* Load the start button icon and create a image list for it */
155 hIconStart
= (HICON
) LoadImageW(hExplorerInstance
,
156 MAKEINTRESOURCEW(IDI_START
),
160 LR_SHARED
| LR_DEFAULTCOLOR
);
162 if (hIconStart
== NULL
)
165 m_ImageList
= ImageList_Create(IconSize
.cx
,
167 ILC_COLOR32
| ILC_MASK
,
169 if (m_ImageList
== NULL
)
172 int s
= ImageList_ReplaceIcon(m_ImageList
, -1, hIconStart
);
175 /* Failed to add the icon! */
176 ImageList_Destroy(m_ImageList
);
185 HBITMAP
CreateBitmap()
187 WCHAR szStartCaption
[32];
190 HDC hDCScreen
= NULL
;
191 SIZE Size
, SmallIcon
;
192 HBITMAP hbmpOld
, hbmp
= NULL
;
193 HBITMAP hBitmap
= NULL
;
199 /* NOTE: this is the backwards compatibility code that is used if the
200 Common Controls Version 6.0 are not available! */
202 if (!LoadStringW(hExplorerInstance
,
205 _countof(szStartCaption
)))
210 /* Load the start button icon */
211 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
212 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
213 hIconStart
= (HICON
) LoadImageW(hExplorerInstance
,
214 MAKEINTRESOURCEW(IDI_START
),
218 LR_SHARED
| LR_DEFAULTCOLOR
);
220 hDCScreen
= ::GetDC(NULL
);
221 if (hDCScreen
== NULL
)
224 hDC
= CreateCompatibleDC(hDCScreen
);
228 hFontOld
= (HFONT
) SelectObject(hDC
, m_Font
);
230 Ret
= GetTextExtentPoint32(hDC
,
232 wcslen(szStartCaption
),
235 SelectObject(hDC
, hFontOld
);
239 /* Make sure the height is at least the size of a caption icon. */
240 if (hIconStart
!= NULL
)
241 Size
.cx
+= SmallIcon
.cx
+ 4;
242 Size
.cy
= max(Size
.cy
, SmallIcon
.cy
);
244 /* Create the bitmap */
245 hbmp
= CreateCompatibleBitmap(hDCScreen
,
251 /* Calculate the button rect */
254 rcButton
.right
= Size
.cx
;
255 rcButton
.bottom
= Size
.cy
;
257 /* Draw the button */
258 hbmpOld
= (HBITMAP
) SelectObject(hDC
, hbmp
);
260 Flags
= DC_TEXT
| DC_INBUTTON
;
261 if (hIconStart
!= NULL
)
264 Ret
= DrawCaptionTemp(NULL
,
272 SelectObject(hDC
, hbmpOld
);
277 /* We successfully created the bitmap! */
282 if (hDCScreen
!= NULL
)
284 ::ReleaseDC(NULL
, hDCScreen
);
298 NONCLIENTMETRICS ncm
;
300 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
304 /* Get the system fonts, we use the caption font, always bold, though. */
305 ncm
.cbSize
= sizeof(ncm
);
306 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
308 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
309 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
313 SetFont(m_Font
, FALSE
);
315 if (CreateImageList())
317 BUTTON_IMAGELIST bil
;
319 /* Try to set the start button image. this requires the Common
320 Controls 6.0 to be present (XP and later) */
321 bil
.himl
= m_ImageList
;
322 bil
.margin
.left
= bil
.margin
.right
= 1;
323 bil
.margin
.top
= bil
.margin
.bottom
= 1;
324 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
326 if (SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
))
328 SIZE Size
= { 0, 0 };
329 if (SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
331 /* We're using the image list, remove the BS_BITMAP style and
332 don't center it horizontally */
333 SetWindowStyle(m_hWnd
, BS_BITMAP
| BS_RIGHT
, 0);
340 /* Fall back to the deprecated method on older systems that don't
341 support Common Controls 6.0 */
342 ImageList_Destroy(m_ImageList
);
346 HBITMAP hbmStart
= CreateBitmap();
347 if (hbmStart
!= NULL
)
349 UpdateSize(hbmStart
);
351 HBITMAP hbmOld
= (HBITMAP
) SendMessageW(BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbmStart
);
354 DeleteObject(hbmOld
);
358 HWND
Create(HWND hwndParent
)
360 WCHAR szStartCaption
[32];
361 if (!LoadStringW(hExplorerInstance
,
364 _countof(szStartCaption
)))
366 szStartCaption
[0] = L
'\0';
369 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
;
371 m_hWnd
= CreateWindowEx(
378 (HMENU
) IDC_STARTBTN
,
390 public CComCoClass
<CTrayWindow
>,
391 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
392 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
394 public IShellDesktopTray
396 CStartButton m_StartButton
;
398 CComPtr
<IMenuBand
> m_StartMenuBand
;
399 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
411 CTrayNotifyWnd
* m_TrayNotifyInstance
;
415 HMONITOR m_PreviousMonitor
;
416 DWORD m_DraggingPosition
;
417 HMONITOR m_DraggingMonitor
;
422 HWND m_TrayPropertiesOwner
;
423 HWND m_RunFileDlgOwner
;
425 UINT m_AutoHideState
;
426 SIZE m_AutoHideOffset
;
427 TRACKMOUSEEVENT m_MouseTrackingInfo
;
429 HDPA m_ShellServices
;
432 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
440 DWORD AlwaysOnTop
: 1;
441 DWORD SmSmallIcons
: 1;
446 DWORD InSizeMove
: 1;
447 DWORD IsDragging
: 1;
448 DWORD NewPosSize
: 1;
464 m_PreviousMonitor(NULL
),
465 m_DraggingPosition(0),
466 m_DraggingMonitor(NULL
),
467 m_TrayPropertiesOwner(NULL
),
468 m_RunFileDlgOwner(NULL
),
469 m_AutoHideState(NULL
),
470 m_ShellServices(NULL
),
473 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
474 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
475 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
476 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
479 virtual ~CTrayWindow()
481 if (m_ShellServices
!= NULL
)
483 ShutdownShellServices(m_ShellServices
);
484 m_ShellServices
= NULL
;
487 if (m_CaptionFont
!= NULL
)
489 DeleteObject(m_CaptionFont
);
490 m_CaptionFont
= NULL
;
495 DeleteObject(m_Font
);
501 CloseThemeData(m_Theme
);
505 if (InterlockedDecrement(&TrayWndCount
) == 0)
513 /**********************************************************
514 * ##### command handling #####
517 HRESULT
ExecResourceCmd(int id
)
519 WCHAR szCommand
[256];
520 WCHAR
*pszParameters
;
522 if (!LoadStringW(hExplorerInstance
,
525 _countof(szCommand
)))
530 pszParameters
= wcschr(szCommand
, L
'>');
537 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
541 LRESULT
DoExitWindows()
543 ExitWindowsDialog(m_hWnd
);
547 DWORD WINAPI
RunFileDlgThread()
552 m_StartButton
.GetWindowRect(&posRect
);
554 hwnd
= CreateWindowEx(0,
557 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
560 posRect
.right
- posRect
.left
,
561 posRect
.bottom
- posRect
.top
,
567 m_RunFileDlgOwner
= hwnd
;
569 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
571 m_RunFileDlgOwner
= NULL
;
572 ::DestroyWindow(hwnd
);
577 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
579 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
580 return This
->RunFileDlgThread();
583 void DisplayRunFileDlg()
586 if (m_RunFileDlgOwner
)
588 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
589 if (hRunDlg
!= NULL
&&
590 hRunDlg
!= m_RunFileDlgOwner
)
592 SetForegroundWindow(hRunDlg
);
597 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
600 DWORD WINAPI
TrayPropertiesThread()
605 m_StartButton
.GetWindowRect(&posRect
);
606 hwnd
= CreateWindowEx(0,
609 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
612 posRect
.right
- posRect
.left
,
613 posRect
.bottom
- posRect
.top
,
619 m_TrayPropertiesOwner
= hwnd
;
621 DisplayTrayProperties(hwnd
);
623 m_TrayPropertiesOwner
= NULL
;
624 ::DestroyWindow(hwnd
);
629 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
631 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
633 return This
->TrayPropertiesThread();
636 HWND STDMETHODCALLTYPE
DisplayProperties()
640 if (m_TrayPropertiesOwner
)
642 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
643 if (hTrayProp
!= NULL
&&
644 hTrayProp
!= m_TrayPropertiesOwner
)
646 SetForegroundWindow(hTrayProp
);
651 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
655 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
657 WCHAR szDir
[MAX_PATH
];
659 if (SHGetSpecialFolderPath(hWndOwner
,
661 CSIDL_COMMON_STARTMENU
,
664 ShellExecute(hWndOwner
,
673 VOID
OpenTaskManager(IN HWND hWndOwner
)
675 ShellExecute(hWndOwner
,
683 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
687 case ID_SHELL_CMD_PROPERTIES
:
691 case ID_SHELL_CMD_OPEN_ALL_USERS
:
692 OpenCommonStartMenuDirectory(m_hWnd
,
696 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
697 OpenCommonStartMenuDirectory(m_hWnd
,
702 if (SHRestricted(REST_CLASSICSHELL
) == 0)
708 case ID_SHELL_CMD_OPEN_TASKMGR
:
709 OpenTaskManager(m_hWnd
);
712 case ID_SHELL_CMD_UNDO_ACTION
:
715 case ID_SHELL_CMD_SHOW_DESKTOP
:
718 case ID_SHELL_CMD_TILE_WND_H
:
719 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
722 case ID_SHELL_CMD_TILE_WND_V
:
723 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
726 case ID_SHELL_CMD_CASCADE_WND
:
727 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
730 case ID_SHELL_CMD_CUST_NOTIF
:
733 case ID_SHELL_CMD_ADJUST_DAT
:
734 //FIXME: Use SHRunControlPanel
735 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
739 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
746 LRESULT
HandleHotKey(DWORD id
)
754 ExecResourceCmd(IDS_HELP_COMMAND
);
757 //FIXME: We don't support this yet:
758 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
759 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
762 SHFindFiles(NULL
, NULL
);
764 case IDHK_FIND_COMPUTER
:
765 SHFindComputer(NULL
, NULL
);
767 case IDHK_SYS_PROPERTIES
:
768 //FIXME: Use SHRunControlPanel
769 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
775 case IDHK_MINIMIZE_ALL
:
777 case IDHK_RESTORE_ALL
:
788 LRESULT
HandleCommand(UINT uCommand
)
792 case IDM_TASKBARANDSTARTMENU
:
797 SHFindFiles(NULL
, NULL
);
800 case IDM_HELPANDSUPPORT
:
801 ExecResourceCmd(IDS_HELP_COMMAND
);
808 /* FIXME: Handle these commands as well */
809 case IDM_SYNCHRONIZE
:
811 case IDM_UNDOCKCOMPUTER
:
815 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
829 IN POINT
*ppt OPTIONAL
,
830 IN HWND hwndExclude OPTIONAL
,
832 IN BOOL IsContextMenu
)
834 TPMPARAMS tmp
, *ptmp
= NULL
;
839 if (hwndExclude
!= NULL
)
841 /* Get the client rectangle and map it to screen coordinates */
842 if (::GetClientRect(hwndExclude
,
844 ::MapWindowPoints(hwndExclude
,
846 (LPPOINT
) &tmp
.rcExclude
,
856 GetClientRect(&tmp
.rcExclude
) &&
859 (LPPOINT
) &tmp
.rcExclude
,
867 /* NOTE: TrackPopupMenuEx will eventually align the track position
868 for us, no need to take care of it here as long as the
869 coordinates are somewhere within the exclusion rectangle */
870 pt
.x
= ptmp
->rcExclude
.left
;
871 pt
.y
= ptmp
->rcExclude
.top
;
879 tmp
.cbSize
= sizeof(tmp
);
881 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
882 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
884 fuFlags
|= TPM_RIGHTBUTTON
;
886 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
888 cmdId
= TrackPopupMenuEx(hMenu
,
898 HRESULT
TrackCtxMenu(
899 IN IContextMenu
* contextMenu
,
900 IN POINT
*ppt OPTIONAL
,
901 IN HWND hwndExclude OPTIONAL
,
903 IN PVOID Context OPTIONAL
)
909 HMENU popup
= CreatePopupMenu();
914 TRACE("Before Query\n");
915 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
916 if (FAILED_UNEXPECTEDLY(hr
))
918 TRACE("Query failed\n");
923 TRACE("Before Tracking\n");
924 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
928 TRACE("Before InvokeCommand\n");
929 CMINVOKECOMMANDINFO cmi
= { 0 };
930 cmi
.cbSize
= sizeof(cmi
);
931 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
933 hr
= contextMenu
->InvokeCommand(&cmi
);
937 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
949 /**********************************************************
950 * ##### moving and sizing handling #####
953 BOOL
UpdateNonClientMetrics()
955 NONCLIENTMETRICS ncm
;
956 ncm
.cbSize
= sizeof(ncm
);
957 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
960 DeleteObject(m_Font
);
962 m_Font
= CreateFontIndirect(&ncm
.lfMessageFont
);
969 VOID
SetWindowsFont()
971 if (m_TrayNotify
!= NULL
)
973 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
977 HMONITOR
GetScreenRectFromRect(
984 mi
.cbSize
= sizeof(mi
);
985 hMon
= MonitorFromRect(pRect
, dwFlags
);
987 GetMonitorInfo(hMon
, &mi
))
989 *pRect
= mi
.rcMonitor
;
995 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
996 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
1004 HMONITOR
GetMonitorFromRect(
1005 IN
const RECT
*pRect
)
1009 /* In case the monitor sizes or saved sizes differ a bit (probably
1010 not a lot, only so the tray window overlaps into another monitor
1011 now), minimize the risk that we determine a wrong monitor by
1012 using the center point of the tray window if we can't determine
1013 it using the rectangle. */
1014 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
1019 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1020 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1022 /* be less error-prone, find the nearest monitor */
1023 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
1029 HMONITOR
GetScreenRect(
1030 IN HMONITOR hMonitor
,
1033 HMONITOR hMon
= NULL
;
1035 if (hMonitor
!= NULL
)
1039 mi
.cbSize
= sizeof(mi
);
1040 if (!GetMonitorInfo(hMonitor
, &mi
))
1042 /* Hm, the monitor is gone? Try to find a monitor where it
1043 could be located now */
1044 hMon
= GetMonitorFromRect(pRect
);
1046 !GetMonitorInfo(hMon
, &mi
))
1049 goto GetPrimaryRect
;
1053 *pRect
= mi
.rcMonitor
;
1060 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
1061 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
1067 VOID
MakeTrayRectWithSize(IN DWORD Position
,
1068 IN
const SIZE
*pTraySize
,
1074 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
1078 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
1082 pRect
->left
= pRect
->right
- pTraySize
->cx
;
1087 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
1092 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
1093 IN
const RECT
*pScreen
,
1094 IN
const SIZE
*pTraySize OPTIONAL
,
1097 if (pTraySize
== NULL
)
1098 pTraySize
= &m_TraySize
;
1102 /* Move the border outside of the screen */
1104 GetSystemMetrics(SM_CXEDGE
),
1105 GetSystemMetrics(SM_CYEDGE
));
1107 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
1110 BOOL
IsPosHorizontal()
1112 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
1115 HMONITOR
CalculateValidSize(
1124 //Horizontal = IsPosHorizontal();
1126 szWnd
.cx
= pRect
->right
- pRect
->left
;
1127 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
1130 hMon
= GetScreenRectFromRect(
1132 MONITOR_DEFAULTTONEAREST
);
1134 /* Calculate the maximum size of the tray window and limit the window
1135 size to half of the screen's size. */
1136 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
1137 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
1138 if (szWnd
.cx
> szMax
.cx
)
1139 szWnd
.cx
= szMax
.cx
;
1140 if (szWnd
.cy
> szMax
.cy
)
1141 szWnd
.cy
= szMax
.cy
;
1143 /* FIXME - calculate */
1145 GetTrayRectFromScreenRect(Position
,
1155 GetMinimumWindowSize(
1160 AdjustWindowRectEx(&rcMin
,
1161 GetWindowLong(m_hWnd
,
1164 GetWindowLong(m_hWnd
,
1172 DWORD
GetDraggingRectFromPt(
1175 OUT HMONITOR
*phMonitor
)
1177 HMONITOR hMon
, hMonNew
;
1178 DWORD PosH
, PosV
, Pos
;
1179 SIZE DeltaPt
, ScreenOffset
;
1185 /* Determine the screen rectangle */
1186 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
1191 mi
.cbSize
= sizeof(mi
);
1192 if (!GetMonitorInfo(hMon
, &mi
))
1195 goto GetPrimaryScreenRect
;
1198 /* make left top corner of the screen zero based to
1199 make calculations easier */
1200 pt
.x
-= mi
.rcMonitor
.left
;
1201 pt
.y
-= mi
.rcMonitor
.top
;
1203 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1204 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1205 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1206 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1210 GetPrimaryScreenRect
:
1211 ScreenOffset
.cx
= 0;
1212 ScreenOffset
.cy
= 0;
1213 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1214 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1217 /* Calculate the nearest screen border */
1218 if (pt
.x
< rcScreen
.right
/ 2)
1225 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1229 if (pt
.y
< rcScreen
.bottom
/ 2)
1236 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1240 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1242 /* Fix the screen origin to be relative to the primary monitor again */
1243 OffsetRect(&rcScreen
,
1247 RECT rcPos
= m_TrayRects
[Pos
];
1249 hMonNew
= GetMonitorFromRect(&rcPos
);
1250 if (hMon
!= hMonNew
)
1254 /* Recalculate the rectangle, we're dragging to another monitor.
1255 We don't need to recalculate the rect on single monitor systems. */
1256 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1257 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1259 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1262 pRect
->left
+= m_AutoHideOffset
.cx
;
1263 pRect
->right
+= m_AutoHideOffset
.cx
;
1264 pRect
->top
+= m_AutoHideOffset
.cy
;
1265 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1271 /* The user is dragging the tray window on the same monitor. We don't need
1272 to recalculate the rectangle */
1276 pRect
->left
+= m_AutoHideOffset
.cx
;
1277 pRect
->right
+= m_AutoHideOffset
.cx
;
1278 pRect
->top
+= m_AutoHideOffset
.cy
;
1279 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1288 DWORD
GetDraggingRectFromRect(
1290 OUT HMONITOR
*phMonitor
)
1294 /* Calculate the center of the rectangle. We call
1295 GetDraggingRectFromPt to calculate a valid
1296 dragging rectangle */
1297 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1298 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1300 return GetDraggingRectFromPt(
1306 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1312 rcTray
.left
= pwp
->x
;
1313 rcTray
.top
= pwp
->y
;
1314 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1315 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1318 rcTray
.left
-= m_AutoHideOffset
.cx
;
1319 rcTray
.right
-= m_AutoHideOffset
.cx
;
1320 rcTray
.top
-= m_AutoHideOffset
.cy
;
1321 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1324 if (!EqualRect(&rcTray
,
1325 &m_TrayRects
[m_DraggingPosition
]))
1327 /* Recalculate the rectangle, the user dragged the tray
1328 window to another monitor or the window was somehow else
1330 m_DraggingPosition
= GetDraggingRectFromRect(
1332 &m_DraggingMonitor
);
1333 //m_TrayRects[DraggingPosition] = rcTray;
1336 //Monitor = CalculateValidSize(DraggingPosition,
1339 m_Monitor
= m_DraggingMonitor
;
1340 m_Position
= m_DraggingPosition
;
1343 m_TrayRects
[m_Position
] = rcTray
;
1346 else if (GetWindowRect(&rcTray
))
1350 if (!(pwp
->flags
& SWP_NOMOVE
))
1352 rcTray
.left
= pwp
->x
;
1353 rcTray
.top
= pwp
->y
;
1356 if (!(pwp
->flags
& SWP_NOSIZE
))
1358 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1359 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1362 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1364 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1371 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1376 rcTray
.left
-= m_AutoHideOffset
.cx
;
1377 rcTray
.right
-= m_AutoHideOffset
.cx
;
1378 rcTray
.top
-= m_AutoHideOffset
.cy
;
1379 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1381 m_TrayRects
[m_Position
] = rcTray
;
1385 /* If the user isn't resizing the tray window we need to make sure the
1386 new size or position is valid. this is to prevent changes to the window
1387 without user interaction. */
1388 rcTray
= m_TrayRects
[m_Position
];
1392 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1393 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1397 rcTray
.left
+= m_AutoHideOffset
.cx
;
1398 rcTray
.right
+= m_AutoHideOffset
.cx
;
1399 rcTray
.top
+= m_AutoHideOffset
.cy
;
1400 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1403 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1404 pwp
->x
= rcTray
.left
;
1405 pwp
->y
= rcTray
.top
;
1406 pwp
->cx
= m_TraySize
.cx
;
1407 pwp
->cy
= m_TraySize
.cy
;
1411 VOID
ApplyClipping(IN BOOL Clip
)
1413 RECT rcClip
, rcWindow
;
1416 if (GetWindowRect(&rcWindow
))
1418 /* Disable clipping on systems with only one monitor */
1419 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1426 GetScreenRect(m_Monitor
, &rcClip
);
1428 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1437 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1442 /* Set the clipping region or make sure the window isn't clipped
1443 by disabling it explicitly. */
1444 SetWindowRgn(hClipRgn
, TRUE
);
1448 VOID
ResizeWorkArea()
1450 #if !WIN7_DEBUG_MODE
1451 RECT rcTray
, rcWorkArea
;
1453 /* If monitor has changed then fix the previous monitors work area */
1454 if (m_PreviousMonitor
!= m_Monitor
)
1456 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1457 SystemParametersInfoW(SPI_SETWORKAREA
,
1463 rcTray
= m_TrayRects
[m_Position
];
1465 GetScreenRect(m_Monitor
, &rcWorkArea
);
1466 m_PreviousMonitor
= m_Monitor
;
1468 /* If AutoHide is false then change the workarea to exclude
1469 the area that the taskbar covers. */
1475 rcWorkArea
.top
= rcTray
.bottom
;
1478 rcWorkArea
.left
= rcTray
.right
;
1481 rcWorkArea
.right
= rcTray
.left
;
1484 rcWorkArea
.bottom
= rcTray
.top
;
1490 * Resize the current monitor work area. Win32k will also send
1491 * a WM_SIZE message to automatically resize the desktop.
1493 SystemParametersInfoW(SPI_SETWORKAREA
,
1500 VOID
CheckTrayWndPosition()
1504 rcTray
= m_TrayRects
[m_Position
];
1508 rcTray
.left
+= m_AutoHideOffset
.cx
;
1509 rcTray
.right
+= m_AutoHideOffset
.cx
;
1510 rcTray
.top
+= m_AutoHideOffset
.cy
;
1511 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1514 /* Move the tray window */
1518 rcTray
.right
- rcTray
.left
,
1519 rcTray
.bottom
- rcTray
.top
,
1520 SWP_NOZORDER
| SWP_NOACTIVATE
);
1524 ApplyClipping(TRUE
);
1527 typedef struct _TW_STUCKRECTS2
1535 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1537 VOID
RegLoadSettings()
1542 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1543 DWORD cbSize
= sizeof(sr
);
1544 SIZE StartBtnSize
= m_StartButton
.GetSize();
1546 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1547 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1548 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1549 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1551 if (SHGetValue(hkExplorer
,
1552 TEXT("StuckRects2"),
1556 &cbSize
) == ERROR_SUCCESS
&&
1557 sr
.cbSize
== sizeof(sr
))
1559 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1560 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1561 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1562 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1564 /* FIXME: Are there more flags? */
1567 m_Position
= ABE_LEFT
;
1569 if (sr
.Position
> ABE_BOTTOM
)
1570 m_Position
= ABE_BOTTOM
;
1572 m_Position
= sr
.Position
;
1575 /* Try to find out which monitor the tray window was located on last.
1576 Here we're only interested in the monitor screen that we think
1577 is the last one used. We're going to determine on which monitor
1578 we really are after calculating the docked position. */
1580 GetScreenRectFromRect(
1582 MONITOR_DEFAULTTONEAREST
);
1586 m_Position
= ABE_BOTTOM
;
1589 /* Use the minimum size of the taskbar, we'll use the start
1590 button as a minimum for now. Make sure we calculate the
1591 entire window size, not just the client size. However, we
1592 use a thinner border than a standard thick border, so that
1593 the start button and bands are not stuck to the screen border. */
1594 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1595 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1597 /* Use the primary screen by default */
1600 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1601 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1602 GetScreenRectFromRect(
1604 MONITOR_DEFAULTTOPRIMARY
);
1609 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1614 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1616 /* Determine a minimum tray window rectangle. The "client" height is
1617 zero here since we cannot determine an optimal minimum width when
1618 loaded as a vertical tray window. We just need to make sure the values
1619 loaded from the registry are at least. The windows explorer behaves
1620 the same way, it allows the user to save a zero width vertical tray
1621 window, but not a zero height horizontal tray window. */
1622 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1623 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1625 if (WndSize
.cx
< sr
.Size
.cx
)
1626 WndSize
.cx
= sr
.Size
.cx
;
1627 if (WndSize
.cy
< sr
.Size
.cy
)
1628 WndSize
.cy
= sr
.Size
.cy
;
1630 /* Save the calculated size */
1631 m_TraySize
= WndSize
;
1633 /* Calculate all docking rectangles. We need to do this here so they're
1634 initialized and dragging the tray window to another position gives
1636 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1638 GetTrayRectFromScreenRect(Pos
,
1642 // 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);
1645 /* Determine which monitor we are on. It shouldn't matter which docked
1646 position rectangle we use */
1647 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1650 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1653 SIZE TraySize
, StartSize
;
1654 POINT ptTrayNotify
= { 0, 0 };
1658 m_StartButton
.UpdateSize();
1659 if (prcClient
!= NULL
)
1661 rcClient
= *prcClient
;
1665 if (!GetClientRect(&rcClient
))
1667 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1672 Horizontal
= IsPosHorizontal();
1674 /* We're about to resize/move the start button, the rebar control and
1675 the tray notification control */
1676 dwp
= BeginDeferWindowPos(3);
1679 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1683 /* Limit the Start button width to the client width, if necessary */
1684 StartSize
= m_StartButton
.GetSize();
1685 if (StartSize
.cx
> rcClient
.right
)
1686 StartSize
.cx
= rcClient
.right
;
1688 if (m_StartButton
.m_hWnd
!= NULL
)
1690 /* Resize and reposition the button */
1691 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1697 SWP_NOZORDER
| SWP_NOACTIVATE
);
1700 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1705 /* Determine the size that the tray notification window needs */
1709 TraySize
.cy
= rcClient
.bottom
;
1713 TraySize
.cx
= rcClient
.right
;
1717 if (m_TrayNotify
!= NULL
&&
1718 SendMessage(m_TrayNotify
,
1719 TNWM_GETMINIMUMSIZE
,
1723 /* Move the tray notification window to the desired location */
1725 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1727 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1729 dwp
= ::DeferWindowPos(dwp
,
1736 SWP_NOZORDER
| SWP_NOACTIVATE
);
1739 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1744 /* Resize/Move the rebar control */
1745 if (m_Rebar
!= NULL
)
1747 POINT ptRebar
= { 0, 0 };
1750 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1754 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1755 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1756 szRebar
.cy
= rcClient
.bottom
;
1760 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1761 szRebar
.cx
= rcClient
.right
;
1762 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1765 dwp
= ::DeferWindowPos(dwp
,
1772 SWP_NOZORDER
| SWP_NOACTIVATE
);
1776 EndDeferWindowPos(dwp
);
1778 if (m_TaskSwitch
!= NULL
)
1780 /* Update the task switch window configuration */
1781 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1785 void PopupStartMenu()
1787 if (m_StartMenuPopup
!= NULL
)
1793 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1798 pt
.x
= rcExclude
.left
;
1799 pt
.y
= rcExclude
.top
;
1800 dwFlags
|= MPPF_TOP
;
1803 pt
.x
= rcExclude
.left
;
1804 pt
.y
= rcExclude
.bottom
;
1805 dwFlags
|= MPPF_BOTTOM
;
1808 pt
.x
= rcExclude
.right
;
1809 pt
.y
= rcExclude
.top
;
1810 dwFlags
|= MPPF_RIGHT
;
1813 pt
.x
= rcExclude
.left
;
1814 pt
.y
= rcExclude
.top
;
1815 dwFlags
|= MPPF_LEFT
;
1819 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1821 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1826 void ProcessMouseTracking()
1831 UINT state
= m_AutoHideState
;
1834 GetWindowRect(&rcCurrent
);
1835 over
= PtInRect(&rcCurrent
, pt
);
1837 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1844 if (state
== AUTOHIDE_HIDING
)
1846 TRACE("AutoHide cancelling hide.\n");
1847 m_AutoHideState
= AUTOHIDE_SHOWING
;
1848 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1850 else if (state
== AUTOHIDE_HIDDEN
)
1852 TRACE("AutoHide starting show.\n");
1853 m_AutoHideState
= AUTOHIDE_SHOWING
;
1854 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1859 if (state
== AUTOHIDE_SHOWING
)
1861 TRACE("AutoHide cancelling show.\n");
1862 m_AutoHideState
= AUTOHIDE_HIDING
;
1863 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1865 else if (state
== AUTOHIDE_SHOWN
)
1867 TRACE("AutoHide starting hide.\n");
1868 m_AutoHideState
= AUTOHIDE_HIDING
;
1869 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1872 KillTimer(TIMER_ID_MOUSETRACK
);
1876 void ProcessAutoHide()
1878 RECT rc
= m_TrayRects
[m_Position
];
1879 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1880 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1882 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
);
1884 switch (m_AutoHideState
)
1886 case AUTOHIDE_HIDING
:
1890 m_AutoHideOffset
.cy
= 0;
1891 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1892 if (m_AutoHideOffset
.cx
< -w
)
1893 m_AutoHideOffset
.cx
= -w
;
1896 m_AutoHideOffset
.cx
= 0;
1897 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1898 if (m_AutoHideOffset
.cy
< -h
)
1899 m_AutoHideOffset
.cy
= -h
;
1902 m_AutoHideOffset
.cy
= 0;
1903 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1904 if (m_AutoHideOffset
.cx
> w
)
1905 m_AutoHideOffset
.cx
= w
;
1908 m_AutoHideOffset
.cx
= 0;
1909 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1910 if (m_AutoHideOffset
.cy
> h
)
1911 m_AutoHideOffset
.cy
= h
;
1915 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1917 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1922 case AUTOHIDE_HIDDEN
:
1927 m_AutoHideOffset
.cx
= -w
;
1928 m_AutoHideOffset
.cy
= 0;
1931 m_AutoHideOffset
.cx
= 0;
1932 m_AutoHideOffset
.cy
= -h
;
1935 m_AutoHideOffset
.cx
= w
;
1936 m_AutoHideOffset
.cy
= 0;
1939 m_AutoHideOffset
.cx
= 0;
1940 m_AutoHideOffset
.cy
= h
;
1944 KillTimer(TIMER_ID_AUTOHIDE
);
1945 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1948 case AUTOHIDE_SHOWING
:
1949 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1951 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1953 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1955 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1959 m_AutoHideOffset
.cx
= 0;
1962 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1964 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1966 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1968 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1972 m_AutoHideOffset
.cy
= 0;
1975 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1977 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1982 case AUTOHIDE_SHOWN
:
1984 KillTimer(TIMER_ID_AUTOHIDE
);
1985 m_AutoHideState
= AUTOHIDE_SHOWN
;
1989 rc
.left
+= m_AutoHideOffset
.cx
;
1990 rc
.right
+= m_AutoHideOffset
.cx
;
1991 rc
.top
+= m_AutoHideOffset
.cy
;
1992 rc
.bottom
+= m_AutoHideOffset
.cy
;
1994 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1995 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2002 /**********************************************************
2003 * ##### taskbar drawing #####
2006 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
2012 GetClientRect(&rect
);
2016 GetClientRect(&rect
);
2020 partId
= TBP_BACKGROUNDLEFT
;
2023 partId
= TBP_BACKGROUNDTOP
;
2026 partId
= TBP_BACKGROUNDRIGHT
;
2030 partId
= TBP_BACKGROUNDBOTTOM
;
2033 res
= DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
2039 int DrawSizerWithTheme(IN HRGN hRgn
)
2045 GetWindowRect(&rect
);
2046 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
2048 hdc
= GetDCEx(hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
2053 backgroundPart
= TBP_SIZINGBARLEFT
;
2054 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
2057 backgroundPart
= TBP_SIZINGBARTOP
;
2058 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
2061 backgroundPart
= TBP_SIZINGBARRIGHT
;
2062 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
2066 backgroundPart
= TBP_SIZINGBARBOTTOM
;
2067 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
2070 if (IsThemeBackgroundPartiallyTransparent(m_Theme
, backgroundPart
, 0))
2072 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
2074 DrawThemeBackground(m_Theme
, hdc
, backgroundPart
, 0, &rect
, 0);
2087 HRESULT STDMETHODCALLTYPE
Open()
2091 /* Check if there's already a window created and try to show it.
2092 If it was somehow destroyed just create a new tray window. */
2093 if (m_hWnd
!= NULL
&& IsWindow())
2095 if (!IsWindowVisible())
2097 CheckTrayWndPosition();
2099 ShowWindow(SW_SHOW
);
2105 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
2107 dwExStyle
|= WS_EX_TOPMOST
;
2109 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
2110 WS_BORDER
| WS_THICKFRAME
;
2112 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
2113 if (m_Position
!= (DWORD
) -1)
2114 rcWnd
= m_TrayRects
[m_Position
];
2116 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
2122 HRESULT STDMETHODCALLTYPE
Close()
2135 HWND STDMETHODCALLTYPE
GetHWND()
2140 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2142 return (m_hWnd
== hWnd
||
2143 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2146 BOOL STDMETHODCALLTYPE
IsHorizontal()
2148 return IsPosHorizontal();
2151 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
2153 if (phBoldCaption
!= NULL
)
2154 *phBoldCaption
= m_StartButton
.GetFont();
2156 return m_CaptionFont
;
2159 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2161 BOOL bPrevLock
= Locked
;
2163 if (Locked
!= bLock
)
2167 if (m_TrayBandSite
!= NULL
)
2169 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2177 if (Locked
&& m_Theme
)
2179 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2183 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2185 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2197 /**********************************************************
2198 * ##### message handling #####
2201 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2203 ((ITrayWindow
*)this)->AddRef();
2205 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2207 InterlockedIncrement(&TrayWndCount
);
2209 if (m_CaptionFont
== NULL
)
2211 NONCLIENTMETRICS ncm
;
2213 /* Get the system fonts, we use the caption font,
2214 always bold, though. */
2215 ncm
.cbSize
= sizeof(ncm
);
2216 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
2218 if (m_CaptionFont
== NULL
)
2220 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
2221 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
2226 /* Create the Start button */
2227 m_StartButton
.Create(m_hWnd
);
2229 /* Load the saved tray window settings */
2232 /* Create and initialize the start menu */
2233 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2234 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2236 /* Load the tray band site */
2237 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
2238 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2240 /* Create the tray notification window */
2241 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2243 if (UpdateNonClientMetrics())
2248 /* Move the tray window to the right position and resize it if necessary */
2249 CheckTrayWndPosition();
2251 /* Align all controls on the tray window */
2252 AlignControls(NULL
);
2254 InitShellServices(&m_ShellServices
);
2258 m_AutoHideState
= AUTOHIDE_HIDING
;
2259 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2262 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2263 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2264 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2265 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2266 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2267 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2268 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2269 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2270 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2271 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2272 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2273 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2278 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2281 CloseThemeData(m_Theme
);
2283 if (IsThemeActive())
2284 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2288 if (Locked
&& m_Theme
)
2290 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2294 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2296 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2301 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2303 HDC hdc
= (HDC
) wParam
;
2311 return EraseBackgroundWithTheme(hdc
);
2314 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2316 /* Load the saved tray window settings */
2319 /* Move the tray window to the right position and resize it if necessary */
2320 CheckTrayWndPosition();
2322 /* Align all controls on the tray window */
2323 AlignControls(NULL
);
2328 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2332 TRACE("WM_COPYDATA notify message received. Handling...\n");
2333 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2338 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2346 return DrawSizerWithTheme((HRGN
) wParam
);
2349 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2351 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2352 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2355 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2362 /* The user may not be able to resize the tray window.
2363 Pretend like the window is not sizeable when the user
2364 clicks on the border. */
2368 SetLastError(ERROR_SUCCESS
);
2369 if (GetClientRect(&rcClient
) &&
2370 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2372 pt
.x
= (SHORT
) LOWORD(lParam
);
2373 pt
.y
= (SHORT
) HIWORD(lParam
);
2375 if (PtInRect(&rcClient
,
2378 /* The user is trying to drag the tray window */
2382 /* Depending on the position of the tray window, allow only
2383 changing the border next to the monitor working area */
2387 if (pt
.y
> rcClient
.bottom
)
2391 if (pt
.x
> rcClient
.right
)
2395 if (pt
.x
< rcClient
.left
)
2400 if (pt
.y
< rcClient
.top
)
2409 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2412 PRECT pRect
= (PRECT
) lParam
;
2414 /* We need to ensure that an application can not accidently
2415 move the tray window (using SetWindowPos). However, we still
2416 need to be able to move the window in case the user wants to
2417 drag the tray window to another position or in case the user
2418 wants to resize the tray window. */
2419 if (!Locked
&& GetCursorPos(&ptCursor
))
2422 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2426 *pRect
= m_TrayRects
[m_Position
];
2430 pRect
->left
+= m_AutoHideOffset
.cx
;
2431 pRect
->right
+= m_AutoHideOffset
.cx
;
2432 pRect
->top
+= m_AutoHideOffset
.cy
;
2433 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2439 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2441 PRECT pRect
= (PRECT
) lParam
;
2445 /* Get the rect of the rebar */
2446 RECT rebarRect
, taskbarRect
;
2447 ::GetWindowRect(m_Rebar
, &rebarRect
);
2448 ::GetWindowRect(m_hWnd
, &taskbarRect
);
2449 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
2451 /* Calculate the difference of size of the taskbar and the rebar */
2453 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
2454 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
2456 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
2460 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
2461 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2462 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
2465 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
2466 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2467 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
2471 /* FIXME: what to do here? */
2475 CalculateValidSize(m_Position
, pRect
);
2479 *pRect
= m_TrayRects
[m_Position
];
2483 pRect
->left
+= m_AutoHideOffset
.cx
;
2484 pRect
->right
+= m_AutoHideOffset
.cx
;
2485 pRect
->top
+= m_AutoHideOffset
.cy
;
2486 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2492 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2494 ChangingWinPos((LPWINDOWPOS
) lParam
);
2498 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2501 InvalidateRect(NULL
, TRUE
);
2502 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2505 /* Clip the tray window on multi monitor systems so the edges can't
2506 overlap into another monitor */
2507 ApplyClipping(TRUE
);
2509 if (!GetClientRect(&rcClient
))
2516 rcClient
.left
= rcClient
.top
= 0;
2517 rcClient
.right
= LOWORD(lParam
);
2518 rcClient
.bottom
= HIWORD(lParam
);
2521 AlignControls(&rcClient
);
2525 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2531 /* Remove the clipping on multi monitor systems while dragging around */
2532 ApplyClipping(FALSE
);
2537 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2542 /* Apply clipping */
2543 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2548 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2554 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2555 The tray window needs to handle this specially, since it normally doesn't have
2558 static const UINT uidDisableItem
[] = {
2568 /* temporarily enable the system menu */
2569 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2571 hSysMenu
= GetSystemMenu(FALSE
);
2572 if (hSysMenu
!= NULL
)
2574 /* Disable all items that are not relevant */
2575 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2577 EnableMenuItem(hSysMenu
,
2579 MF_BYCOMMAND
| MF_GRAYED
);
2582 EnableMenuItem(hSysMenu
,
2585 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2587 /* Display the system menu */
2591 m_StartButton
.m_hWnd
,
2592 m_Position
!= ABE_TOP
,
2596 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2600 /* revert the system menu window style */
2601 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2611 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2613 /* We want the user to be able to get a context menu even on the nonclient
2614 area (including the sizing border)! */
2615 uMsg
= WM_CONTEXTMENU
;
2616 wParam
= (WPARAM
) m_hWnd
;
2618 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2621 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2623 LRESULT Ret
= FALSE
;
2624 POINT pt
, *ppt
= NULL
;
2625 HWND hWndExclude
= NULL
;
2627 /* Check if the administrator has forbidden access to context menus */
2628 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2631 pt
.x
= (SHORT
) LOWORD(lParam
);
2632 pt
.y
= (SHORT
) HIWORD(lParam
);
2634 if (pt
.x
!= -1 || pt
.y
!= -1)
2637 hWndExclude
= m_StartButton
.m_hWnd
;
2639 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2641 /* Make sure we can't track the context menu if the start
2642 menu is currently being shown */
2643 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2645 CComPtr
<IContextMenu
> ctxMenu
;
2646 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2647 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2652 /* See if the context menu should be handled by the task band site */
2653 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2656 POINT ptClient
= *ppt
;
2658 /* Convert the coordinates to client-coordinates */
2659 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2661 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2662 if (hWndAtPt
!= NULL
&&
2663 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2665 /* Check if the user clicked on the task switch window */
2667 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2669 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2670 if (hWndAtPt
== m_TaskSwitch
)
2671 goto HandleTrayContextMenu
;
2673 /* Forward the message to the task band site */
2674 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2677 goto HandleTrayContextMenu
;
2681 HandleTrayContextMenu
:
2682 /* Tray the default tray window context menu */
2683 CComPtr
<IContextMenu
> ctxMenu
;
2684 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2685 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2691 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2693 LRESULT Ret
= FALSE
;
2694 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2695 the rebar control! But we shouldn't forward messages that the band
2696 site doesn't handle, such as other controls (start button, tray window */
2698 HRESULT hr
= E_FAIL
;
2702 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2707 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2709 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2711 if (nmh
->hwndFrom
== m_TrayNotify
)
2716 /* Cause all controls to be aligned */
2717 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2725 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2727 /* We "handle" this message so users can't cause a weird maximize/restore
2728 window animation when double-clicking the tray window! */
2730 /* We should forward mouse messages to child windows here.
2731 Right now, this is only clock double-click */
2733 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2736 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2737 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2738 if (PtInRect(&rcClock
, ptClick
))
2740 //FIXME: use SHRunControlPanel
2741 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2747 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2753 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2756 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2757 if (FAILED_UNEXPECTEDLY(hr
))
2760 if (::IsWindowVisible(hwndStartMenu
))
2762 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2772 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2775 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2776 * to show the shutdown dialog. Also a WM_CLOSE message sent
2777 * by apps should show the dialog.
2779 return DoExitWindows();
2782 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2784 if (wParam
== SC_CLOSE
)
2786 return DoExitWindows();
2793 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2795 return HandleHotKey(wParam
);
2798 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2800 LRESULT Ret
= FALSE
;
2802 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2808 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2810 return HandleCommand(LOWORD(wParam
));
2815 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2819 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2825 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2827 if (wParam
== TIMER_ID_MOUSETRACK
)
2829 ProcessMouseTracking();
2831 else if (wParam
== TIMER_ID_AUTOHIDE
)
2840 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2843 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2849 ::GetWindowRect(m_hWnd
, &rc
);
2853 rc
.bottom
- rc
.top
};
2855 as
->rcTarget
.right
- as
->rcTarget
.left
,
2856 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2858 as
->rcActual
.right
- as
->rcActual
.left
,
2859 as
->rcActual
.bottom
- as
->rcActual
.top
};
2862 szWindow
.cx
- szTarget
.cx
,
2863 szWindow
.cy
- szTarget
.cx
,
2869 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2872 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2875 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2876 rc
.left
= rc
.right
- szWindow
.cy
;
2879 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2880 rc
.top
= rc
.bottom
- szWindow
.cy
;
2884 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2891 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2893 BEGIN_MSG_MAP(CTrayWindow
)
2894 if (m_StartMenuBand
!= NULL
)
2901 Msg
.wParam
= wParam
;
2902 Msg
.lParam
= lParam
;
2904 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2909 wParam
= Msg
.wParam
;
2910 lParam
= Msg
.lParam
;
2912 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2913 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2914 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2915 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2916 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2917 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2918 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2919 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2920 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2921 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2922 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2923 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2924 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2925 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2926 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2927 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2928 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2929 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2930 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2931 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2932 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2933 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2934 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2935 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2936 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2937 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2938 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2939 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2940 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2941 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2942 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2946 /*****************************************************************************/
2948 VOID
TrayProcessMessages()
2952 /* FIXME: We should keep a reference here... */
2954 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2956 if (Msg
.message
== WM_QUIT
)
2959 if (m_StartMenuBand
== NULL
||
2960 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2962 TranslateMessage(&Msg
);
2963 DispatchMessage(&Msg
);
2968 VOID
TrayMessageLoop()
2973 /* FIXME: We should keep a reference here... */
2977 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2979 if (!Ret
|| Ret
== -1)
2982 if (m_StartMenuBand
== NULL
||
2983 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2985 TranslateMessage(&Msg
);
2986 DispatchMessage(&Msg
);
2994 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2995 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2996 * The reason we implement it is because we have to use SHCreateDesktop() so
2997 * that the shell provides the desktop window and all the features that come
2998 * with it (especially positioning of desktop icons)
3001 virtual ULONG STDMETHODCALLTYPE
GetState()
3003 /* FIXME: Return ABS_ flags? */
3004 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3008 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
3010 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
3011 *phWndTray
= m_hWnd
;
3015 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
3017 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
3019 m_DesktopWnd
= hWndDesktop
;
3023 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
3025 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
3029 virtual HRESULT
RaiseStartButton()
3031 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
3037 m_Position
= (DWORD
) -1;
3040 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
3042 DECLARE_PROTECT_FINAL_CONSTRUCT()
3043 BEGIN_COM_MAP(CTrayWindow
)
3044 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3045 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
3049 class CTrayWindowCtxMenu
:
3050 public CComCoClass
<CTrayWindowCtxMenu
>,
3051 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
3055 CComPtr
<CTrayWindow
> TrayWnd
;
3056 CComPtr
<IContextMenu
> pcm
;
3059 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3061 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3062 this->hWndOwner
= hWndOwner
;
3066 virtual HRESULT STDMETHODCALLTYPE
3067 QueryContextMenu(HMENU hPopup
,
3073 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3076 return HRESULT_FROM_WIN32(GetLastError());
3078 int count
= ::GetMenuItemCount(menubase
);
3080 for (int i
= 0; i
< count
; i
++)
3084 MENUITEMINFOW mii
= { 0 };
3085 mii
.cbSize
= sizeof(mii
);
3086 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3087 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3088 mii
.dwTypeData
= label
;
3089 mii
.cch
= _countof(label
);
3090 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3092 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3094 mii
.fType
|= MFT_RADIOCHECK
;
3096 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3099 ::DestroyMenu(menubase
);
3101 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3108 CheckMenuItem(hPopup
,
3110 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3112 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3114 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3122 WARN("AddContextMenus failed.\n");
3130 virtual HRESULT STDMETHODCALLTYPE
3131 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3133 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3136 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3138 CMINVOKECOMMANDINFO cmici
= { 0 };
3142 /* Setup and invoke the shell command */
3143 cmici
.cbSize
= sizeof(cmici
);
3144 cmici
.hwnd
= hWndOwner
;
3145 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- ID_SHELL_CMD_FIRST
);
3146 cmici
.nShow
= SW_NORMAL
;
3148 pcm
->InvokeCommand(&cmici
);
3153 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3160 virtual HRESULT STDMETHODCALLTYPE
3161 GetCommandString(UINT_PTR idCmd
,
3170 CTrayWindowCtxMenu()
3174 virtual ~CTrayWindowCtxMenu()
3178 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3179 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3183 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3185 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3186 mnu
->Initialize(TrayWnd
, hWndOwner
);
3191 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3193 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3195 return E_OUTOFMEMORY
;
3200 *ppTray
= (ITrayWindow
*) Tray
;
3206 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3208 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3209 return TrayWindow
->RaiseStartButton();
3212 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3214 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3215 TrayWindow
->TrayProcessMessages();
3218 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3220 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3221 TrayWindow
->TrayMessageLoop();