4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * this library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * this library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
26 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
28 #define TIMER_ID_AUTOHIDE 1
29 #define TIMER_ID_MOUSETRACK 2
30 #define MOUSETRACK_INTERVAL 100
31 #define AUTOHIDE_DELAY_HIDE 2000
32 #define AUTOHIDE_DELAY_SHOW 50
33 #define AUTOHIDE_INTERVAL_ANIMATING 10
35 #define AUTOHIDE_SPEED_SHOW 10
36 #define AUTOHIDE_SPEED_HIDE 1
38 #define AUTOHIDE_HIDDEN 0
39 #define AUTOHIDE_SHOWING 1
40 #define AUTOHIDE_SHOWN 2
41 #define AUTOHIDE_HIDING 3
43 #define IDHK_RUN 0x1f4
44 #define IDHK_MINIMIZE_ALL 0x1f5
45 #define IDHK_RESTORE_ALL 0x1f6
46 #define IDHK_HELP 0x1f7
47 #define IDHK_EXPLORE 0x1f8
48 #define IDHK_FIND 0x1f9
49 #define IDHK_FIND_COMPUTER 0x1fa
50 #define IDHK_NEXT_TASK 0x1fb
51 #define IDHK_PREV_TASK 0x1fc
52 #define IDHK_SYS_PROPERTIES 0x1fd
53 #define IDHK_DESKTOP 0x1fe
54 #define IDHK_PAGER 0x1ff
56 static const WCHAR szTrayWndClass
[] = L
"Shell_TrayWnd";
62 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
67 HIMAGELIST m_ImageList
;
80 virtual ~CStartButton()
82 if (m_ImageList
!= NULL
)
83 ImageList_Destroy(m_ImageList
);
98 if (m_ImageList
== NULL
||
99 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
101 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
) + GetSystemMetrics(SM_CYCAPTION
) * 3;
104 Size
.cy
= max(Size
.cy
, GetSystemMetrics(SM_CYCAPTION
));
106 /* Save the size of the start button */
112 /* Get the system fonts, we use the caption font, always bold, though. */
113 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
114 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
118 DeleteObject(m_Font
);
120 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
121 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
123 SetFont(m_Font
, FALSE
);
128 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
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
,
180 CStartButton m_StartButton
;
182 CComPtr
<IMenuBand
> m_StartMenuBand
;
183 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
185 CComPtr
<IDeskBand
> m_TaskBand
;
195 CTrayNotifyWnd
* m_TrayNotifyInstance
;
199 HMONITOR m_PreviousMonitor
;
200 DWORD m_DraggingPosition
;
201 HMONITOR m_DraggingMonitor
;
206 HWND m_TrayPropertiesOwner
;
207 HWND m_RunFileDlgOwner
;
209 UINT m_AutoHideState
;
210 SIZE m_AutoHideOffset
;
211 TRACKMOUSEEVENT m_MouseTrackingInfo
;
213 HDPA m_ShellServices
;
216 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
224 DWORD AlwaysOnTop
: 1;
225 DWORD SmSmallIcons
: 1;
230 DWORD InSizeMove
: 1;
231 DWORD IsDragging
: 1;
232 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
;
272 DeleteObject(m_Font
);
278 CloseThemeData(m_Theme
);
289 /**********************************************************
290 * ##### command handling #####
293 HRESULT
ExecResourceCmd(int id
)
295 WCHAR szCommand
[256];
296 WCHAR
*pszParameters
;
298 if (!LoadStringW(hExplorerInstance
,
301 _countof(szCommand
)))
306 pszParameters
= wcschr(szCommand
, L
'>');
313 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
317 LRESULT
DoExitWindows()
319 ExitWindowsDialog(m_hWnd
);
323 DWORD WINAPI
RunFileDlgThread()
328 m_StartButton
.GetWindowRect(&posRect
);
330 hwnd
= CreateWindowEx(0,
333 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
336 posRect
.right
- posRect
.left
,
337 posRect
.bottom
- posRect
.top
,
343 m_RunFileDlgOwner
= hwnd
;
345 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
347 m_RunFileDlgOwner
= NULL
;
348 ::DestroyWindow(hwnd
);
353 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
355 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
356 return This
->RunFileDlgThread();
359 void DisplayRunFileDlg()
362 if (m_RunFileDlgOwner
)
364 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
365 if (hRunDlg
!= NULL
&&
366 hRunDlg
!= m_RunFileDlgOwner
)
368 SetForegroundWindow(hRunDlg
);
373 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
376 DWORD WINAPI
TrayPropertiesThread()
381 m_StartButton
.GetWindowRect(&posRect
);
382 hwnd
= CreateWindowEx(0,
385 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
388 posRect
.right
- posRect
.left
,
389 posRect
.bottom
- posRect
.top
,
395 m_TrayPropertiesOwner
= hwnd
;
397 DisplayTrayProperties(hwnd
);
399 m_TrayPropertiesOwner
= NULL
;
400 ::DestroyWindow(hwnd
);
405 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
407 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
409 return This
->TrayPropertiesThread();
412 HWND STDMETHODCALLTYPE
DisplayProperties()
416 if (m_TrayPropertiesOwner
)
418 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
419 if (hTrayProp
!= NULL
&&
420 hTrayProp
!= m_TrayPropertiesOwner
)
422 SetForegroundWindow(hTrayProp
);
427 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
431 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
433 WCHAR szDir
[MAX_PATH
];
435 if (SHGetSpecialFolderPath(hWndOwner
,
437 CSIDL_COMMON_STARTMENU
,
440 ShellExecute(hWndOwner
,
449 VOID
OpenTaskManager(IN HWND hWndOwner
)
451 ShellExecute(hWndOwner
,
459 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
463 case ID_SHELL_CMD_PROPERTIES
:
467 case ID_SHELL_CMD_OPEN_ALL_USERS
:
468 OpenCommonStartMenuDirectory(m_hWnd
,
472 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
473 OpenCommonStartMenuDirectory(m_hWnd
,
478 if (SHRestricted(REST_CLASSICSHELL
) == 0)
484 case ID_SHELL_CMD_OPEN_TASKMGR
:
485 OpenTaskManager(m_hWnd
);
488 case ID_SHELL_CMD_UNDO_ACTION
:
491 case ID_SHELL_CMD_SHOW_DESKTOP
:
494 case ID_SHELL_CMD_TILE_WND_H
:
495 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
498 case ID_SHELL_CMD_TILE_WND_V
:
499 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
502 case ID_SHELL_CMD_CASCADE_WND
:
503 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
506 case ID_SHELL_CMD_CUST_NOTIF
:
507 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
510 case ID_SHELL_CMD_ADJUST_DAT
:
511 //FIXME: Use SHRunControlPanel
512 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
516 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
523 LRESULT
HandleHotKey(DWORD id
)
531 ExecResourceCmd(IDS_HELP_COMMAND
);
534 //FIXME: We don't support this yet:
535 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
536 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
539 SHFindFiles(NULL
, NULL
);
541 case IDHK_FIND_COMPUTER
:
542 SHFindComputer(NULL
, NULL
);
544 case IDHK_SYS_PROPERTIES
:
545 //FIXME: Use SHRunControlPanel
546 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
552 case IDHK_MINIMIZE_ALL
:
554 case IDHK_RESTORE_ALL
:
565 LRESULT
HandleCommand(UINT uCommand
)
569 case IDM_TASKBARANDSTARTMENU
:
574 SHFindFiles(NULL
, NULL
);
577 case IDM_HELPANDSUPPORT
:
578 ExecResourceCmd(IDS_HELP_COMMAND
);
585 /* FIXME: Handle these commands as well */
586 case IDM_SYNCHRONIZE
:
588 case IDM_UNDOCKCOMPUTER
:
592 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
606 IN POINT
*ppt OPTIONAL
,
607 IN HWND hwndExclude OPTIONAL
,
609 IN BOOL IsContextMenu
)
611 TPMPARAMS tmp
, *ptmp
= NULL
;
616 if (hwndExclude
!= NULL
)
618 /* Get the client rectangle and map it to screen coordinates */
619 if (::GetClientRect(hwndExclude
,
621 ::MapWindowPoints(hwndExclude
,
623 (LPPOINT
) &tmp
.rcExclude
,
633 GetClientRect(&tmp
.rcExclude
) &&
636 (LPPOINT
) &tmp
.rcExclude
,
644 /* NOTE: TrackPopupMenuEx will eventually align the track position
645 for us, no need to take care of it here as long as the
646 coordinates are somewhere within the exclusion rectangle */
647 pt
.x
= ptmp
->rcExclude
.left
;
648 pt
.y
= ptmp
->rcExclude
.top
;
656 tmp
.cbSize
= sizeof(tmp
);
658 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
659 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
661 fuFlags
|= TPM_RIGHTBUTTON
;
663 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
665 cmdId
= TrackPopupMenuEx(hMenu
,
675 HRESULT
TrackCtxMenu(
676 IN IContextMenu
* contextMenu
,
677 IN POINT
*ppt OPTIONAL
,
678 IN HWND hwndExclude OPTIONAL
,
680 IN PVOID Context OPTIONAL
)
686 HMENU popup
= CreatePopupMenu();
691 TRACE("Before Query\n");
692 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
693 if (FAILED_UNEXPECTEDLY(hr
))
695 TRACE("Query failed\n");
700 TRACE("Before Tracking\n");
701 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
705 TRACE("Before InvokeCommand\n");
706 CMINVOKECOMMANDINFO cmi
= { 0 };
707 cmi
.cbSize
= sizeof(cmi
);
708 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
710 hr
= contextMenu
->InvokeCommand(&cmi
);
714 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
726 /**********************************************************
727 * ##### moving and sizing handling #####
732 /* There is nothing to do if themes are not enabled */
736 m_StartButton
.UpdateFont();
738 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
739 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
741 ERR("SPI_GETNONCLIENTMETRICS failed\n");
746 DeleteObject(m_Font
);
748 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
749 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
752 ERR("CreateFontIndirect failed\n");
756 SendMessage(m_Rebar
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
757 SendMessage(m_TaskSwitch
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
758 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
)
853 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
856 if (pos
> ABE_BOTTOM
)
859 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[pos
], 0, NULL
, TS_TRUE
, &size
);
860 if (FAILED_UNEXPECTEDLY(hr
))
866 rc
->bottom
-= size
.cy
;
872 rc
->right
-= size
.cx
;
880 VOID
MakeTrayRectWithSize(IN DWORD Position
,
881 IN
const SIZE
*pTraySize
,
887 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
891 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
895 pRect
->left
= pRect
->right
- pTraySize
->cx
;
900 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
905 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
906 IN
const RECT
*pScreen
,
907 IN
const SIZE
*pTraySize OPTIONAL
,
910 if (pTraySize
== NULL
)
911 pTraySize
= &m_TraySize
;
917 /* Move the border outside of the screen */
919 GetSystemMetrics(SM_CXEDGE
),
920 GetSystemMetrics(SM_CYEDGE
));
923 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
926 BOOL
IsPosHorizontal()
928 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
931 HMONITOR
CalculateValidSize(
940 //Horizontal = IsPosHorizontal();
942 szWnd
.cx
= pRect
->right
- pRect
->left
;
943 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
946 hMon
= GetScreenRectFromRect(
948 MONITOR_DEFAULTTONEAREST
);
950 /* Calculate the maximum size of the tray window and limit the window
951 size to half of the screen's size. */
952 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
953 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
954 if (szWnd
.cx
> szMax
.cx
)
956 if (szWnd
.cy
> szMax
.cy
)
959 /* FIXME - calculate */
961 GetTrayRectFromScreenRect(Position
,
971 GetMinimumWindowSize(
976 AdjustWindowRectEx(&rcMin
,
977 GetWindowLong(m_hWnd
,
980 GetWindowLong(m_hWnd
,
988 DWORD
GetDraggingRectFromPt(
991 OUT HMONITOR
*phMonitor
)
993 HMONITOR hMon
, hMonNew
;
994 DWORD PosH
, PosV
, Pos
;
995 SIZE DeltaPt
, ScreenOffset
;
1001 /* Determine the screen rectangle */
1002 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
1007 mi
.cbSize
= sizeof(mi
);
1008 if (!GetMonitorInfo(hMon
, &mi
))
1011 goto GetPrimaryScreenRect
;
1014 /* make left top corner of the screen zero based to
1015 make calculations easier */
1016 pt
.x
-= mi
.rcMonitor
.left
;
1017 pt
.y
-= mi
.rcMonitor
.top
;
1019 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1020 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1021 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1022 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1026 GetPrimaryScreenRect
:
1027 ScreenOffset
.cx
= 0;
1028 ScreenOffset
.cy
= 0;
1029 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1030 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1033 /* Calculate the nearest screen border */
1034 if (pt
.x
< rcScreen
.right
/ 2)
1041 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1045 if (pt
.y
< rcScreen
.bottom
/ 2)
1052 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1056 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1058 /* Fix the screen origin to be relative to the primary monitor again */
1059 OffsetRect(&rcScreen
,
1063 RECT rcPos
= m_TrayRects
[Pos
];
1065 hMonNew
= GetMonitorFromRect(&rcPos
);
1066 if (hMon
!= hMonNew
)
1070 /* Recalculate the rectangle, we're dragging to another monitor.
1071 We don't need to recalculate the rect on single monitor systems. */
1072 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1073 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1075 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1078 pRect
->left
+= m_AutoHideOffset
.cx
;
1079 pRect
->right
+= m_AutoHideOffset
.cx
;
1080 pRect
->top
+= m_AutoHideOffset
.cy
;
1081 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1087 /* The user is dragging the tray window on the same monitor. We don't need
1088 to recalculate the rectangle */
1092 pRect
->left
+= m_AutoHideOffset
.cx
;
1093 pRect
->right
+= m_AutoHideOffset
.cx
;
1094 pRect
->top
+= m_AutoHideOffset
.cy
;
1095 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1104 DWORD
GetDraggingRectFromRect(
1106 OUT HMONITOR
*phMonitor
)
1110 /* Calculate the center of the rectangle. We call
1111 GetDraggingRectFromPt to calculate a valid
1112 dragging rectangle */
1113 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1114 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1116 return GetDraggingRectFromPt(
1122 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1128 rcTray
.left
= pwp
->x
;
1129 rcTray
.top
= pwp
->y
;
1130 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1131 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1134 rcTray
.left
-= m_AutoHideOffset
.cx
;
1135 rcTray
.right
-= m_AutoHideOffset
.cx
;
1136 rcTray
.top
-= m_AutoHideOffset
.cy
;
1137 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1140 if (!EqualRect(&rcTray
,
1141 &m_TrayRects
[m_DraggingPosition
]))
1143 /* Recalculate the rectangle, the user dragged the tray
1144 window to another monitor or the window was somehow else
1146 m_DraggingPosition
= GetDraggingRectFromRect(
1148 &m_DraggingMonitor
);
1149 //m_TrayRects[DraggingPosition] = rcTray;
1152 //Monitor = CalculateValidSize(DraggingPosition,
1155 m_Monitor
= m_DraggingMonitor
;
1156 m_Position
= m_DraggingPosition
;
1159 m_TrayRects
[m_Position
] = rcTray
;
1162 else if (GetWindowRect(&rcTray
))
1166 if (!(pwp
->flags
& SWP_NOMOVE
))
1168 rcTray
.left
= pwp
->x
;
1169 rcTray
.top
= pwp
->y
;
1172 if (!(pwp
->flags
& SWP_NOSIZE
))
1174 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1175 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1178 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1180 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1187 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1192 rcTray
.left
-= m_AutoHideOffset
.cx
;
1193 rcTray
.right
-= m_AutoHideOffset
.cx
;
1194 rcTray
.top
-= m_AutoHideOffset
.cy
;
1195 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1197 m_TrayRects
[m_Position
] = rcTray
;
1201 /* If the user isn't resizing the tray window we need to make sure the
1202 new size or position is valid. this is to prevent changes to the window
1203 without user interaction. */
1204 rcTray
= m_TrayRects
[m_Position
];
1208 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1209 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1213 rcTray
.left
+= m_AutoHideOffset
.cx
;
1214 rcTray
.right
+= m_AutoHideOffset
.cx
;
1215 rcTray
.top
+= m_AutoHideOffset
.cy
;
1216 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1219 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1220 pwp
->x
= rcTray
.left
;
1221 pwp
->y
= rcTray
.top
;
1222 pwp
->cx
= m_TraySize
.cx
;
1223 pwp
->cy
= m_TraySize
.cy
;
1227 VOID
ApplyClipping(IN BOOL Clip
)
1229 RECT rcClip
, rcWindow
;
1232 if (GetWindowRect(&rcWindow
))
1234 /* Disable clipping on systems with only one monitor */
1235 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1242 GetScreenRect(m_Monitor
, &rcClip
);
1244 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1253 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1258 /* Set the clipping region or make sure the window isn't clipped
1259 by disabling it explicitly. */
1260 SetWindowRgn(hClipRgn
, TRUE
);
1264 VOID
ResizeWorkArea()
1266 #if !WIN7_DEBUG_MODE
1267 RECT rcTray
, rcWorkArea
;
1269 /* If monitor has changed then fix the previous monitors work area */
1270 if (m_PreviousMonitor
!= m_Monitor
)
1272 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1273 SystemParametersInfoW(SPI_SETWORKAREA
,
1279 rcTray
= m_TrayRects
[m_Position
];
1281 GetScreenRect(m_Monitor
, &rcWorkArea
);
1282 m_PreviousMonitor
= m_Monitor
;
1284 /* If AutoHide is false then change the workarea to exclude
1285 the area that the taskbar covers. */
1291 rcWorkArea
.top
= rcTray
.bottom
;
1294 rcWorkArea
.left
= rcTray
.right
;
1297 rcWorkArea
.right
= rcTray
.left
;
1300 rcWorkArea
.bottom
= rcTray
.top
;
1306 * Resize the current monitor work area. Win32k will also send
1307 * a WM_SIZE message to automatically resize the desktop.
1309 SystemParametersInfoW(SPI_SETWORKAREA
,
1316 VOID
CheckTrayWndPosition()
1320 rcTray
= m_TrayRects
[m_Position
];
1324 rcTray
.left
+= m_AutoHideOffset
.cx
;
1325 rcTray
.right
+= m_AutoHideOffset
.cx
;
1326 rcTray
.top
+= m_AutoHideOffset
.cy
;
1327 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1330 IUnknown_Exec(m_TrayBandSite
,
1332 DBID_BANDINFOCHANGED
,
1337 FitToRebar(&rcTray
);
1338 m_TrayRects
[m_Position
] = rcTray
;
1340 /* Move the tray window */
1344 rcTray
.right
- rcTray
.left
,
1345 rcTray
.bottom
- rcTray
.top
,
1346 SWP_NOZORDER
| SWP_NOACTIVATE
);
1350 ApplyClipping(TRUE
);
1353 typedef struct _TW_STUCKRECTS2
1361 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1363 VOID
RegLoadSettings()
1368 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1369 DWORD cbSize
= sizeof(sr
);
1370 SIZE StartBtnSize
= m_StartButton
.GetSize();
1372 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1373 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1374 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1375 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1377 if (SHGetValue(hkExplorer
,
1378 TEXT("StuckRects2"),
1382 &cbSize
) == ERROR_SUCCESS
&&
1383 sr
.cbSize
== sizeof(sr
))
1385 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1386 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1387 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1388 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1390 /* FIXME: Are there more flags? */
1393 m_Position
= ABE_LEFT
;
1395 if (sr
.Position
> ABE_BOTTOM
)
1396 m_Position
= ABE_BOTTOM
;
1398 m_Position
= sr
.Position
;
1401 /* Try to find out which monitor the tray window was located on last.
1402 Here we're only interested in the monitor screen that we think
1403 is the last one used. We're going to determine on which monitor
1404 we really are after calculating the docked position. */
1406 GetScreenRectFromRect(
1408 MONITOR_DEFAULTTONEAREST
);
1412 m_Position
= ABE_BOTTOM
;
1415 /* Use the minimum size of the taskbar, we'll use the start
1416 button as a minimum for now. Make sure we calculate the
1417 entire window size, not just the client size. However, we
1418 use a thinner border than a standard thick border, so that
1419 the start button and bands are not stuck to the screen border. */
1422 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1423 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1427 sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1428 sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1430 sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1433 /* Use the primary screen by default */
1436 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1437 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1438 GetScreenRectFromRect(
1440 MONITOR_DEFAULTTOPRIMARY
);
1445 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1450 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1452 /* Determine a minimum tray window rectangle. The "client" height is
1453 zero here since we cannot determine an optimal minimum width when
1454 loaded as a vertical tray window. We just need to make sure the values
1455 loaded from the registry are at least. The windows explorer behaves
1456 the same way, it allows the user to save a zero width vertical tray
1457 window, but not a zero height horizontal tray window. */
1460 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1461 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1465 WndSize
.cx
= StartBtnSize
.cx
;
1466 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1469 if (WndSize
.cx
< sr
.Size
.cx
)
1470 WndSize
.cx
= sr
.Size
.cx
;
1471 if (WndSize
.cy
< sr
.Size
.cy
)
1472 WndSize
.cy
= sr
.Size
.cy
;
1474 /* Save the calculated size */
1475 m_TraySize
= WndSize
;
1477 /* Calculate all docking rectangles. We need to do this here so they're
1478 initialized and dragging the tray window to another position gives
1480 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1482 GetTrayRectFromScreenRect(Pos
,
1486 // 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);
1489 /* Determine which monitor we are on. It shouldn't matter which docked
1490 position rectangle we use */
1491 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1494 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1497 SIZE TraySize
, StartSize
;
1498 POINT ptTrayNotify
= { 0, 0 };
1502 m_StartButton
.UpdateSize();
1503 if (prcClient
!= NULL
)
1505 rcClient
= *prcClient
;
1509 if (!GetClientRect(&rcClient
))
1511 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1516 Horizontal
= IsPosHorizontal();
1518 /* We're about to resize/move the start button, the rebar control and
1519 the tray notification control */
1520 dwp
= BeginDeferWindowPos(3);
1523 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1527 /* Limit the Start button width to the client width, if necessary */
1528 StartSize
= m_StartButton
.GetSize();
1529 if (StartSize
.cx
> rcClient
.right
)
1530 StartSize
.cx
= rcClient
.right
;
1532 if (m_StartButton
.m_hWnd
!= NULL
)
1534 /* Resize and reposition the button */
1535 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1541 SWP_NOZORDER
| SWP_NOACTIVATE
);
1544 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1549 /* Determine the size that the tray notification window needs */
1553 TraySize
.cy
= rcClient
.bottom
;
1557 TraySize
.cx
= rcClient
.right
;
1561 if (m_TrayNotify
!= NULL
&&
1562 SendMessage(m_TrayNotify
,
1563 TNWM_GETMINIMUMSIZE
,
1567 /* Move the tray notification window to the desired location */
1569 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1571 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1573 dwp
= ::DeferWindowPos(dwp
,
1580 SWP_NOZORDER
| SWP_NOACTIVATE
);
1583 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1588 /* Resize/Move the rebar control */
1589 if (m_Rebar
!= NULL
)
1591 POINT ptRebar
= { 0, 0 };
1594 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1598 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1599 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1600 szRebar
.cy
= rcClient
.bottom
;
1604 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1605 szRebar
.cx
= rcClient
.right
;
1606 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1609 dwp
= ::DeferWindowPos(dwp
,
1616 SWP_NOZORDER
| SWP_NOACTIVATE
);
1620 EndDeferWindowPos(dwp
);
1622 if (m_TaskSwitch
!= NULL
)
1624 /* Update the task switch window configuration */
1625 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1629 void FitToRebar(PRECT pRect
)
1631 /* Get the rect of the rebar */
1632 RECT rebarRect
, taskbarRect
;
1633 ::GetWindowRect(m_Rebar
, &rebarRect
);
1634 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1635 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1637 /* Calculate the difference of size of the taskbar and the rebar */
1639 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
1640 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
1642 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1646 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1647 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1648 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1651 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1652 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1653 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1657 /* FIXME: what to do here? */
1661 CalculateValidSize(m_Position
, pRect
);
1664 void PopupStartMenu()
1666 if (m_StartMenuPopup
!= NULL
)
1672 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1677 pt
.x
= rcExclude
.left
;
1678 pt
.y
= rcExclude
.top
;
1679 dwFlags
|= MPPF_TOP
;
1682 pt
.x
= rcExclude
.left
;
1683 pt
.y
= rcExclude
.bottom
;
1684 dwFlags
|= MPPF_BOTTOM
;
1687 pt
.x
= rcExclude
.right
;
1688 pt
.y
= rcExclude
.top
;
1689 dwFlags
|= MPPF_RIGHT
;
1692 pt
.x
= rcExclude
.left
;
1693 pt
.y
= rcExclude
.top
;
1694 dwFlags
|= MPPF_LEFT
;
1698 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1700 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1705 void ProcessMouseTracking()
1710 UINT state
= m_AutoHideState
;
1713 GetWindowRect(&rcCurrent
);
1714 over
= PtInRect(&rcCurrent
, pt
);
1716 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1723 if (state
== AUTOHIDE_HIDING
)
1725 TRACE("AutoHide cancelling hide.\n");
1726 m_AutoHideState
= AUTOHIDE_SHOWING
;
1727 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1729 else if (state
== AUTOHIDE_HIDDEN
)
1731 TRACE("AutoHide starting show.\n");
1732 m_AutoHideState
= AUTOHIDE_SHOWING
;
1733 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1738 if (state
== AUTOHIDE_SHOWING
)
1740 TRACE("AutoHide cancelling show.\n");
1741 m_AutoHideState
= AUTOHIDE_HIDING
;
1742 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1744 else if (state
== AUTOHIDE_SHOWN
)
1746 TRACE("AutoHide starting hide.\n");
1747 m_AutoHideState
= AUTOHIDE_HIDING
;
1748 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1751 KillTimer(TIMER_ID_MOUSETRACK
);
1755 void ProcessAutoHide()
1757 RECT rc
= m_TrayRects
[m_Position
];
1758 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1759 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1761 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
);
1763 switch (m_AutoHideState
)
1765 case AUTOHIDE_HIDING
:
1769 m_AutoHideOffset
.cy
= 0;
1770 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1771 if (m_AutoHideOffset
.cx
< -w
)
1772 m_AutoHideOffset
.cx
= -w
;
1775 m_AutoHideOffset
.cx
= 0;
1776 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1777 if (m_AutoHideOffset
.cy
< -h
)
1778 m_AutoHideOffset
.cy
= -h
;
1781 m_AutoHideOffset
.cy
= 0;
1782 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1783 if (m_AutoHideOffset
.cx
> w
)
1784 m_AutoHideOffset
.cx
= w
;
1787 m_AutoHideOffset
.cx
= 0;
1788 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1789 if (m_AutoHideOffset
.cy
> h
)
1790 m_AutoHideOffset
.cy
= h
;
1794 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1796 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1801 case AUTOHIDE_HIDDEN
:
1806 m_AutoHideOffset
.cx
= -w
;
1807 m_AutoHideOffset
.cy
= 0;
1810 m_AutoHideOffset
.cx
= 0;
1811 m_AutoHideOffset
.cy
= -h
;
1814 m_AutoHideOffset
.cx
= w
;
1815 m_AutoHideOffset
.cy
= 0;
1818 m_AutoHideOffset
.cx
= 0;
1819 m_AutoHideOffset
.cy
= h
;
1823 KillTimer(TIMER_ID_AUTOHIDE
);
1824 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1827 case AUTOHIDE_SHOWING
:
1828 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1830 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1832 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1834 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1838 m_AutoHideOffset
.cx
= 0;
1841 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1843 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1845 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1847 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1851 m_AutoHideOffset
.cy
= 0;
1854 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1856 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1861 case AUTOHIDE_SHOWN
:
1863 KillTimer(TIMER_ID_AUTOHIDE
);
1864 m_AutoHideState
= AUTOHIDE_SHOWN
;
1868 rc
.left
+= m_AutoHideOffset
.cx
;
1869 rc
.right
+= m_AutoHideOffset
.cx
;
1870 rc
.top
+= m_AutoHideOffset
.cy
;
1871 rc
.bottom
+= m_AutoHideOffset
.cy
;
1873 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1874 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1881 /**********************************************************
1882 * ##### taskbar drawing #####
1885 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1888 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1890 ASSERT(m_Position
<= ABE_BOTTOM
);
1894 GetClientRect(&rect
);
1895 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1901 int DrawSizerWithTheme(IN HRGN hRgn
)
1905 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1908 ASSERT(m_Position
<= ABE_BOTTOM
);
1910 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
1911 if (FAILED_UNEXPECTEDLY(hr
))
1914 GetWindowRect(&rect
);
1915 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1917 hdc
= GetWindowDC();
1922 rect
.left
= rect
.right
- size
.cx
;
1925 rect
.top
= rect
.bottom
- size
.cy
;
1928 rect
.right
= rect
.left
+ size
.cx
;
1932 rect
.bottom
= rect
.top
+ size
.cy
;
1936 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
1949 HRESULT STDMETHODCALLTYPE
Open()
1953 /* Check if there's already a window created and try to show it.
1954 If it was somehow destroyed just create a new tray window. */
1955 if (m_hWnd
!= NULL
&& IsWindow())
1960 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1962 dwExStyle
|= WS_EX_TOPMOST
;
1964 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1967 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1970 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1971 if (m_Position
!= (DWORD
) -1)
1972 rcWnd
= m_TrayRects
[m_Position
];
1974 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1977 /* Align all controls on the tray window */
1978 AlignControls(NULL
);
1980 /* Move the tray window to the right position and resize it if necessary */
1981 CheckTrayWndPosition();
1986 HRESULT STDMETHODCALLTYPE
Close()
1999 HWND STDMETHODCALLTYPE
GetHWND()
2004 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2006 return (m_hWnd
== hWnd
||
2007 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2010 BOOL STDMETHODCALLTYPE
IsHorizontal()
2012 return IsPosHorizontal();
2015 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2017 BOOL bPrevLock
= Locked
;
2019 if (Locked
!= bLock
)
2023 if (m_TrayBandSite
!= NULL
)
2025 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2035 /* Update cached tray sizes */
2036 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2038 RECT rcGripper
= {0};
2039 AdjustSizerRect(&rcGripper
, Pos
);
2043 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2044 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2045 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2046 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2050 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2051 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2052 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2053 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2057 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2059 ApplyClipping(TRUE
);
2070 /**********************************************************
2071 * ##### message handling #####
2074 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2078 ((ITrayWindow
*)this)->AddRef();
2080 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2082 /* Create the Start button */
2083 m_StartButton
.Create(m_hWnd
);
2085 /* Load the saved tray window settings */
2088 /* Create and initialize the start menu */
2089 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2090 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2092 /* Create the task band */
2093 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2094 if (FAILED_UNEXPECTEDLY(hRet
))
2097 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2098 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2099 if (FAILED_UNEXPECTEDLY(hRet
))
2102 /* Get the hwnd of the rebar */
2103 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2104 if (FAILED_UNEXPECTEDLY(hRet
))
2107 /* Get the hwnd of the tasks toolbar */
2108 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2109 if (FAILED_UNEXPECTEDLY(hRet
))
2112 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2114 /* Create the tray notification window */
2115 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2119 InitShellServices(&m_ShellServices
);
2123 m_AutoHideState
= AUTOHIDE_HIDING
;
2124 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2127 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2128 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2129 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2130 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2131 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2132 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2133 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2134 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2135 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2136 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2137 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2138 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2143 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2146 CloseThemeData(m_Theme
);
2148 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2152 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2156 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2158 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2163 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2165 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2167 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2169 AlignControls(NULL
);
2170 CheckTrayWndPosition();
2176 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2178 HDC hdc
= (HDC
) wParam
;
2186 return EraseBackgroundWithTheme(hdc
);
2189 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2191 /* Move the tray window to the right position and resize it if necessary */
2192 CheckTrayWndPosition();
2197 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2201 TRACE("WM_COPYDATA notify message received. Handling...\n");
2202 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2207 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2215 return DrawSizerWithTheme((HRGN
) wParam
);
2218 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2220 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2221 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2224 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2231 /* The user may not be able to resize the tray window.
2232 Pretend like the window is not sizeable when the user
2233 clicks on the border. */
2237 SetLastError(ERROR_SUCCESS
);
2238 if (GetClientRect(&rcClient
) &&
2239 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2241 pt
.x
= (SHORT
) LOWORD(lParam
);
2242 pt
.y
= (SHORT
) HIWORD(lParam
);
2244 if (PtInRect(&rcClient
,
2247 /* The user is trying to drag the tray window */
2251 /* Depending on the position of the tray window, allow only
2252 changing the border next to the monitor working area */
2256 if (pt
.y
> rcClient
.bottom
)
2260 if (pt
.x
> rcClient
.right
)
2264 if (pt
.x
< rcClient
.left
)
2269 if (pt
.y
< rcClient
.top
)
2278 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2281 PRECT pRect
= (PRECT
) lParam
;
2283 /* We need to ensure that an application can not accidently
2284 move the tray window (using SetWindowPos). However, we still
2285 need to be able to move the window in case the user wants to
2286 drag the tray window to another position or in case the user
2287 wants to resize the tray window. */
2288 if (!Locked
&& GetCursorPos(&ptCursor
))
2291 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2295 *pRect
= m_TrayRects
[m_Position
];
2299 pRect
->left
+= m_AutoHideOffset
.cx
;
2300 pRect
->right
+= m_AutoHideOffset
.cx
;
2301 pRect
->top
+= m_AutoHideOffset
.cy
;
2302 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2308 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2310 PRECT pRect
= (PRECT
) lParam
;
2318 *pRect
= m_TrayRects
[m_Position
];
2322 pRect
->left
+= m_AutoHideOffset
.cx
;
2323 pRect
->right
+= m_AutoHideOffset
.cx
;
2324 pRect
->top
+= m_AutoHideOffset
.cy
;
2325 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2331 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2333 ChangingWinPos((LPWINDOWPOS
) lParam
);
2337 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2340 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2343 /* Clip the tray window on multi monitor systems so the edges can't
2344 overlap into another monitor */
2345 ApplyClipping(TRUE
);
2347 if (!GetClientRect(&rcClient
))
2354 rcClient
.left
= rcClient
.top
= 0;
2355 rcClient
.right
= LOWORD(lParam
);
2356 rcClient
.bottom
= HIWORD(lParam
);
2359 AlignControls(&rcClient
);
2363 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2369 /* Remove the clipping on multi monitor systems while dragging around */
2370 ApplyClipping(FALSE
);
2375 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2380 /* Apply clipping */
2381 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2386 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2392 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2393 The tray window needs to handle this specially, since it normally doesn't have
2396 static const UINT uidDisableItem
[] = {
2406 /* temporarily enable the system menu */
2407 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2409 hSysMenu
= GetSystemMenu(FALSE
);
2410 if (hSysMenu
!= NULL
)
2412 /* Disable all items that are not relevant */
2413 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2415 EnableMenuItem(hSysMenu
,
2417 MF_BYCOMMAND
| MF_GRAYED
);
2420 EnableMenuItem(hSysMenu
,
2423 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2425 /* Display the system menu */
2429 m_StartButton
.m_hWnd
,
2430 m_Position
!= ABE_TOP
,
2434 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2438 /* revert the system menu window style */
2439 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2449 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2451 /* This handler implements the trick that makes the start button to
2452 get pressed when the user clicked left or below the button */
2454 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2455 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2460 m_StartButton
.GetWindowRect(&rcStartBtn
);
2461 GetWindowInfo(m_hWnd
, &wi
);
2468 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2474 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2477 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2478 pt
.x
> rcStartBtn
.right
)
2486 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2491 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2492 pt
.y
> rcStartBtn
.bottom
)
2506 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2508 /* We want the user to be able to get a context menu even on the nonclient
2509 area (including the sizing border)! */
2510 uMsg
= WM_CONTEXTMENU
;
2511 wParam
= (WPARAM
) m_hWnd
;
2513 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2516 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2518 LRESULT Ret
= FALSE
;
2519 POINT pt
, *ppt
= NULL
;
2520 HWND hWndExclude
= NULL
;
2522 /* Check if the administrator has forbidden access to context menus */
2523 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2526 pt
.x
= (SHORT
) LOWORD(lParam
);
2527 pt
.y
= (SHORT
) HIWORD(lParam
);
2529 if (pt
.x
!= -1 || pt
.y
!= -1)
2532 hWndExclude
= m_StartButton
.m_hWnd
;
2534 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2536 /* Make sure we can't track the context menu if the start
2537 menu is currently being shown */
2538 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2540 CComPtr
<IContextMenu
> ctxMenu
;
2541 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2542 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2547 /* See if the context menu should be handled by the task band site */
2548 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2551 POINT ptClient
= *ppt
;
2553 /* Convert the coordinates to client-coordinates */
2554 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2556 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2557 if (hWndAtPt
!= NULL
&&
2558 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2560 /* Check if the user clicked on the task switch window */
2562 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2564 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2565 if (hWndAtPt
== m_TaskSwitch
)
2566 goto HandleTrayContextMenu
;
2568 /* Forward the message to the task band site */
2569 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2572 goto HandleTrayContextMenu
;
2576 HandleTrayContextMenu
:
2577 /* Tray the default tray window context menu */
2578 CComPtr
<IContextMenu
> ctxMenu
;
2579 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2580 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2586 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2588 LRESULT Ret
= FALSE
;
2589 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2590 the rebar control! But we shouldn't forward messages that the band
2591 site doesn't handle, such as other controls (start button, tray window */
2593 HRESULT hr
= E_FAIL
;
2597 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2602 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2604 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2606 if (nmh
->hwndFrom
== m_TrayNotify
)
2611 /* Cause all controls to be aligned */
2612 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2620 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2622 /* We "handle" this message so users can't cause a weird maximize/restore
2623 window animation when double-clicking the tray window! */
2625 /* We should forward mouse messages to child windows here.
2626 Right now, this is only clock double-click */
2628 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2631 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2632 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2633 if (PtInRect(&rcClock
, ptClick
))
2635 //FIXME: use SHRunControlPanel
2636 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2642 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2648 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2651 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2652 if (FAILED_UNEXPECTEDLY(hr
))
2655 if (::IsWindowVisible(hwndStartMenu
))
2657 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2667 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2670 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2671 * to show the shutdown dialog. Also a WM_CLOSE message sent
2672 * by apps should show the dialog.
2674 return DoExitWindows();
2677 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2679 if (wParam
== SC_CLOSE
)
2681 return DoExitWindows();
2688 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2690 return HandleHotKey(wParam
);
2693 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2695 LRESULT Ret
= FALSE
;
2697 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2703 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2705 return HandleCommand(LOWORD(wParam
));
2710 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2714 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2720 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2722 if (wParam
== TIMER_ID_MOUSETRACK
)
2724 ProcessMouseTracking();
2726 else if (wParam
== TIMER_ID_AUTOHIDE
)
2735 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2738 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2739 if(!m_Theme
|| Locked
)
2750 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2751 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2756 rc
= &prms
->rgrc
[0];
2759 AdjustSizerRect(rc
, m_Position
);
2764 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2767 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2773 ::GetWindowRect(m_hWnd
, &rc
);
2777 rc
.bottom
- rc
.top
};
2779 as
->rcTarget
.right
- as
->rcTarget
.left
,
2780 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2782 as
->rcActual
.right
- as
->rcActual
.left
,
2783 as
->rcActual
.bottom
- as
->rcActual
.top
};
2786 szWindow
.cx
- szTarget
.cx
,
2787 szWindow
.cy
- szTarget
.cx
,
2793 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2796 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2799 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2800 rc
.left
= rc
.right
- szWindow
.cy
;
2803 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2804 rc
.top
= rc
.bottom
- szWindow
.cy
;
2808 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2815 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2817 BEGIN_MSG_MAP(CTrayWindow
)
2818 if (m_StartMenuBand
!= NULL
)
2825 Msg
.wParam
= wParam
;
2826 Msg
.lParam
= lParam
;
2828 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2833 wParam
= Msg
.wParam
;
2834 lParam
= Msg
.lParam
;
2836 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2837 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2838 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2839 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2840 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2841 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2842 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2843 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2844 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2845 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2846 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2847 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2848 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2849 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2850 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2851 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2852 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2853 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2854 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2855 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2856 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2857 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2858 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
2859 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2860 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2861 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2862 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2863 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2864 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2865 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2866 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2867 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2868 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2869 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2873 /*****************************************************************************/
2875 VOID
TrayProcessMessages()
2879 /* FIXME: We should keep a reference here... */
2881 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2883 if (Msg
.message
== WM_QUIT
)
2886 if (m_StartMenuBand
== NULL
||
2887 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2889 TranslateMessage(&Msg
);
2890 DispatchMessage(&Msg
);
2895 VOID
TrayMessageLoop()
2900 /* FIXME: We should keep a reference here... */
2904 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2906 if (!Ret
|| Ret
== -1)
2909 if (m_StartMenuBand
== NULL
||
2910 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2912 TranslateMessage(&Msg
);
2913 DispatchMessage(&Msg
);
2921 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2922 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2923 * The reason we implement it is because we have to use SHCreateDesktop() so
2924 * that the shell provides the desktop window and all the features that come
2925 * with it (especially positioning of desktop icons)
2928 virtual ULONG STDMETHODCALLTYPE
GetState()
2930 /* FIXME: Return ABS_ flags? */
2931 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2935 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2937 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2938 *phWndTray
= m_hWnd
;
2942 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2944 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2946 m_DesktopWnd
= hWndDesktop
;
2950 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2952 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2956 virtual HRESULT
RaiseStartButton()
2958 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2962 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
2965 return E_INVALIDARG
;
2970 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
2977 m_Position
= (DWORD
) -1;
2980 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2982 DECLARE_PROTECT_FINAL_CONSTRUCT()
2983 BEGIN_COM_MAP(CTrayWindow
)
2984 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2985 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2986 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
2990 class CTrayWindowCtxMenu
:
2991 public CComCoClass
<CTrayWindowCtxMenu
>,
2992 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2996 CComPtr
<CTrayWindow
> TrayWnd
;
2997 CComPtr
<IContextMenu
> pcm
;
3000 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3002 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3003 this->hWndOwner
= hWndOwner
;
3007 virtual HRESULT STDMETHODCALLTYPE
3008 QueryContextMenu(HMENU hPopup
,
3014 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3017 return HRESULT_FROM_WIN32(GetLastError());
3019 int count
= ::GetMenuItemCount(menubase
);
3021 for (int i
= 0; i
< count
; i
++)
3025 MENUITEMINFOW mii
= { 0 };
3026 mii
.cbSize
= sizeof(mii
);
3027 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3028 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3029 mii
.dwTypeData
= label
;
3030 mii
.cch
= _countof(label
);
3031 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3033 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3035 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3038 ::DestroyMenu(menubase
);
3040 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3047 CheckMenuItem(hPopup
,
3049 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3051 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3053 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3061 WARN("AddContextMenus failed.\n");
3069 virtual HRESULT STDMETHODCALLTYPE
3070 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3072 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3075 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3077 CMINVOKECOMMANDINFO cmici
= { 0 };
3081 /* Setup and invoke the shell command */
3082 cmici
.cbSize
= sizeof(cmici
);
3083 cmici
.hwnd
= hWndOwner
;
3084 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- ID_SHELL_CMD_FIRST
);
3085 cmici
.nShow
= SW_NORMAL
;
3087 pcm
->InvokeCommand(&cmici
);
3092 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3099 virtual HRESULT STDMETHODCALLTYPE
3100 GetCommandString(UINT_PTR idCmd
,
3109 CTrayWindowCtxMenu()
3113 virtual ~CTrayWindowCtxMenu()
3117 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3118 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3122 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3124 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3125 mnu
->Initialize(TrayWnd
, hWndOwner
);
3130 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3132 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3134 return E_OUTOFMEMORY
;
3139 *ppTray
= (ITrayWindow
*) Tray
;
3145 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3147 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3148 return TrayWindow
->RaiseStartButton();
3151 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3153 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3154 TrayWindow
->TrayProcessMessages();
3157 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3159 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3160 TrayWindow
->TrayMessageLoop();