4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * this library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * this library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
26 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
28 #define TIMER_ID_AUTOHIDE 1
29 #define TIMER_ID_MOUSETRACK 2
30 #define MOUSETRACK_INTERVAL 100
31 #define AUTOHIDE_DELAY_HIDE 2000
32 #define AUTOHIDE_DELAY_SHOW 50
33 #define AUTOHIDE_INTERVAL_ANIMATING 10
35 #define AUTOHIDE_SPEED_SHOW 10
36 #define AUTOHIDE_SPEED_HIDE 1
38 #define AUTOHIDE_HIDDEN 0
39 #define AUTOHIDE_SHOWING 1
40 #define AUTOHIDE_SHOWN 2
41 #define AUTOHIDE_HIDING 3
43 #define IDHK_RUN 0x1f4
44 #define IDHK_MINIMIZE_ALL 0x1f5
45 #define IDHK_RESTORE_ALL 0x1f6
46 #define IDHK_HELP 0x1f7
47 #define IDHK_EXPLORE 0x1f8
48 #define IDHK_FIND 0x1f9
49 #define IDHK_FIND_COMPUTER 0x1fa
50 #define IDHK_NEXT_TASK 0x1fb
51 #define IDHK_PREV_TASK 0x1fc
52 #define IDHK_SYS_PROPERTIES 0x1fd
53 #define IDHK_DESKTOP 0x1fe
54 #define IDHK_PAGER 0x1ff
56 static LONG TrayWndCount
= 0;
58 static const WCHAR szTrayWndClass
[] = L
"Shell_TrayWnd";
64 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
69 HIMAGELIST m_ImageList
;
82 virtual ~CStartButton()
84 if (m_ImageList
!= NULL
)
85 ImageList_Destroy(m_ImageList
);
101 VOID
UpdateSize(IN HBITMAP hbmStart
= NULL
)
103 SIZE Size
= { 0, 0 };
105 if (m_ImageList
== NULL
||
106 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
108 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
) + GetSystemMetrics(SM_CYCAPTION
) * 3;
109 Size
.cy
= 2 * GetSystemMetrics(SM_CYEDGE
) + GetSystemMetrics(SM_CYCAPTION
);
112 /* Save the size of the start button */
118 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
120 /* Get the system fonts, we use the caption font, always bold, though. */
121 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
122 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
124 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
125 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
128 SetFont(m_Font
, FALSE
);
130 m_ImageList
= ImageList_LoadImageW(hExplorerInstance
,
131 MAKEINTRESOURCEW(IDB_START
),
134 LR_LOADTRANSPARENT
| LR_CREATEDIBSECTION
);
136 BUTTON_IMAGELIST bil
= {m_ImageList
, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT
};
137 SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
);
141 HWND
Create(HWND hwndParent
)
143 WCHAR szStartCaption
[32];
144 if (!LoadStringW(hExplorerInstance
,
147 _countof(szStartCaption
)))
149 wcscpy(szStartCaption
, L
"Start");
152 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| BS_PUSHBUTTON
| BS_LEFT
| BS_VCENTER
;
154 m_hWnd
= CreateWindowEx(
161 (HMENU
) IDC_STARTBTN
,
173 public CComCoClass
<CTrayWindow
>,
174 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
175 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
177 public IShellDesktopTray
179 CStartButton m_StartButton
;
181 CComPtr
<IMenuBand
> m_StartMenuBand
;
182 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
194 CTrayNotifyWnd
* m_TrayNotifyInstance
;
198 HMONITOR m_PreviousMonitor
;
199 DWORD m_DraggingPosition
;
200 HMONITOR m_DraggingMonitor
;
205 HWND m_TrayPropertiesOwner
;
206 HWND m_RunFileDlgOwner
;
208 UINT m_AutoHideState
;
209 SIZE m_AutoHideOffset
;
210 TRACKMOUSEEVENT m_MouseTrackingInfo
;
212 HDPA m_ShellServices
;
215 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
223 DWORD AlwaysOnTop
: 1;
224 DWORD SmSmallIcons
: 1;
229 DWORD InSizeMove
: 1;
230 DWORD IsDragging
: 1;
231 DWORD NewPosSize
: 1;
247 m_PreviousMonitor(NULL
),
248 m_DraggingPosition(0),
249 m_DraggingMonitor(NULL
),
250 m_TrayPropertiesOwner(NULL
),
251 m_RunFileDlgOwner(NULL
),
252 m_AutoHideState(NULL
),
253 m_ShellServices(NULL
),
256 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
257 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
258 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
259 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
262 virtual ~CTrayWindow()
264 if (m_ShellServices
!= NULL
)
266 ShutdownShellServices(m_ShellServices
);
267 m_ShellServices
= NULL
;
270 if (m_CaptionFont
!= NULL
)
272 DeleteObject(m_CaptionFont
);
273 m_CaptionFont
= NULL
;
278 DeleteObject(m_Font
);
284 CloseThemeData(m_Theme
);
288 if (InterlockedDecrement(&TrayWndCount
) == 0)
296 /**********************************************************
297 * ##### command handling #####
300 HRESULT
ExecResourceCmd(int id
)
302 WCHAR szCommand
[256];
303 WCHAR
*pszParameters
;
305 if (!LoadStringW(hExplorerInstance
,
308 _countof(szCommand
)))
313 pszParameters
= wcschr(szCommand
, L
'>');
320 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
324 LRESULT
DoExitWindows()
326 ExitWindowsDialog(m_hWnd
);
330 DWORD WINAPI
RunFileDlgThread()
335 m_StartButton
.GetWindowRect(&posRect
);
337 hwnd
= CreateWindowEx(0,
340 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
343 posRect
.right
- posRect
.left
,
344 posRect
.bottom
- posRect
.top
,
350 m_RunFileDlgOwner
= hwnd
;
352 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
354 m_RunFileDlgOwner
= NULL
;
355 ::DestroyWindow(hwnd
);
360 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
362 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
363 return This
->RunFileDlgThread();
366 void DisplayRunFileDlg()
369 if (m_RunFileDlgOwner
)
371 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
372 if (hRunDlg
!= NULL
&&
373 hRunDlg
!= m_RunFileDlgOwner
)
375 SetForegroundWindow(hRunDlg
);
380 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
383 DWORD WINAPI
TrayPropertiesThread()
388 m_StartButton
.GetWindowRect(&posRect
);
389 hwnd
= CreateWindowEx(0,
392 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
395 posRect
.right
- posRect
.left
,
396 posRect
.bottom
- posRect
.top
,
402 m_TrayPropertiesOwner
= hwnd
;
404 DisplayTrayProperties(hwnd
);
406 m_TrayPropertiesOwner
= NULL
;
407 ::DestroyWindow(hwnd
);
412 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
414 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
416 return This
->TrayPropertiesThread();
419 HWND STDMETHODCALLTYPE
DisplayProperties()
423 if (m_TrayPropertiesOwner
)
425 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
426 if (hTrayProp
!= NULL
&&
427 hTrayProp
!= m_TrayPropertiesOwner
)
429 SetForegroundWindow(hTrayProp
);
434 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
438 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
440 WCHAR szDir
[MAX_PATH
];
442 if (SHGetSpecialFolderPath(hWndOwner
,
444 CSIDL_COMMON_STARTMENU
,
447 ShellExecute(hWndOwner
,
456 VOID
OpenTaskManager(IN HWND hWndOwner
)
458 ShellExecute(hWndOwner
,
466 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
470 case ID_SHELL_CMD_PROPERTIES
:
474 case ID_SHELL_CMD_OPEN_ALL_USERS
:
475 OpenCommonStartMenuDirectory(m_hWnd
,
479 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
480 OpenCommonStartMenuDirectory(m_hWnd
,
485 if (SHRestricted(REST_CLASSICSHELL
) == 0)
491 case ID_SHELL_CMD_OPEN_TASKMGR
:
492 OpenTaskManager(m_hWnd
);
495 case ID_SHELL_CMD_UNDO_ACTION
:
498 case ID_SHELL_CMD_SHOW_DESKTOP
:
501 case ID_SHELL_CMD_TILE_WND_H
:
502 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
505 case ID_SHELL_CMD_TILE_WND_V
:
506 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
509 case ID_SHELL_CMD_CASCADE_WND
:
510 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
513 case ID_SHELL_CMD_CUST_NOTIF
:
516 case ID_SHELL_CMD_ADJUST_DAT
:
517 //FIXME: Use SHRunControlPanel
518 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
522 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
529 LRESULT
HandleHotKey(DWORD id
)
537 ExecResourceCmd(IDS_HELP_COMMAND
);
540 //FIXME: We don't support this yet:
541 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
542 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
545 SHFindFiles(NULL
, NULL
);
547 case IDHK_FIND_COMPUTER
:
548 SHFindComputer(NULL
, NULL
);
550 case IDHK_SYS_PROPERTIES
:
551 //FIXME: Use SHRunControlPanel
552 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
558 case IDHK_MINIMIZE_ALL
:
560 case IDHK_RESTORE_ALL
:
571 LRESULT
HandleCommand(UINT uCommand
)
575 case IDM_TASKBARANDSTARTMENU
:
580 SHFindFiles(NULL
, NULL
);
583 case IDM_HELPANDSUPPORT
:
584 ExecResourceCmd(IDS_HELP_COMMAND
);
591 /* FIXME: Handle these commands as well */
592 case IDM_SYNCHRONIZE
:
594 case IDM_UNDOCKCOMPUTER
:
598 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
612 IN POINT
*ppt OPTIONAL
,
613 IN HWND hwndExclude OPTIONAL
,
615 IN BOOL IsContextMenu
)
617 TPMPARAMS tmp
, *ptmp
= NULL
;
622 if (hwndExclude
!= NULL
)
624 /* Get the client rectangle and map it to screen coordinates */
625 if (::GetClientRect(hwndExclude
,
627 ::MapWindowPoints(hwndExclude
,
629 (LPPOINT
) &tmp
.rcExclude
,
639 GetClientRect(&tmp
.rcExclude
) &&
642 (LPPOINT
) &tmp
.rcExclude
,
650 /* NOTE: TrackPopupMenuEx will eventually align the track position
651 for us, no need to take care of it here as long as the
652 coordinates are somewhere within the exclusion rectangle */
653 pt
.x
= ptmp
->rcExclude
.left
;
654 pt
.y
= ptmp
->rcExclude
.top
;
662 tmp
.cbSize
= sizeof(tmp
);
664 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
665 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
667 fuFlags
|= TPM_RIGHTBUTTON
;
669 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
671 cmdId
= TrackPopupMenuEx(hMenu
,
681 HRESULT
TrackCtxMenu(
682 IN IContextMenu
* contextMenu
,
683 IN POINT
*ppt OPTIONAL
,
684 IN HWND hwndExclude OPTIONAL
,
686 IN PVOID Context OPTIONAL
)
692 HMENU popup
= CreatePopupMenu();
697 TRACE("Before Query\n");
698 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
699 if (FAILED_UNEXPECTEDLY(hr
))
701 TRACE("Query failed\n");
706 TRACE("Before Tracking\n");
707 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
711 TRACE("Before InvokeCommand\n");
712 CMINVOKECOMMANDINFO cmi
= { 0 };
713 cmi
.cbSize
= sizeof(cmi
);
714 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
716 hr
= contextMenu
->InvokeCommand(&cmi
);
720 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
732 /**********************************************************
733 * ##### moving and sizing handling #####
736 BOOL
UpdateNonClientMetrics()
738 NONCLIENTMETRICS ncm
;
739 ncm
.cbSize
= sizeof(ncm
);
740 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
743 DeleteObject(m_Font
);
745 m_Font
= CreateFontIndirect(&ncm
.lfMessageFont
);
752 VOID
SetWindowsFont()
754 if (m_TrayNotify
!= NULL
)
756 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
760 HMONITOR
GetScreenRectFromRect(
767 mi
.cbSize
= sizeof(mi
);
768 hMon
= MonitorFromRect(pRect
, dwFlags
);
770 GetMonitorInfo(hMon
, &mi
))
772 *pRect
= mi
.rcMonitor
;
778 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
779 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
787 HMONITOR
GetMonitorFromRect(
788 IN
const RECT
*pRect
)
792 /* In case the monitor sizes or saved sizes differ a bit (probably
793 not a lot, only so the tray window overlaps into another monitor
794 now), minimize the risk that we determine a wrong monitor by
795 using the center point of the tray window if we can't determine
796 it using the rectangle. */
797 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
802 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
803 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
805 /* be less error-prone, find the nearest monitor */
806 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
812 HMONITOR
GetScreenRect(
813 IN HMONITOR hMonitor
,
816 HMONITOR hMon
= NULL
;
818 if (hMonitor
!= NULL
)
822 mi
.cbSize
= sizeof(mi
);
823 if (!GetMonitorInfo(hMonitor
, &mi
))
825 /* Hm, the monitor is gone? Try to find a monitor where it
826 could be located now */
827 hMon
= GetMonitorFromRect(pRect
);
829 !GetMonitorInfo(hMon
, &mi
))
836 *pRect
= mi
.rcMonitor
;
843 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
844 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
850 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
855 rc
->bottom
-= GetSystemMetrics(SM_CXSIZEFRAME
);
858 rc
->top
+= GetSystemMetrics(SM_CXSIZEFRAME
);
861 rc
->right
-= GetSystemMetrics(SM_CYSIZEFRAME
);
864 rc
->left
+= GetSystemMetrics(SM_CYSIZEFRAME
);
870 VOID
MakeTrayRectWithSize(IN DWORD Position
,
871 IN
const SIZE
*pTraySize
,
877 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
881 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
885 pRect
->left
= pRect
->right
- pTraySize
->cx
;
890 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
895 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
896 IN
const RECT
*pScreen
,
897 IN
const SIZE
*pTraySize OPTIONAL
,
900 if (pTraySize
== NULL
)
901 pTraySize
= &m_TraySize
;
907 /* Move the border outside of the screen */
909 GetSystemMetrics(SM_CXEDGE
),
910 GetSystemMetrics(SM_CYEDGE
));
913 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
916 BOOL
IsPosHorizontal()
918 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
921 HMONITOR
CalculateValidSize(
930 //Horizontal = IsPosHorizontal();
932 szWnd
.cx
= pRect
->right
- pRect
->left
;
933 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
936 hMon
= GetScreenRectFromRect(
938 MONITOR_DEFAULTTONEAREST
);
940 /* Calculate the maximum size of the tray window and limit the window
941 size to half of the screen's size. */
942 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
943 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
944 if (szWnd
.cx
> szMax
.cx
)
946 if (szWnd
.cy
> szMax
.cy
)
949 /* FIXME - calculate */
951 GetTrayRectFromScreenRect(Position
,
961 GetMinimumWindowSize(
966 AdjustWindowRectEx(&rcMin
,
967 GetWindowLong(m_hWnd
,
970 GetWindowLong(m_hWnd
,
978 DWORD
GetDraggingRectFromPt(
981 OUT HMONITOR
*phMonitor
)
983 HMONITOR hMon
, hMonNew
;
984 DWORD PosH
, PosV
, Pos
;
985 SIZE DeltaPt
, ScreenOffset
;
991 /* Determine the screen rectangle */
992 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
997 mi
.cbSize
= sizeof(mi
);
998 if (!GetMonitorInfo(hMon
, &mi
))
1001 goto GetPrimaryScreenRect
;
1004 /* make left top corner of the screen zero based to
1005 make calculations easier */
1006 pt
.x
-= mi
.rcMonitor
.left
;
1007 pt
.y
-= mi
.rcMonitor
.top
;
1009 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1010 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1011 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1012 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1016 GetPrimaryScreenRect
:
1017 ScreenOffset
.cx
= 0;
1018 ScreenOffset
.cy
= 0;
1019 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1020 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1023 /* Calculate the nearest screen border */
1024 if (pt
.x
< rcScreen
.right
/ 2)
1031 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1035 if (pt
.y
< rcScreen
.bottom
/ 2)
1042 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1046 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1048 /* Fix the screen origin to be relative to the primary monitor again */
1049 OffsetRect(&rcScreen
,
1053 RECT rcPos
= m_TrayRects
[Pos
];
1055 hMonNew
= GetMonitorFromRect(&rcPos
);
1056 if (hMon
!= hMonNew
)
1060 /* Recalculate the rectangle, we're dragging to another monitor.
1061 We don't need to recalculate the rect on single monitor systems. */
1062 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1063 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1065 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1068 pRect
->left
+= m_AutoHideOffset
.cx
;
1069 pRect
->right
+= m_AutoHideOffset
.cx
;
1070 pRect
->top
+= m_AutoHideOffset
.cy
;
1071 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1077 /* The user is dragging the tray window on the same monitor. We don't need
1078 to recalculate the rectangle */
1082 pRect
->left
+= m_AutoHideOffset
.cx
;
1083 pRect
->right
+= m_AutoHideOffset
.cx
;
1084 pRect
->top
+= m_AutoHideOffset
.cy
;
1085 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1094 DWORD
GetDraggingRectFromRect(
1096 OUT HMONITOR
*phMonitor
)
1100 /* Calculate the center of the rectangle. We call
1101 GetDraggingRectFromPt to calculate a valid
1102 dragging rectangle */
1103 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1104 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1106 return GetDraggingRectFromPt(
1112 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1118 rcTray
.left
= pwp
->x
;
1119 rcTray
.top
= pwp
->y
;
1120 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1121 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1124 rcTray
.left
-= m_AutoHideOffset
.cx
;
1125 rcTray
.right
-= m_AutoHideOffset
.cx
;
1126 rcTray
.top
-= m_AutoHideOffset
.cy
;
1127 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1130 if (!EqualRect(&rcTray
,
1131 &m_TrayRects
[m_DraggingPosition
]))
1133 /* Recalculate the rectangle, the user dragged the tray
1134 window to another monitor or the window was somehow else
1136 m_DraggingPosition
= GetDraggingRectFromRect(
1138 &m_DraggingMonitor
);
1139 //m_TrayRects[DraggingPosition] = rcTray;
1142 //Monitor = CalculateValidSize(DraggingPosition,
1145 m_Monitor
= m_DraggingMonitor
;
1146 m_Position
= m_DraggingPosition
;
1149 m_TrayRects
[m_Position
] = rcTray
;
1152 else if (GetWindowRect(&rcTray
))
1156 if (!(pwp
->flags
& SWP_NOMOVE
))
1158 rcTray
.left
= pwp
->x
;
1159 rcTray
.top
= pwp
->y
;
1162 if (!(pwp
->flags
& SWP_NOSIZE
))
1164 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1165 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1168 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1170 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1177 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1182 rcTray
.left
-= m_AutoHideOffset
.cx
;
1183 rcTray
.right
-= m_AutoHideOffset
.cx
;
1184 rcTray
.top
-= m_AutoHideOffset
.cy
;
1185 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1187 m_TrayRects
[m_Position
] = rcTray
;
1191 /* If the user isn't resizing the tray window we need to make sure the
1192 new size or position is valid. this is to prevent changes to the window
1193 without user interaction. */
1194 rcTray
= m_TrayRects
[m_Position
];
1198 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1199 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1203 rcTray
.left
+= m_AutoHideOffset
.cx
;
1204 rcTray
.right
+= m_AutoHideOffset
.cx
;
1205 rcTray
.top
+= m_AutoHideOffset
.cy
;
1206 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1209 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1210 pwp
->x
= rcTray
.left
;
1211 pwp
->y
= rcTray
.top
;
1212 pwp
->cx
= m_TraySize
.cx
;
1213 pwp
->cy
= m_TraySize
.cy
;
1217 VOID
ApplyClipping(IN BOOL Clip
)
1219 RECT rcClip
, rcWindow
;
1222 if (GetWindowRect(&rcWindow
))
1224 /* Disable clipping on systems with only one monitor */
1225 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1232 GetScreenRect(m_Monitor
, &rcClip
);
1234 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1243 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1248 /* Set the clipping region or make sure the window isn't clipped
1249 by disabling it explicitly. */
1250 SetWindowRgn(hClipRgn
, TRUE
);
1254 VOID
ResizeWorkArea()
1256 #if !WIN7_DEBUG_MODE
1257 RECT rcTray
, rcWorkArea
;
1259 /* If monitor has changed then fix the previous monitors work area */
1260 if (m_PreviousMonitor
!= m_Monitor
)
1262 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1263 SystemParametersInfoW(SPI_SETWORKAREA
,
1269 rcTray
= m_TrayRects
[m_Position
];
1271 GetScreenRect(m_Monitor
, &rcWorkArea
);
1272 m_PreviousMonitor
= m_Monitor
;
1274 /* If AutoHide is false then change the workarea to exclude
1275 the area that the taskbar covers. */
1281 rcWorkArea
.top
= rcTray
.bottom
;
1284 rcWorkArea
.left
= rcTray
.right
;
1287 rcWorkArea
.right
= rcTray
.left
;
1290 rcWorkArea
.bottom
= rcTray
.top
;
1296 * Resize the current monitor work area. Win32k will also send
1297 * a WM_SIZE message to automatically resize the desktop.
1299 SystemParametersInfoW(SPI_SETWORKAREA
,
1306 VOID
CheckTrayWndPosition()
1310 rcTray
= m_TrayRects
[m_Position
];
1314 rcTray
.left
+= m_AutoHideOffset
.cx
;
1315 rcTray
.right
+= m_AutoHideOffset
.cx
;
1316 rcTray
.top
+= m_AutoHideOffset
.cy
;
1317 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1320 /* Move the tray window */
1324 rcTray
.right
- rcTray
.left
,
1325 rcTray
.bottom
- rcTray
.top
,
1326 SWP_NOZORDER
| SWP_NOACTIVATE
);
1330 ApplyClipping(TRUE
);
1333 typedef struct _TW_STUCKRECTS2
1341 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1343 VOID
RegLoadSettings()
1348 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1349 DWORD cbSize
= sizeof(sr
);
1350 SIZE StartBtnSize
= m_StartButton
.GetSize();
1352 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1353 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1354 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1355 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1357 if (SHGetValue(hkExplorer
,
1358 TEXT("StuckRects2"),
1362 &cbSize
) == ERROR_SUCCESS
&&
1363 sr
.cbSize
== sizeof(sr
))
1365 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1366 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1367 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1368 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1370 /* FIXME: Are there more flags? */
1373 m_Position
= ABE_LEFT
;
1375 if (sr
.Position
> ABE_BOTTOM
)
1376 m_Position
= ABE_BOTTOM
;
1378 m_Position
= sr
.Position
;
1381 /* Try to find out which monitor the tray window was located on last.
1382 Here we're only interested in the monitor screen that we think
1383 is the last one used. We're going to determine on which monitor
1384 we really are after calculating the docked position. */
1386 GetScreenRectFromRect(
1388 MONITOR_DEFAULTTONEAREST
);
1392 m_Position
= ABE_BOTTOM
;
1395 /* Use the minimum size of the taskbar, we'll use the start
1396 button as a minimum for now. Make sure we calculate the
1397 entire window size, not just the client size. However, we
1398 use a thinner border than a standard thick border, so that
1399 the start button and bands are not stuck to the screen border. */
1400 if(!IsThemeActive())
1402 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1403 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1407 sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1408 sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1410 sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1413 /* Use the primary screen by default */
1416 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1417 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1418 GetScreenRectFromRect(
1420 MONITOR_DEFAULTTOPRIMARY
);
1425 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1430 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1432 /* Determine a minimum tray window rectangle. The "client" height is
1433 zero here since we cannot determine an optimal minimum width when
1434 loaded as a vertical tray window. We just need to make sure the values
1435 loaded from the registry are at least. The windows explorer behaves
1436 the same way, it allows the user to save a zero width vertical tray
1437 window, but not a zero height horizontal tray window. */
1438 if(!IsThemeActive())
1440 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1441 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1445 WndSize
.cx
= StartBtnSize
.cx
;
1446 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1449 if (WndSize
.cx
< sr
.Size
.cx
)
1450 WndSize
.cx
= sr
.Size
.cx
;
1451 if (WndSize
.cy
< sr
.Size
.cy
)
1452 WndSize
.cy
= sr
.Size
.cy
;
1454 /* Save the calculated size */
1455 m_TraySize
= WndSize
;
1457 /* Calculate all docking rectangles. We need to do this here so they're
1458 initialized and dragging the tray window to another position gives
1460 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1462 GetTrayRectFromScreenRect(Pos
,
1466 // 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);
1469 /* Determine which monitor we are on. It shouldn't matter which docked
1470 position rectangle we use */
1471 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1474 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1477 SIZE TraySize
, StartSize
;
1478 POINT ptTrayNotify
= { 0, 0 };
1482 m_StartButton
.UpdateSize();
1483 if (prcClient
!= NULL
)
1485 rcClient
= *prcClient
;
1489 if (!GetClientRect(&rcClient
))
1491 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1496 Horizontal
= IsPosHorizontal();
1498 /* We're about to resize/move the start button, the rebar control and
1499 the tray notification control */
1500 dwp
= BeginDeferWindowPos(3);
1503 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1507 /* Limit the Start button width to the client width, if necessary */
1508 StartSize
= m_StartButton
.GetSize();
1509 if (StartSize
.cx
> rcClient
.right
)
1510 StartSize
.cx
= rcClient
.right
;
1512 if (m_StartButton
.m_hWnd
!= NULL
)
1514 /* Resize and reposition the button */
1515 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1521 SWP_NOZORDER
| SWP_NOACTIVATE
);
1524 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1529 /* Determine the size that the tray notification window needs */
1533 TraySize
.cy
= rcClient
.bottom
;
1537 TraySize
.cx
= rcClient
.right
;
1541 if (m_TrayNotify
!= NULL
&&
1542 SendMessage(m_TrayNotify
,
1543 TNWM_GETMINIMUMSIZE
,
1547 /* Move the tray notification window to the desired location */
1549 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1551 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1553 dwp
= ::DeferWindowPos(dwp
,
1560 SWP_NOZORDER
| SWP_NOACTIVATE
);
1563 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1568 /* Resize/Move the rebar control */
1569 if (m_Rebar
!= NULL
)
1571 POINT ptRebar
= { 0, 0 };
1574 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1578 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1579 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1580 szRebar
.cy
= rcClient
.bottom
;
1584 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1585 szRebar
.cx
= rcClient
.right
;
1586 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1589 dwp
= ::DeferWindowPos(dwp
,
1596 SWP_NOZORDER
| SWP_NOACTIVATE
);
1600 EndDeferWindowPos(dwp
);
1602 if (m_TaskSwitch
!= NULL
)
1604 /* Update the task switch window configuration */
1605 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1609 void PopupStartMenu()
1611 if (m_StartMenuPopup
!= NULL
)
1617 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1622 pt
.x
= rcExclude
.left
;
1623 pt
.y
= rcExclude
.top
;
1624 dwFlags
|= MPPF_TOP
;
1627 pt
.x
= rcExclude
.left
;
1628 pt
.y
= rcExclude
.bottom
;
1629 dwFlags
|= MPPF_BOTTOM
;
1632 pt
.x
= rcExclude
.right
;
1633 pt
.y
= rcExclude
.top
;
1634 dwFlags
|= MPPF_RIGHT
;
1637 pt
.x
= rcExclude
.left
;
1638 pt
.y
= rcExclude
.top
;
1639 dwFlags
|= MPPF_LEFT
;
1643 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1645 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1650 void ProcessMouseTracking()
1655 UINT state
= m_AutoHideState
;
1658 GetWindowRect(&rcCurrent
);
1659 over
= PtInRect(&rcCurrent
, pt
);
1661 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1668 if (state
== AUTOHIDE_HIDING
)
1670 TRACE("AutoHide cancelling hide.\n");
1671 m_AutoHideState
= AUTOHIDE_SHOWING
;
1672 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1674 else if (state
== AUTOHIDE_HIDDEN
)
1676 TRACE("AutoHide starting show.\n");
1677 m_AutoHideState
= AUTOHIDE_SHOWING
;
1678 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1683 if (state
== AUTOHIDE_SHOWING
)
1685 TRACE("AutoHide cancelling show.\n");
1686 m_AutoHideState
= AUTOHIDE_HIDING
;
1687 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1689 else if (state
== AUTOHIDE_SHOWN
)
1691 TRACE("AutoHide starting hide.\n");
1692 m_AutoHideState
= AUTOHIDE_HIDING
;
1693 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1696 KillTimer(TIMER_ID_MOUSETRACK
);
1700 void ProcessAutoHide()
1702 RECT rc
= m_TrayRects
[m_Position
];
1703 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1704 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1706 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
);
1708 switch (m_AutoHideState
)
1710 case AUTOHIDE_HIDING
:
1714 m_AutoHideOffset
.cy
= 0;
1715 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1716 if (m_AutoHideOffset
.cx
< -w
)
1717 m_AutoHideOffset
.cx
= -w
;
1720 m_AutoHideOffset
.cx
= 0;
1721 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1722 if (m_AutoHideOffset
.cy
< -h
)
1723 m_AutoHideOffset
.cy
= -h
;
1726 m_AutoHideOffset
.cy
= 0;
1727 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1728 if (m_AutoHideOffset
.cx
> w
)
1729 m_AutoHideOffset
.cx
= w
;
1732 m_AutoHideOffset
.cx
= 0;
1733 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1734 if (m_AutoHideOffset
.cy
> h
)
1735 m_AutoHideOffset
.cy
= h
;
1739 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1741 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1746 case AUTOHIDE_HIDDEN
:
1751 m_AutoHideOffset
.cx
= -w
;
1752 m_AutoHideOffset
.cy
= 0;
1755 m_AutoHideOffset
.cx
= 0;
1756 m_AutoHideOffset
.cy
= -h
;
1759 m_AutoHideOffset
.cx
= w
;
1760 m_AutoHideOffset
.cy
= 0;
1763 m_AutoHideOffset
.cx
= 0;
1764 m_AutoHideOffset
.cy
= h
;
1768 KillTimer(TIMER_ID_AUTOHIDE
);
1769 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1772 case AUTOHIDE_SHOWING
:
1773 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1775 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1777 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1779 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1783 m_AutoHideOffset
.cx
= 0;
1786 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1788 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1790 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1792 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1796 m_AutoHideOffset
.cy
= 0;
1799 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1801 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1806 case AUTOHIDE_SHOWN
:
1808 KillTimer(TIMER_ID_AUTOHIDE
);
1809 m_AutoHideState
= AUTOHIDE_SHOWN
;
1813 rc
.left
+= m_AutoHideOffset
.cx
;
1814 rc
.right
+= m_AutoHideOffset
.cx
;
1815 rc
.top
+= m_AutoHideOffset
.cy
;
1816 rc
.bottom
+= m_AutoHideOffset
.cy
;
1818 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1819 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1826 /**********************************************************
1827 * ##### taskbar drawing #####
1830 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1836 GetClientRect(&rect
);
1840 GetClientRect(&rect
);
1844 partId
= TBP_BACKGROUNDLEFT
;
1847 partId
= TBP_BACKGROUNDTOP
;
1850 partId
= TBP_BACKGROUNDRIGHT
;
1854 partId
= TBP_BACKGROUNDBOTTOM
;
1857 res
= DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1863 int DrawSizerWithTheme(IN HRGN hRgn
)
1869 GetWindowRect(&rect
);
1870 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1872 hdc
= GetWindowDC();
1877 backgroundPart
= TBP_SIZINGBARLEFT
;
1878 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1881 backgroundPart
= TBP_SIZINGBARTOP
;
1882 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1885 backgroundPart
= TBP_SIZINGBARRIGHT
;
1886 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1890 backgroundPart
= TBP_SIZINGBARBOTTOM
;
1891 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1894 if (IsThemeBackgroundPartiallyTransparent(m_Theme
, backgroundPart
, 0))
1896 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1898 DrawThemeBackground(m_Theme
, hdc
, backgroundPart
, 0, &rect
, 0);
1911 HRESULT STDMETHODCALLTYPE
Open()
1915 /* Check if there's already a window created and try to show it.
1916 If it was somehow destroyed just create a new tray window. */
1917 if (m_hWnd
!= NULL
&& IsWindow())
1919 if (!IsWindowVisible())
1921 CheckTrayWndPosition();
1923 ShowWindow(SW_SHOW
);
1929 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1931 dwExStyle
|= WS_EX_TOPMOST
;
1933 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1934 if(!IsThemeActive())
1936 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1939 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1940 if (m_Position
!= (DWORD
) -1)
1941 rcWnd
= m_TrayRects
[m_Position
];
1943 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1949 HRESULT STDMETHODCALLTYPE
Close()
1962 HWND STDMETHODCALLTYPE
GetHWND()
1967 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1969 return (m_hWnd
== hWnd
||
1970 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1973 BOOL STDMETHODCALLTYPE
IsHorizontal()
1975 return IsPosHorizontal();
1978 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1980 if (phBoldCaption
!= NULL
)
1981 *phBoldCaption
= m_StartButton
.GetFont();
1983 return m_CaptionFont
;
1986 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1988 BOOL bPrevLock
= Locked
;
1990 if (Locked
!= bLock
)
1994 if (m_TrayBandSite
!= NULL
)
1996 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2006 /* Update cached tray sizes */
2007 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2009 RECT rcGripper
= {0};
2010 AdjustSizerRect(&rcGripper
, Pos
);
2014 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2015 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2016 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2017 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2021 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2022 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2023 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2024 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2028 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2039 /**********************************************************
2040 * ##### message handling #####
2043 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2045 ((ITrayWindow
*)this)->AddRef();
2047 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2049 InterlockedIncrement(&TrayWndCount
);
2051 if (m_CaptionFont
== NULL
)
2053 NONCLIENTMETRICS ncm
;
2055 /* Get the system fonts, we use the caption font,
2056 always bold, though. */
2057 ncm
.cbSize
= sizeof(ncm
);
2058 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
2060 if (m_CaptionFont
== NULL
)
2062 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
2063 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
2068 /* Create the Start button */
2069 m_StartButton
.Create(m_hWnd
);
2071 /* Load the saved tray window settings */
2074 /* Create and initialize the start menu */
2075 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2076 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2078 /* Load the tray band site */
2079 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
2080 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2082 /* Create the tray notification window */
2083 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2085 if (UpdateNonClientMetrics())
2090 /* Move the tray window to the right position and resize it if necessary */
2091 CheckTrayWndPosition();
2093 /* Align all controls on the tray window */
2094 AlignControls(NULL
);
2096 InitShellServices(&m_ShellServices
);
2100 m_AutoHideState
= AUTOHIDE_HIDING
;
2101 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2104 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2105 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2106 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2107 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2108 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2109 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2110 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2111 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2112 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2113 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2114 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2115 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2120 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2123 CloseThemeData(m_Theme
);
2125 if (IsThemeActive())
2126 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2132 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2136 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2138 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2143 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2145 HDC hdc
= (HDC
) wParam
;
2153 return EraseBackgroundWithTheme(hdc
);
2156 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2158 /* Load the saved tray window settings */
2161 /* Move the tray window to the right position and resize it if necessary */
2162 CheckTrayWndPosition();
2164 /* Align all controls on the tray window */
2165 AlignControls(NULL
);
2170 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2174 TRACE("WM_COPYDATA notify message received. Handling...\n");
2175 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2180 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2188 return DrawSizerWithTheme((HRGN
) wParam
);
2191 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2193 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2194 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2197 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2204 /* The user may not be able to resize the tray window.
2205 Pretend like the window is not sizeable when the user
2206 clicks on the border. */
2210 SetLastError(ERROR_SUCCESS
);
2211 if (GetClientRect(&rcClient
) &&
2212 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2214 pt
.x
= (SHORT
) LOWORD(lParam
);
2215 pt
.y
= (SHORT
) HIWORD(lParam
);
2217 if (PtInRect(&rcClient
,
2220 /* The user is trying to drag the tray window */
2224 /* Depending on the position of the tray window, allow only
2225 changing the border next to the monitor working area */
2229 if (pt
.y
> rcClient
.bottom
)
2233 if (pt
.x
> rcClient
.right
)
2237 if (pt
.x
< rcClient
.left
)
2242 if (pt
.y
< rcClient
.top
)
2251 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2254 PRECT pRect
= (PRECT
) lParam
;
2256 /* We need to ensure that an application can not accidently
2257 move the tray window (using SetWindowPos). However, we still
2258 need to be able to move the window in case the user wants to
2259 drag the tray window to another position or in case the user
2260 wants to resize the tray window. */
2261 if (!Locked
&& GetCursorPos(&ptCursor
))
2264 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2268 *pRect
= m_TrayRects
[m_Position
];
2272 pRect
->left
+= m_AutoHideOffset
.cx
;
2273 pRect
->right
+= m_AutoHideOffset
.cx
;
2274 pRect
->top
+= m_AutoHideOffset
.cy
;
2275 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2281 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2283 PRECT pRect
= (PRECT
) lParam
;
2287 /* Get the rect of the rebar */
2288 RECT rebarRect
, taskbarRect
;
2289 ::GetWindowRect(m_Rebar
, &rebarRect
);
2290 ::GetWindowRect(m_hWnd
, &taskbarRect
);
2291 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
2293 /* Calculate the difference of size of the taskbar and the rebar */
2295 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
2296 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
2298 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
2302 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
2303 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2304 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
2307 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
2308 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2309 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
2313 /* FIXME: what to do here? */
2317 CalculateValidSize(m_Position
, pRect
);
2321 *pRect
= m_TrayRects
[m_Position
];
2325 pRect
->left
+= m_AutoHideOffset
.cx
;
2326 pRect
->right
+= m_AutoHideOffset
.cx
;
2327 pRect
->top
+= m_AutoHideOffset
.cy
;
2328 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2334 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2336 ChangingWinPos((LPWINDOWPOS
) lParam
);
2340 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2343 InvalidateRect(NULL
, TRUE
);
2344 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2347 /* Clip the tray window on multi monitor systems so the edges can't
2348 overlap into another monitor */
2349 ApplyClipping(TRUE
);
2351 if (!GetClientRect(&rcClient
))
2358 rcClient
.left
= rcClient
.top
= 0;
2359 rcClient
.right
= LOWORD(lParam
);
2360 rcClient
.bottom
= HIWORD(lParam
);
2363 AlignControls(&rcClient
);
2367 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2373 /* Remove the clipping on multi monitor systems while dragging around */
2374 ApplyClipping(FALSE
);
2379 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2384 /* Apply clipping */
2385 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2390 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2396 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2397 The tray window needs to handle this specially, since it normally doesn't have
2400 static const UINT uidDisableItem
[] = {
2410 /* temporarily enable the system menu */
2411 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2413 hSysMenu
= GetSystemMenu(FALSE
);
2414 if (hSysMenu
!= NULL
)
2416 /* Disable all items that are not relevant */
2417 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2419 EnableMenuItem(hSysMenu
,
2421 MF_BYCOMMAND
| MF_GRAYED
);
2424 EnableMenuItem(hSysMenu
,
2427 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2429 /* Display the system menu */
2433 m_StartButton
.m_hWnd
,
2434 m_Position
!= ABE_TOP
,
2438 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2442 /* revert the system menu window style */
2443 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2453 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2455 /* We want the user to be able to get a context menu even on the nonclient
2456 area (including the sizing border)! */
2457 uMsg
= WM_CONTEXTMENU
;
2458 wParam
= (WPARAM
) m_hWnd
;
2460 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2463 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2465 LRESULT Ret
= FALSE
;
2466 POINT pt
, *ppt
= NULL
;
2467 HWND hWndExclude
= NULL
;
2469 /* Check if the administrator has forbidden access to context menus */
2470 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2473 pt
.x
= (SHORT
) LOWORD(lParam
);
2474 pt
.y
= (SHORT
) HIWORD(lParam
);
2476 if (pt
.x
!= -1 || pt
.y
!= -1)
2479 hWndExclude
= m_StartButton
.m_hWnd
;
2481 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2483 /* Make sure we can't track the context menu if the start
2484 menu is currently being shown */
2485 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2487 CComPtr
<IContextMenu
> ctxMenu
;
2488 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2489 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2494 /* See if the context menu should be handled by the task band site */
2495 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2498 POINT ptClient
= *ppt
;
2500 /* Convert the coordinates to client-coordinates */
2501 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2503 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2504 if (hWndAtPt
!= NULL
&&
2505 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2507 /* Check if the user clicked on the task switch window */
2509 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2511 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2512 if (hWndAtPt
== m_TaskSwitch
)
2513 goto HandleTrayContextMenu
;
2515 /* Forward the message to the task band site */
2516 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2519 goto HandleTrayContextMenu
;
2523 HandleTrayContextMenu
:
2524 /* Tray the default tray window context menu */
2525 CComPtr
<IContextMenu
> ctxMenu
;
2526 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2527 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2533 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2535 LRESULT Ret
= FALSE
;
2536 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2537 the rebar control! But we shouldn't forward messages that the band
2538 site doesn't handle, such as other controls (start button, tray window */
2540 HRESULT hr
= E_FAIL
;
2544 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2549 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2551 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2553 if (nmh
->hwndFrom
== m_TrayNotify
)
2558 /* Cause all controls to be aligned */
2559 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2567 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2569 /* We "handle" this message so users can't cause a weird maximize/restore
2570 window animation when double-clicking the tray window! */
2572 /* We should forward mouse messages to child windows here.
2573 Right now, this is only clock double-click */
2575 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2578 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2579 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2580 if (PtInRect(&rcClock
, ptClick
))
2582 //FIXME: use SHRunControlPanel
2583 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2589 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2595 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2598 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2599 if (FAILED_UNEXPECTEDLY(hr
))
2602 if (::IsWindowVisible(hwndStartMenu
))
2604 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2614 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2617 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2618 * to show the shutdown dialog. Also a WM_CLOSE message sent
2619 * by apps should show the dialog.
2621 return DoExitWindows();
2624 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2626 if (wParam
== SC_CLOSE
)
2628 return DoExitWindows();
2635 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2637 return HandleHotKey(wParam
);
2640 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2642 LRESULT Ret
= FALSE
;
2644 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2650 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2652 return HandleCommand(LOWORD(wParam
));
2657 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2661 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2667 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2669 if (wParam
== TIMER_ID_MOUSETRACK
)
2671 ProcessMouseTracking();
2673 else if (wParam
== TIMER_ID_AUTOHIDE
)
2682 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2685 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2686 if(!IsThemeActive() || Locked
)
2697 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2698 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2703 rc
= &prms
->rgrc
[0];
2706 AdjustSizerRect(rc
, m_Position
);
2711 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2714 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2720 ::GetWindowRect(m_hWnd
, &rc
);
2724 rc
.bottom
- rc
.top
};
2726 as
->rcTarget
.right
- as
->rcTarget
.left
,
2727 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2729 as
->rcActual
.right
- as
->rcActual
.left
,
2730 as
->rcActual
.bottom
- as
->rcActual
.top
};
2733 szWindow
.cx
- szTarget
.cx
,
2734 szWindow
.cy
- szTarget
.cx
,
2740 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2743 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2746 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2747 rc
.left
= rc
.right
- szWindow
.cy
;
2750 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2751 rc
.top
= rc
.bottom
- szWindow
.cy
;
2755 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2762 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2764 BEGIN_MSG_MAP(CTrayWindow
)
2765 if (m_StartMenuBand
!= NULL
)
2772 Msg
.wParam
= wParam
;
2773 Msg
.lParam
= lParam
;
2775 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2780 wParam
= Msg
.wParam
;
2781 lParam
= Msg
.lParam
;
2783 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2784 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2785 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2786 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2787 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2788 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2789 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2790 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2791 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2792 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2793 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2794 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2795 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2796 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2797 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2798 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2799 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2800 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2801 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2802 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2803 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2804 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2805 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2806 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2807 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2808 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2809 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2810 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2811 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2812 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2813 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2814 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2818 /*****************************************************************************/
2820 VOID
TrayProcessMessages()
2824 /* FIXME: We should keep a reference here... */
2826 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2828 if (Msg
.message
== WM_QUIT
)
2831 if (m_StartMenuBand
== NULL
||
2832 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2834 TranslateMessage(&Msg
);
2835 DispatchMessage(&Msg
);
2840 VOID
TrayMessageLoop()
2845 /* FIXME: We should keep a reference here... */
2849 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2851 if (!Ret
|| Ret
== -1)
2854 if (m_StartMenuBand
== NULL
||
2855 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2857 TranslateMessage(&Msg
);
2858 DispatchMessage(&Msg
);
2866 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2867 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2868 * The reason we implement it is because we have to use SHCreateDesktop() so
2869 * that the shell provides the desktop window and all the features that come
2870 * with it (especially positioning of desktop icons)
2873 virtual ULONG STDMETHODCALLTYPE
GetState()
2875 /* FIXME: Return ABS_ flags? */
2876 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2880 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2882 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2883 *phWndTray
= m_hWnd
;
2887 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2889 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2891 m_DesktopWnd
= hWndDesktop
;
2895 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2897 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2901 virtual HRESULT
RaiseStartButton()
2903 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2909 m_Position
= (DWORD
) -1;
2912 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2914 DECLARE_PROTECT_FINAL_CONSTRUCT()
2915 BEGIN_COM_MAP(CTrayWindow
)
2916 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2917 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2921 class CTrayWindowCtxMenu
:
2922 public CComCoClass
<CTrayWindowCtxMenu
>,
2923 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2927 CComPtr
<CTrayWindow
> TrayWnd
;
2928 CComPtr
<IContextMenu
> pcm
;
2931 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2933 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2934 this->hWndOwner
= hWndOwner
;
2938 virtual HRESULT STDMETHODCALLTYPE
2939 QueryContextMenu(HMENU hPopup
,
2945 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
2948 return HRESULT_FROM_WIN32(GetLastError());
2950 int count
= ::GetMenuItemCount(menubase
);
2952 for (int i
= 0; i
< count
; i
++)
2956 MENUITEMINFOW mii
= { 0 };
2957 mii
.cbSize
= sizeof(mii
);
2958 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2959 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2960 mii
.dwTypeData
= label
;
2961 mii
.cch
= _countof(label
);
2962 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2964 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
2966 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
2969 ::DestroyMenu(menubase
);
2971 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2978 CheckMenuItem(hPopup
,
2980 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
2982 if (TrayWnd
->m_TrayBandSite
!= NULL
)
2984 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
2992 WARN("AddContextMenus failed.\n");
3000 virtual HRESULT STDMETHODCALLTYPE
3001 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3003 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3006 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3008 CMINVOKECOMMANDINFO cmici
= { 0 };
3012 /* Setup and invoke the shell command */
3013 cmici
.cbSize
= sizeof(cmici
);
3014 cmici
.hwnd
= hWndOwner
;
3015 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- ID_SHELL_CMD_FIRST
);
3016 cmici
.nShow
= SW_NORMAL
;
3018 pcm
->InvokeCommand(&cmici
);
3023 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3030 virtual HRESULT STDMETHODCALLTYPE
3031 GetCommandString(UINT_PTR idCmd
,
3040 CTrayWindowCtxMenu()
3044 virtual ~CTrayWindowCtxMenu()
3048 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3049 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3053 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3055 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3056 mnu
->Initialize(TrayWnd
, hWndOwner
);
3061 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3063 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3065 return E_OUTOFMEMORY
;
3070 *ppTray
= (ITrayWindow
*) Tray
;
3076 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3078 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3079 return TrayWindow
->RaiseStartButton();
3082 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3084 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3085 TrayWindow
->TrayProcessMessages();
3088 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3090 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3091 TrayWindow
->TrayMessageLoop();