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
MakeTrayRectWithSize(IN DWORD Position
,
851 IN
const SIZE
*pTraySize
,
857 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
861 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
865 pRect
->left
= pRect
->right
- pTraySize
->cx
;
870 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
875 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
876 IN
const RECT
*pScreen
,
877 IN
const SIZE
*pTraySize OPTIONAL
,
880 if (pTraySize
== NULL
)
881 pTraySize
= &m_TraySize
;
885 /* Move the border outside of the screen */
887 GetSystemMetrics(SM_CXEDGE
),
888 GetSystemMetrics(SM_CYEDGE
));
890 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
893 BOOL
IsPosHorizontal()
895 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
898 HMONITOR
CalculateValidSize(
907 //Horizontal = IsPosHorizontal();
909 szWnd
.cx
= pRect
->right
- pRect
->left
;
910 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
913 hMon
= GetScreenRectFromRect(
915 MONITOR_DEFAULTTONEAREST
);
917 /* Calculate the maximum size of the tray window and limit the window
918 size to half of the screen's size. */
919 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
920 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
921 if (szWnd
.cx
> szMax
.cx
)
923 if (szWnd
.cy
> szMax
.cy
)
926 /* FIXME - calculate */
928 GetTrayRectFromScreenRect(Position
,
938 GetMinimumWindowSize(
943 AdjustWindowRectEx(&rcMin
,
944 GetWindowLong(m_hWnd
,
947 GetWindowLong(m_hWnd
,
955 DWORD
GetDraggingRectFromPt(
958 OUT HMONITOR
*phMonitor
)
960 HMONITOR hMon
, hMonNew
;
961 DWORD PosH
, PosV
, Pos
;
962 SIZE DeltaPt
, ScreenOffset
;
968 /* Determine the screen rectangle */
969 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
974 mi
.cbSize
= sizeof(mi
);
975 if (!GetMonitorInfo(hMon
, &mi
))
978 goto GetPrimaryScreenRect
;
981 /* make left top corner of the screen zero based to
982 make calculations easier */
983 pt
.x
-= mi
.rcMonitor
.left
;
984 pt
.y
-= mi
.rcMonitor
.top
;
986 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
987 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
988 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
989 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
993 GetPrimaryScreenRect
:
996 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
997 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1000 /* Calculate the nearest screen border */
1001 if (pt
.x
< rcScreen
.right
/ 2)
1008 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1012 if (pt
.y
< rcScreen
.bottom
/ 2)
1019 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1023 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1025 /* Fix the screen origin to be relative to the primary monitor again */
1026 OffsetRect(&rcScreen
,
1030 RECT rcPos
= m_TrayRects
[Pos
];
1032 hMonNew
= GetMonitorFromRect(&rcPos
);
1033 if (hMon
!= hMonNew
)
1037 /* Recalculate the rectangle, we're dragging to another monitor.
1038 We don't need to recalculate the rect on single monitor systems. */
1039 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1040 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1042 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1045 pRect
->left
+= m_AutoHideOffset
.cx
;
1046 pRect
->right
+= m_AutoHideOffset
.cx
;
1047 pRect
->top
+= m_AutoHideOffset
.cy
;
1048 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1054 /* The user is dragging the tray window on the same monitor. We don't need
1055 to recalculate the rectangle */
1059 pRect
->left
+= m_AutoHideOffset
.cx
;
1060 pRect
->right
+= m_AutoHideOffset
.cx
;
1061 pRect
->top
+= m_AutoHideOffset
.cy
;
1062 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1071 DWORD
GetDraggingRectFromRect(
1073 OUT HMONITOR
*phMonitor
)
1077 /* Calculate the center of the rectangle. We call
1078 GetDraggingRectFromPt to calculate a valid
1079 dragging rectangle */
1080 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1081 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1083 return GetDraggingRectFromPt(
1089 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1095 rcTray
.left
= pwp
->x
;
1096 rcTray
.top
= pwp
->y
;
1097 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1098 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1101 rcTray
.left
-= m_AutoHideOffset
.cx
;
1102 rcTray
.right
-= m_AutoHideOffset
.cx
;
1103 rcTray
.top
-= m_AutoHideOffset
.cy
;
1104 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1107 if (!EqualRect(&rcTray
,
1108 &m_TrayRects
[m_DraggingPosition
]))
1110 /* Recalculate the rectangle, the user dragged the tray
1111 window to another monitor or the window was somehow else
1113 m_DraggingPosition
= GetDraggingRectFromRect(
1115 &m_DraggingMonitor
);
1116 //m_TrayRects[DraggingPosition] = rcTray;
1119 //Monitor = CalculateValidSize(DraggingPosition,
1122 m_Monitor
= m_DraggingMonitor
;
1123 m_Position
= m_DraggingPosition
;
1126 m_TrayRects
[m_Position
] = rcTray
;
1129 else if (GetWindowRect(&rcTray
))
1133 if (!(pwp
->flags
& SWP_NOMOVE
))
1135 rcTray
.left
= pwp
->x
;
1136 rcTray
.top
= pwp
->y
;
1139 if (!(pwp
->flags
& SWP_NOSIZE
))
1141 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1142 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1145 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1147 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1154 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1159 rcTray
.left
-= m_AutoHideOffset
.cx
;
1160 rcTray
.right
-= m_AutoHideOffset
.cx
;
1161 rcTray
.top
-= m_AutoHideOffset
.cy
;
1162 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1164 m_TrayRects
[m_Position
] = rcTray
;
1168 /* If the user isn't resizing the tray window we need to make sure the
1169 new size or position is valid. this is to prevent changes to the window
1170 without user interaction. */
1171 rcTray
= m_TrayRects
[m_Position
];
1175 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1176 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1180 rcTray
.left
+= m_AutoHideOffset
.cx
;
1181 rcTray
.right
+= m_AutoHideOffset
.cx
;
1182 rcTray
.top
+= m_AutoHideOffset
.cy
;
1183 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1186 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1187 pwp
->x
= rcTray
.left
;
1188 pwp
->y
= rcTray
.top
;
1189 pwp
->cx
= m_TraySize
.cx
;
1190 pwp
->cy
= m_TraySize
.cy
;
1194 VOID
ApplyClipping(IN BOOL Clip
)
1196 RECT rcClip
, rcWindow
;
1199 if (GetWindowRect(&rcWindow
))
1201 /* Disable clipping on systems with only one monitor */
1202 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1209 GetScreenRect(m_Monitor
, &rcClip
);
1211 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1220 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1225 /* Set the clipping region or make sure the window isn't clipped
1226 by disabling it explicitly. */
1227 SetWindowRgn(hClipRgn
, TRUE
);
1231 VOID
ResizeWorkArea()
1233 #if !WIN7_DEBUG_MODE
1234 RECT rcTray
, rcWorkArea
;
1236 /* If monitor has changed then fix the previous monitors work area */
1237 if (m_PreviousMonitor
!= m_Monitor
)
1239 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1240 SystemParametersInfoW(SPI_SETWORKAREA
,
1246 rcTray
= m_TrayRects
[m_Position
];
1248 GetScreenRect(m_Monitor
, &rcWorkArea
);
1249 m_PreviousMonitor
= m_Monitor
;
1251 /* If AutoHide is false then change the workarea to exclude
1252 the area that the taskbar covers. */
1258 rcWorkArea
.top
= rcTray
.bottom
;
1261 rcWorkArea
.left
= rcTray
.right
;
1264 rcWorkArea
.right
= rcTray
.left
;
1267 rcWorkArea
.bottom
= rcTray
.top
;
1273 * Resize the current monitor work area. Win32k will also send
1274 * a WM_SIZE message to automatically resize the desktop.
1276 SystemParametersInfoW(SPI_SETWORKAREA
,
1283 VOID
CheckTrayWndPosition()
1287 rcTray
= m_TrayRects
[m_Position
];
1291 rcTray
.left
+= m_AutoHideOffset
.cx
;
1292 rcTray
.right
+= m_AutoHideOffset
.cx
;
1293 rcTray
.top
+= m_AutoHideOffset
.cy
;
1294 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1297 /* Move the tray window */
1301 rcTray
.right
- rcTray
.left
,
1302 rcTray
.bottom
- rcTray
.top
,
1303 SWP_NOZORDER
| SWP_NOACTIVATE
);
1307 ApplyClipping(TRUE
);
1310 typedef struct _TW_STUCKRECTS2
1318 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1320 VOID
RegLoadSettings()
1325 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1326 DWORD cbSize
= sizeof(sr
);
1327 SIZE StartBtnSize
= m_StartButton
.GetSize();
1329 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1330 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1331 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1332 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1334 if (SHGetValue(hkExplorer
,
1335 TEXT("StuckRects2"),
1339 &cbSize
) == ERROR_SUCCESS
&&
1340 sr
.cbSize
== sizeof(sr
))
1342 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1343 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1344 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1345 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1347 /* FIXME: Are there more flags? */
1350 m_Position
= ABE_LEFT
;
1352 if (sr
.Position
> ABE_BOTTOM
)
1353 m_Position
= ABE_BOTTOM
;
1355 m_Position
= sr
.Position
;
1358 /* Try to find out which monitor the tray window was located on last.
1359 Here we're only interested in the monitor screen that we think
1360 is the last one used. We're going to determine on which monitor
1361 we really are after calculating the docked position. */
1363 GetScreenRectFromRect(
1365 MONITOR_DEFAULTTONEAREST
);
1369 m_Position
= ABE_BOTTOM
;
1372 /* Use the minimum size of the taskbar, we'll use the start
1373 button as a minimum for now. Make sure we calculate the
1374 entire window size, not just the client size. However, we
1375 use a thinner border than a standard thick border, so that
1376 the start button and bands are not stuck to the screen border. */
1377 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1378 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1380 /* Use the primary screen by default */
1383 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1384 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1385 GetScreenRectFromRect(
1387 MONITOR_DEFAULTTOPRIMARY
);
1392 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1397 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1399 /* Determine a minimum tray window rectangle. The "client" height is
1400 zero here since we cannot determine an optimal minimum width when
1401 loaded as a vertical tray window. We just need to make sure the values
1402 loaded from the registry are at least. The windows explorer behaves
1403 the same way, it allows the user to save a zero width vertical tray
1404 window, but not a zero height horizontal tray window. */
1405 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1406 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1408 if (WndSize
.cx
< sr
.Size
.cx
)
1409 WndSize
.cx
= sr
.Size
.cx
;
1410 if (WndSize
.cy
< sr
.Size
.cy
)
1411 WndSize
.cy
= sr
.Size
.cy
;
1413 /* Save the calculated size */
1414 m_TraySize
= WndSize
;
1416 /* Calculate all docking rectangles. We need to do this here so they're
1417 initialized and dragging the tray window to another position gives
1419 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1421 GetTrayRectFromScreenRect(Pos
,
1425 // 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);
1428 /* Determine which monitor we are on. It shouldn't matter which docked
1429 position rectangle we use */
1430 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1433 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1436 SIZE TraySize
, StartSize
;
1437 POINT ptTrayNotify
= { 0, 0 };
1441 m_StartButton
.UpdateSize();
1442 if (prcClient
!= NULL
)
1444 rcClient
= *prcClient
;
1448 if (!GetClientRect(&rcClient
))
1450 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1455 Horizontal
= IsPosHorizontal();
1457 /* We're about to resize/move the start button, the rebar control and
1458 the tray notification control */
1459 dwp
= BeginDeferWindowPos(3);
1462 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1466 /* Limit the Start button width to the client width, if necessary */
1467 StartSize
= m_StartButton
.GetSize();
1468 if (StartSize
.cx
> rcClient
.right
)
1469 StartSize
.cx
= rcClient
.right
;
1471 if (m_StartButton
.m_hWnd
!= NULL
)
1473 /* Resize and reposition the button */
1474 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1480 SWP_NOZORDER
| SWP_NOACTIVATE
);
1483 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1488 /* Determine the size that the tray notification window needs */
1492 TraySize
.cy
= rcClient
.bottom
;
1496 TraySize
.cx
= rcClient
.right
;
1500 if (m_TrayNotify
!= NULL
&&
1501 SendMessage(m_TrayNotify
,
1502 TNWM_GETMINIMUMSIZE
,
1506 /* Move the tray notification window to the desired location */
1508 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1510 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1512 dwp
= ::DeferWindowPos(dwp
,
1519 SWP_NOZORDER
| SWP_NOACTIVATE
);
1522 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1527 /* Resize/Move the rebar control */
1528 if (m_Rebar
!= NULL
)
1530 POINT ptRebar
= { 0, 0 };
1533 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1537 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1538 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1539 szRebar
.cy
= rcClient
.bottom
;
1543 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1544 szRebar
.cx
= rcClient
.right
;
1545 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1548 dwp
= ::DeferWindowPos(dwp
,
1555 SWP_NOZORDER
| SWP_NOACTIVATE
);
1559 EndDeferWindowPos(dwp
);
1561 if (m_TaskSwitch
!= NULL
)
1563 /* Update the task switch window configuration */
1564 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1568 void PopupStartMenu()
1570 if (m_StartMenuPopup
!= NULL
)
1576 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1581 pt
.x
= rcExclude
.left
;
1582 pt
.y
= rcExclude
.top
;
1583 dwFlags
|= MPPF_TOP
;
1586 pt
.x
= rcExclude
.left
;
1587 pt
.y
= rcExclude
.bottom
;
1588 dwFlags
|= MPPF_BOTTOM
;
1591 pt
.x
= rcExclude
.right
;
1592 pt
.y
= rcExclude
.top
;
1593 dwFlags
|= MPPF_RIGHT
;
1596 pt
.x
= rcExclude
.left
;
1597 pt
.y
= rcExclude
.top
;
1598 dwFlags
|= MPPF_LEFT
;
1602 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1604 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1609 void ProcessMouseTracking()
1614 UINT state
= m_AutoHideState
;
1617 GetWindowRect(&rcCurrent
);
1618 over
= PtInRect(&rcCurrent
, pt
);
1620 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1627 if (state
== AUTOHIDE_HIDING
)
1629 TRACE("AutoHide cancelling hide.\n");
1630 m_AutoHideState
= AUTOHIDE_SHOWING
;
1631 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1633 else if (state
== AUTOHIDE_HIDDEN
)
1635 TRACE("AutoHide starting show.\n");
1636 m_AutoHideState
= AUTOHIDE_SHOWING
;
1637 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1642 if (state
== AUTOHIDE_SHOWING
)
1644 TRACE("AutoHide cancelling show.\n");
1645 m_AutoHideState
= AUTOHIDE_HIDING
;
1646 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1648 else if (state
== AUTOHIDE_SHOWN
)
1650 TRACE("AutoHide starting hide.\n");
1651 m_AutoHideState
= AUTOHIDE_HIDING
;
1652 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1655 KillTimer(TIMER_ID_MOUSETRACK
);
1659 void ProcessAutoHide()
1661 RECT rc
= m_TrayRects
[m_Position
];
1662 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1663 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1665 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
);
1667 switch (m_AutoHideState
)
1669 case AUTOHIDE_HIDING
:
1673 m_AutoHideOffset
.cy
= 0;
1674 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1675 if (m_AutoHideOffset
.cx
< -w
)
1676 m_AutoHideOffset
.cx
= -w
;
1679 m_AutoHideOffset
.cx
= 0;
1680 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1681 if (m_AutoHideOffset
.cy
< -h
)
1682 m_AutoHideOffset
.cy
= -h
;
1685 m_AutoHideOffset
.cy
= 0;
1686 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1687 if (m_AutoHideOffset
.cx
> w
)
1688 m_AutoHideOffset
.cx
= w
;
1691 m_AutoHideOffset
.cx
= 0;
1692 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1693 if (m_AutoHideOffset
.cy
> h
)
1694 m_AutoHideOffset
.cy
= h
;
1698 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1700 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1705 case AUTOHIDE_HIDDEN
:
1710 m_AutoHideOffset
.cx
= -w
;
1711 m_AutoHideOffset
.cy
= 0;
1714 m_AutoHideOffset
.cx
= 0;
1715 m_AutoHideOffset
.cy
= -h
;
1718 m_AutoHideOffset
.cx
= w
;
1719 m_AutoHideOffset
.cy
= 0;
1722 m_AutoHideOffset
.cx
= 0;
1723 m_AutoHideOffset
.cy
= h
;
1727 KillTimer(TIMER_ID_AUTOHIDE
);
1728 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1731 case AUTOHIDE_SHOWING
:
1732 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1734 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1736 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1738 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1742 m_AutoHideOffset
.cx
= 0;
1745 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1747 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1749 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1751 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1755 m_AutoHideOffset
.cy
= 0;
1758 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1760 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1765 case AUTOHIDE_SHOWN
:
1767 KillTimer(TIMER_ID_AUTOHIDE
);
1768 m_AutoHideState
= AUTOHIDE_SHOWN
;
1772 rc
.left
+= m_AutoHideOffset
.cx
;
1773 rc
.right
+= m_AutoHideOffset
.cx
;
1774 rc
.top
+= m_AutoHideOffset
.cy
;
1775 rc
.bottom
+= m_AutoHideOffset
.cy
;
1777 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1778 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1785 /**********************************************************
1786 * ##### taskbar drawing #####
1789 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1795 GetClientRect(&rect
);
1799 GetClientRect(&rect
);
1803 partId
= TBP_BACKGROUNDLEFT
;
1806 partId
= TBP_BACKGROUNDTOP
;
1809 partId
= TBP_BACKGROUNDRIGHT
;
1813 partId
= TBP_BACKGROUNDBOTTOM
;
1816 res
= DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1822 int DrawSizerWithTheme(IN HRGN hRgn
)
1828 GetWindowRect(&rect
);
1829 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1831 hdc
= GetDCEx(hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1836 backgroundPart
= TBP_SIZINGBARLEFT
;
1837 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1840 backgroundPart
= TBP_SIZINGBARTOP
;
1841 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1844 backgroundPart
= TBP_SIZINGBARRIGHT
;
1845 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1849 backgroundPart
= TBP_SIZINGBARBOTTOM
;
1850 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1853 if (IsThemeBackgroundPartiallyTransparent(m_Theme
, backgroundPart
, 0))
1855 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1857 DrawThemeBackground(m_Theme
, hdc
, backgroundPart
, 0, &rect
, 0);
1870 HRESULT STDMETHODCALLTYPE
Open()
1874 /* Check if there's already a window created and try to show it.
1875 If it was somehow destroyed just create a new tray window. */
1876 if (m_hWnd
!= NULL
&& IsWindow())
1878 if (!IsWindowVisible())
1880 CheckTrayWndPosition();
1882 ShowWindow(SW_SHOW
);
1888 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1890 dwExStyle
|= WS_EX_TOPMOST
;
1892 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1893 WS_BORDER
| WS_THICKFRAME
;
1895 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1896 if (m_Position
!= (DWORD
) -1)
1897 rcWnd
= m_TrayRects
[m_Position
];
1899 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1905 HRESULT STDMETHODCALLTYPE
Close()
1918 HWND STDMETHODCALLTYPE
GetHWND()
1923 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1925 return (m_hWnd
== hWnd
||
1926 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1929 BOOL STDMETHODCALLTYPE
IsHorizontal()
1931 return IsPosHorizontal();
1934 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1936 if (phBoldCaption
!= NULL
)
1937 *phBoldCaption
= m_StartButton
.GetFont();
1939 return m_CaptionFont
;
1942 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1944 BOOL bPrevLock
= Locked
;
1946 if (Locked
!= bLock
)
1950 if (m_TrayBandSite
!= NULL
)
1952 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1960 if (Locked
&& m_Theme
)
1962 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1966 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1968 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1980 /**********************************************************
1981 * ##### message handling #####
1984 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1986 ((ITrayWindow
*)this)->AddRef();
1988 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1990 InterlockedIncrement(&TrayWndCount
);
1992 if (m_CaptionFont
== NULL
)
1994 NONCLIENTMETRICS ncm
;
1996 /* Get the system fonts, we use the caption font,
1997 always bold, though. */
1998 ncm
.cbSize
= sizeof(ncm
);
1999 if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
2001 if (m_CaptionFont
== NULL
)
2003 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
2004 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
2009 /* Create the Start button */
2010 m_StartButton
.Create(m_hWnd
);
2012 /* Load the saved tray window settings */
2015 /* Create and initialize the start menu */
2016 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2017 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2019 /* Load the tray band site */
2020 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
2021 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2023 /* Create the tray notification window */
2024 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2026 if (UpdateNonClientMetrics())
2031 /* Move the tray window to the right position and resize it if necessary */
2032 CheckTrayWndPosition();
2034 /* Align all controls on the tray window */
2035 AlignControls(NULL
);
2037 InitShellServices(&m_ShellServices
);
2041 m_AutoHideState
= AUTOHIDE_HIDING
;
2042 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2045 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2046 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2047 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2048 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2049 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2050 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2051 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2052 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2053 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2054 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2055 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2056 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2061 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2064 CloseThemeData(m_Theme
);
2066 if (IsThemeActive())
2067 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2071 if (Locked
&& m_Theme
)
2073 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2077 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2079 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2084 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2086 HDC hdc
= (HDC
) wParam
;
2094 return EraseBackgroundWithTheme(hdc
);
2097 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2099 /* Load the saved tray window settings */
2102 /* Move the tray window to the right position and resize it if necessary */
2103 CheckTrayWndPosition();
2105 /* Align all controls on the tray window */
2106 AlignControls(NULL
);
2111 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2115 TRACE("WM_COPYDATA notify message received. Handling...\n");
2116 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2121 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2129 return DrawSizerWithTheme((HRGN
) wParam
);
2132 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2134 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2135 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2138 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2145 /* The user may not be able to resize the tray window.
2146 Pretend like the window is not sizeable when the user
2147 clicks on the border. */
2151 SetLastError(ERROR_SUCCESS
);
2152 if (GetClientRect(&rcClient
) &&
2153 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2155 pt
.x
= (SHORT
) LOWORD(lParam
);
2156 pt
.y
= (SHORT
) HIWORD(lParam
);
2158 if (PtInRect(&rcClient
,
2161 /* The user is trying to drag the tray window */
2165 /* Depending on the position of the tray window, allow only
2166 changing the border next to the monitor working area */
2170 if (pt
.y
> rcClient
.bottom
)
2174 if (pt
.x
> rcClient
.right
)
2178 if (pt
.x
< rcClient
.left
)
2183 if (pt
.y
< rcClient
.top
)
2192 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2195 PRECT pRect
= (PRECT
) lParam
;
2197 /* We need to ensure that an application can not accidently
2198 move the tray window (using SetWindowPos). However, we still
2199 need to be able to move the window in case the user wants to
2200 drag the tray window to another position or in case the user
2201 wants to resize the tray window. */
2202 if (!Locked
&& GetCursorPos(&ptCursor
))
2205 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2209 *pRect
= m_TrayRects
[m_Position
];
2213 pRect
->left
+= m_AutoHideOffset
.cx
;
2214 pRect
->right
+= m_AutoHideOffset
.cx
;
2215 pRect
->top
+= m_AutoHideOffset
.cy
;
2216 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2222 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2224 PRECT pRect
= (PRECT
) lParam
;
2228 /* Get the rect of the rebar */
2229 RECT rebarRect
, taskbarRect
;
2230 ::GetWindowRect(m_Rebar
, &rebarRect
);
2231 ::GetWindowRect(m_hWnd
, &taskbarRect
);
2232 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
2234 /* Calculate the difference of size of the taskbar and the rebar */
2236 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
2237 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
2239 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
2243 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
2244 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2245 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
2248 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
2249 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
2250 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
2254 /* FIXME: what to do here? */
2258 CalculateValidSize(m_Position
, pRect
);
2262 *pRect
= m_TrayRects
[m_Position
];
2266 pRect
->left
+= m_AutoHideOffset
.cx
;
2267 pRect
->right
+= m_AutoHideOffset
.cx
;
2268 pRect
->top
+= m_AutoHideOffset
.cy
;
2269 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2275 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2277 ChangingWinPos((LPWINDOWPOS
) lParam
);
2281 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2284 InvalidateRect(NULL
, TRUE
);
2285 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2288 /* Clip the tray window on multi monitor systems so the edges can't
2289 overlap into another monitor */
2290 ApplyClipping(TRUE
);
2292 if (!GetClientRect(&rcClient
))
2299 rcClient
.left
= rcClient
.top
= 0;
2300 rcClient
.right
= LOWORD(lParam
);
2301 rcClient
.bottom
= HIWORD(lParam
);
2304 AlignControls(&rcClient
);
2308 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2314 /* Remove the clipping on multi monitor systems while dragging around */
2315 ApplyClipping(FALSE
);
2320 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2325 /* Apply clipping */
2326 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2331 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2337 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2338 The tray window needs to handle this specially, since it normally doesn't have
2341 static const UINT uidDisableItem
[] = {
2351 /* temporarily enable the system menu */
2352 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2354 hSysMenu
= GetSystemMenu(FALSE
);
2355 if (hSysMenu
!= NULL
)
2357 /* Disable all items that are not relevant */
2358 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2360 EnableMenuItem(hSysMenu
,
2362 MF_BYCOMMAND
| MF_GRAYED
);
2365 EnableMenuItem(hSysMenu
,
2368 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2370 /* Display the system menu */
2374 m_StartButton
.m_hWnd
,
2375 m_Position
!= ABE_TOP
,
2379 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2383 /* revert the system menu window style */
2384 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2394 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2396 /* We want the user to be able to get a context menu even on the nonclient
2397 area (including the sizing border)! */
2398 uMsg
= WM_CONTEXTMENU
;
2399 wParam
= (WPARAM
) m_hWnd
;
2401 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2404 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2406 LRESULT Ret
= FALSE
;
2407 POINT pt
, *ppt
= NULL
;
2408 HWND hWndExclude
= NULL
;
2410 /* Check if the administrator has forbidden access to context menus */
2411 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2414 pt
.x
= (SHORT
) LOWORD(lParam
);
2415 pt
.y
= (SHORT
) HIWORD(lParam
);
2417 if (pt
.x
!= -1 || pt
.y
!= -1)
2420 hWndExclude
= m_StartButton
.m_hWnd
;
2422 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2424 /* Make sure we can't track the context menu if the start
2425 menu is currently being shown */
2426 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2428 CComPtr
<IContextMenu
> ctxMenu
;
2429 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2430 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2435 /* See if the context menu should be handled by the task band site */
2436 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2439 POINT ptClient
= *ppt
;
2441 /* Convert the coordinates to client-coordinates */
2442 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2444 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2445 if (hWndAtPt
!= NULL
&&
2446 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2448 /* Check if the user clicked on the task switch window */
2450 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2452 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2453 if (hWndAtPt
== m_TaskSwitch
)
2454 goto HandleTrayContextMenu
;
2456 /* Forward the message to the task band site */
2457 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2460 goto HandleTrayContextMenu
;
2464 HandleTrayContextMenu
:
2465 /* Tray the default tray window context menu */
2466 CComPtr
<IContextMenu
> ctxMenu
;
2467 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2468 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2474 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2476 LRESULT Ret
= FALSE
;
2477 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2478 the rebar control! But we shouldn't forward messages that the band
2479 site doesn't handle, such as other controls (start button, tray window */
2481 HRESULT hr
= E_FAIL
;
2485 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2490 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2492 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2494 if (nmh
->hwndFrom
== m_TrayNotify
)
2499 /* Cause all controls to be aligned */
2500 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2508 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2510 /* We "handle" this message so users can't cause a weird maximize/restore
2511 window animation when double-clicking the tray window! */
2513 /* We should forward mouse messages to child windows here.
2514 Right now, this is only clock double-click */
2516 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2519 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2520 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2521 if (PtInRect(&rcClock
, ptClick
))
2523 //FIXME: use SHRunControlPanel
2524 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2530 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2536 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2539 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2540 if (FAILED_UNEXPECTEDLY(hr
))
2543 if (::IsWindowVisible(hwndStartMenu
))
2545 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2555 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2558 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2559 * to show the shutdown dialog. Also a WM_CLOSE message sent
2560 * by apps should show the dialog.
2562 return DoExitWindows();
2565 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2567 if (wParam
== SC_CLOSE
)
2569 return DoExitWindows();
2576 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2578 return HandleHotKey(wParam
);
2581 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2583 LRESULT Ret
= FALSE
;
2585 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2591 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2593 return HandleCommand(LOWORD(wParam
));
2598 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2602 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2608 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2610 if (wParam
== TIMER_ID_MOUSETRACK
)
2612 ProcessMouseTracking();
2614 else if (wParam
== TIMER_ID_AUTOHIDE
)
2623 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2626 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2632 ::GetWindowRect(m_hWnd
, &rc
);
2636 rc
.bottom
- rc
.top
};
2638 as
->rcTarget
.right
- as
->rcTarget
.left
,
2639 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2641 as
->rcActual
.right
- as
->rcActual
.left
,
2642 as
->rcActual
.bottom
- as
->rcActual
.top
};
2645 szWindow
.cx
- szTarget
.cx
,
2646 szWindow
.cy
- szTarget
.cx
,
2652 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2655 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2658 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2659 rc
.left
= rc
.right
- szWindow
.cy
;
2662 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2663 rc
.top
= rc
.bottom
- szWindow
.cy
;
2667 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2674 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2676 BEGIN_MSG_MAP(CTrayWindow
)
2677 if (m_StartMenuBand
!= NULL
)
2684 Msg
.wParam
= wParam
;
2685 Msg
.lParam
= lParam
;
2687 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2692 wParam
= Msg
.wParam
;
2693 lParam
= Msg
.lParam
;
2695 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2696 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2697 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2698 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2699 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2700 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2701 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2702 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2703 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2704 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2705 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2706 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2707 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2708 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2709 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2710 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2711 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2712 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2713 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2714 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2715 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2716 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2717 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2718 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2719 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2720 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2721 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2722 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2723 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2724 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2725 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2729 /*****************************************************************************/
2731 VOID
TrayProcessMessages()
2735 /* FIXME: We should keep a reference here... */
2737 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2739 if (Msg
.message
== WM_QUIT
)
2742 if (m_StartMenuBand
== NULL
||
2743 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2745 TranslateMessage(&Msg
);
2746 DispatchMessage(&Msg
);
2751 VOID
TrayMessageLoop()
2756 /* FIXME: We should keep a reference here... */
2760 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2762 if (!Ret
|| Ret
== -1)
2765 if (m_StartMenuBand
== NULL
||
2766 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2768 TranslateMessage(&Msg
);
2769 DispatchMessage(&Msg
);
2777 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2778 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2779 * The reason we implement it is because we have to use SHCreateDesktop() so
2780 * that the shell provides the desktop window and all the features that come
2781 * with it (especially positioning of desktop icons)
2784 virtual ULONG STDMETHODCALLTYPE
GetState()
2786 /* FIXME: Return ABS_ flags? */
2787 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2791 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2793 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2794 *phWndTray
= m_hWnd
;
2798 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2800 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2802 m_DesktopWnd
= hWndDesktop
;
2806 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2808 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2812 virtual HRESULT
RaiseStartButton()
2814 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2820 m_Position
= (DWORD
) -1;
2823 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2825 DECLARE_PROTECT_FINAL_CONSTRUCT()
2826 BEGIN_COM_MAP(CTrayWindow
)
2827 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2828 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2832 class CTrayWindowCtxMenu
:
2833 public CComCoClass
<CTrayWindowCtxMenu
>,
2834 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2838 CComPtr
<CTrayWindow
> TrayWnd
;
2839 CComPtr
<IContextMenu
> pcm
;
2842 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2844 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2845 this->hWndOwner
= hWndOwner
;
2849 virtual HRESULT STDMETHODCALLTYPE
2850 QueryContextMenu(HMENU hPopup
,
2856 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
2859 return HRESULT_FROM_WIN32(GetLastError());
2861 int count
= ::GetMenuItemCount(menubase
);
2863 for (int i
= 0; i
< count
; i
++)
2867 MENUITEMINFOW mii
= { 0 };
2868 mii
.cbSize
= sizeof(mii
);
2869 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2870 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2871 mii
.dwTypeData
= label
;
2872 mii
.cch
= _countof(label
);
2873 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2875 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
2877 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
2880 ::DestroyMenu(menubase
);
2882 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2889 CheckMenuItem(hPopup
,
2891 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
2893 if (TrayWnd
->m_TrayBandSite
!= NULL
)
2895 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
2903 WARN("AddContextMenus failed.\n");
2911 virtual HRESULT STDMETHODCALLTYPE
2912 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2914 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
2917 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
2919 CMINVOKECOMMANDINFO cmici
= { 0 };
2923 /* Setup and invoke the shell command */
2924 cmici
.cbSize
= sizeof(cmici
);
2925 cmici
.hwnd
= hWndOwner
;
2926 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- ID_SHELL_CMD_FIRST
);
2927 cmici
.nShow
= SW_NORMAL
;
2929 pcm
->InvokeCommand(&cmici
);
2934 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
2941 virtual HRESULT STDMETHODCALLTYPE
2942 GetCommandString(UINT_PTR idCmd
,
2951 CTrayWindowCtxMenu()
2955 virtual ~CTrayWindowCtxMenu()
2959 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
2960 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
2964 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
2966 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
2967 mnu
->Initialize(TrayWnd
, hWndOwner
);
2972 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
2974 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
2976 return E_OUTOFMEMORY
;
2981 *ppTray
= (ITrayWindow
*) Tray
;
2987 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
2989 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
2990 return TrayWindow
->RaiseStartButton();
2993 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
2995 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
2996 TrayWindow
->TrayProcessMessages();
2999 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3001 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3002 TrayWindow
->TrayMessageLoop();