4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * this library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * this library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
26 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
28 #define TIMER_ID_AUTOHIDE 1
29 #define TIMER_ID_MOUSETRACK 2
30 #define MOUSETRACK_INTERVAL 100
31 #define AUTOHIDE_DELAY_HIDE 2000
32 #define AUTOHIDE_DELAY_SHOW 50
33 #define AUTOHIDE_INTERVAL_ANIMATING 10
35 #define AUTOHIDE_SPEED_SHOW 10
36 #define AUTOHIDE_SPEED_HIDE 1
38 #define AUTOHIDE_HIDDEN 0
39 #define AUTOHIDE_SHOWING 1
40 #define AUTOHIDE_SHOWN 2
41 #define AUTOHIDE_HIDING 3
43 #define IDHK_RUN 0x1f4
44 #define IDHK_MINIMIZE_ALL 0x1f5
45 #define IDHK_RESTORE_ALL 0x1f6
46 #define IDHK_HELP 0x1f7
47 #define IDHK_EXPLORE 0x1f8
48 #define IDHK_FIND 0x1f9
49 #define IDHK_FIND_COMPUTER 0x1fa
50 #define IDHK_NEXT_TASK 0x1fb
51 #define IDHK_PREV_TASK 0x1fc
52 #define IDHK_SYS_PROPERTIES 0x1fd
53 #define IDHK_DESKTOP 0x1fe
54 #define IDHK_PAGER 0x1ff
56 static const WCHAR szTrayWndClass
[] = L
"Shell_TrayWnd";
62 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
67 HIMAGELIST m_ImageList
;
80 virtual ~CStartButton()
82 if (m_ImageList
!= NULL
)
83 ImageList_Destroy(m_ImageList
);
98 if (m_ImageList
== NULL
||
99 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
101 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
) + GetSystemMetrics(SM_CYCAPTION
) * 3;
104 if (GetWindowTheme(m_hWnd
))
105 Size
.cy
= max(Size
.cy
, GetSystemMetrics(SM_CYCAPTION
));
107 Size
.cy
= max(Size
.cy
, GetSystemMetrics(SM_CYSIZE
) + (2 * GetSystemMetrics(SM_CYEDGE
)));
109 /* Save the size of the start button */
115 /* Get the system fonts, we use the caption font, always bold, though. */
116 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
117 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
121 DeleteObject(m_Font
);
123 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
124 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
126 SetFont(m_Font
, FALSE
);
131 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
133 m_ImageList
= ImageList_LoadImageW(hExplorerInstance
,
134 MAKEINTRESOURCEW(IDB_START
),
137 LR_LOADTRANSPARENT
| LR_CREATEDIBSECTION
);
139 BUTTON_IMAGELIST bil
= {m_ImageList
, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT
};
140 SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
);
144 HWND
Create(HWND hwndParent
)
146 WCHAR szStartCaption
[32];
147 if (!LoadStringW(hExplorerInstance
,
150 _countof(szStartCaption
)))
152 wcscpy(szStartCaption
, L
"Start");
155 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| BS_PUSHBUTTON
| BS_LEFT
| BS_VCENTER
;
157 m_hWnd
= CreateWindowEx(
164 (HMENU
) IDC_STARTBTN
,
176 public CComCoClass
<CTrayWindow
>,
177 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
178 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
180 public IShellDesktopTray
182 CStartButton m_StartButton
;
184 CComPtr
<IMenuBand
> m_StartMenuBand
;
185 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
196 CTrayNotifyWnd
* m_TrayNotifyInstance
;
200 HMONITOR m_PreviousMonitor
;
201 DWORD m_DraggingPosition
;
202 HMONITOR m_DraggingMonitor
;
207 HWND m_TrayPropertiesOwner
;
208 HWND m_RunFileDlgOwner
;
210 UINT m_AutoHideState
;
211 SIZE m_AutoHideOffset
;
212 TRACKMOUSEEVENT m_MouseTrackingInfo
;
214 HDPA m_ShellServices
;
217 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
225 DWORD AlwaysOnTop
: 1;
226 DWORD SmSmallIcons
: 1;
231 DWORD InSizeMove
: 1;
232 DWORD IsDragging
: 1;
233 DWORD NewPosSize
: 1;
248 m_PreviousMonitor(NULL
),
249 m_DraggingPosition(0),
250 m_DraggingMonitor(NULL
),
251 m_TrayPropertiesOwner(NULL
),
252 m_RunFileDlgOwner(NULL
),
253 m_AutoHideState(NULL
),
254 m_ShellServices(NULL
),
257 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
258 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
259 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
260 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
263 virtual ~CTrayWindow()
265 if (m_ShellServices
!= NULL
)
267 ShutdownShellServices(m_ShellServices
);
268 m_ShellServices
= NULL
;
273 DeleteObject(m_Font
);
279 CloseThemeData(m_Theme
);
290 /**********************************************************
291 * ##### command handling #####
294 HRESULT
ExecResourceCmd(int id
)
296 WCHAR szCommand
[256];
297 WCHAR
*pszParameters
;
299 if (!LoadStringW(hExplorerInstance
,
302 _countof(szCommand
)))
307 pszParameters
= wcschr(szCommand
, L
'>');
314 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
318 LRESULT
DoExitWindows()
320 ExitWindowsDialog(m_hWnd
);
324 DWORD WINAPI
RunFileDlgThread()
329 m_StartButton
.GetWindowRect(&posRect
);
331 hwnd
= CreateWindowEx(0,
334 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
337 posRect
.right
- posRect
.left
,
338 posRect
.bottom
- posRect
.top
,
344 m_RunFileDlgOwner
= hwnd
;
346 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
348 m_RunFileDlgOwner
= NULL
;
349 ::DestroyWindow(hwnd
);
354 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
356 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
357 return This
->RunFileDlgThread();
360 void DisplayRunFileDlg()
363 if (m_RunFileDlgOwner
)
365 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
366 if (hRunDlg
!= NULL
&&
367 hRunDlg
!= m_RunFileDlgOwner
)
369 SetForegroundWindow(hRunDlg
);
374 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
377 DWORD WINAPI
TrayPropertiesThread()
382 m_StartButton
.GetWindowRect(&posRect
);
383 hwnd
= CreateWindowEx(0,
386 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
389 posRect
.right
- posRect
.left
,
390 posRect
.bottom
- posRect
.top
,
396 m_TrayPropertiesOwner
= hwnd
;
398 DisplayTrayProperties(hwnd
);
400 m_TrayPropertiesOwner
= NULL
;
401 ::DestroyWindow(hwnd
);
406 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
408 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
410 return This
->TrayPropertiesThread();
413 HWND STDMETHODCALLTYPE
DisplayProperties()
417 if (m_TrayPropertiesOwner
)
419 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
420 if (hTrayProp
!= NULL
&&
421 hTrayProp
!= m_TrayPropertiesOwner
)
423 SetForegroundWindow(hTrayProp
);
428 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
432 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
434 WCHAR szDir
[MAX_PATH
];
436 if (SHGetSpecialFolderPath(hWndOwner
,
438 CSIDL_COMMON_STARTMENU
,
441 ShellExecute(hWndOwner
,
450 VOID
OpenTaskManager(IN HWND hWndOwner
)
452 ShellExecute(hWndOwner
,
460 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
464 case ID_SHELL_CMD_PROPERTIES
:
468 case ID_SHELL_CMD_OPEN_ALL_USERS
:
469 OpenCommonStartMenuDirectory(m_hWnd
,
473 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
474 OpenCommonStartMenuDirectory(m_hWnd
,
479 if (SHRestricted(REST_CLASSICSHELL
) == 0)
485 case ID_SHELL_CMD_OPEN_TASKMGR
:
486 OpenTaskManager(m_hWnd
);
489 case ID_SHELL_CMD_UNDO_ACTION
:
492 case ID_SHELL_CMD_SHOW_DESKTOP
:
495 case ID_SHELL_CMD_TILE_WND_H
:
496 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
499 case ID_SHELL_CMD_TILE_WND_V
:
500 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
503 case ID_SHELL_CMD_CASCADE_WND
:
504 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
507 case ID_SHELL_CMD_CUST_NOTIF
:
508 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
511 case ID_SHELL_CMD_ADJUST_DAT
:
512 //FIXME: Use SHRunControlPanel
513 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
517 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
524 LRESULT
HandleHotKey(DWORD id
)
532 ExecResourceCmd(IDS_HELP_COMMAND
);
535 //FIXME: We don't support this yet:
536 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
537 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
540 SHFindFiles(NULL
, NULL
);
542 case IDHK_FIND_COMPUTER
:
543 SHFindComputer(NULL
, NULL
);
545 case IDHK_SYS_PROPERTIES
:
546 //FIXME: Use SHRunControlPanel
547 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
553 case IDHK_MINIMIZE_ALL
:
555 case IDHK_RESTORE_ALL
:
566 LRESULT
HandleCommand(UINT uCommand
)
570 case IDM_TASKBARANDSTARTMENU
:
575 SHFindFiles(NULL
, NULL
);
578 case IDM_HELPANDSUPPORT
:
579 ExecResourceCmd(IDS_HELP_COMMAND
);
586 /* FIXME: Handle these commands as well */
587 case IDM_SYNCHRONIZE
:
589 case IDM_UNDOCKCOMPUTER
:
593 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
607 IN POINT
*ppt OPTIONAL
,
608 IN HWND hwndExclude OPTIONAL
,
610 IN BOOL IsContextMenu
)
612 TPMPARAMS tmp
, *ptmp
= NULL
;
617 if (hwndExclude
!= NULL
)
619 /* Get the client rectangle and map it to screen coordinates */
620 if (::GetClientRect(hwndExclude
,
622 ::MapWindowPoints(hwndExclude
,
624 (LPPOINT
) &tmp
.rcExclude
,
634 GetClientRect(&tmp
.rcExclude
) &&
637 (LPPOINT
) &tmp
.rcExclude
,
645 /* NOTE: TrackPopupMenuEx will eventually align the track position
646 for us, no need to take care of it here as long as the
647 coordinates are somewhere within the exclusion rectangle */
648 pt
.x
= ptmp
->rcExclude
.left
;
649 pt
.y
= ptmp
->rcExclude
.top
;
657 tmp
.cbSize
= sizeof(tmp
);
659 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
660 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
662 fuFlags
|= TPM_RIGHTBUTTON
;
664 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
666 cmdId
= TrackPopupMenuEx(hMenu
,
676 HRESULT
TrackCtxMenu(
677 IN IContextMenu
* contextMenu
,
678 IN POINT
*ppt OPTIONAL
,
679 IN HWND hwndExclude OPTIONAL
,
681 IN PVOID Context OPTIONAL
)
687 HMENU popup
= CreatePopupMenu();
692 TRACE("Before Query\n");
693 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
694 if (FAILED_UNEXPECTEDLY(hr
))
696 TRACE("Query failed\n");
701 TRACE("Before Tracking\n");
702 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
706 TRACE("Before InvokeCommand\n");
707 CMINVOKECOMMANDINFO cmi
= { 0 };
708 cmi
.cbSize
= sizeof(cmi
);
709 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
711 hr
= contextMenu
->InvokeCommand(&cmi
);
715 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
727 /**********************************************************
728 * ##### moving and sizing handling #####
733 m_StartButton
.UpdateFont();
735 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
736 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
738 ERR("SPI_GETNONCLIENTMETRICS failed\n");
743 DeleteObject(m_Font
);
745 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
746 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
749 ERR("CreateFontIndirect failed\n");
753 SendMessage(m_Rebar
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
754 SendMessage(m_TaskSwitch
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
755 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
758 HMONITOR
GetScreenRectFromRect(
765 mi
.cbSize
= sizeof(mi
);
766 hMon
= MonitorFromRect(pRect
, dwFlags
);
768 GetMonitorInfo(hMon
, &mi
))
770 *pRect
= mi
.rcMonitor
;
776 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
777 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
785 HMONITOR
GetMonitorFromRect(
786 IN
const RECT
*pRect
)
790 /* In case the monitor sizes or saved sizes differ a bit (probably
791 not a lot, only so the tray window overlaps into another monitor
792 now), minimize the risk that we determine a wrong monitor by
793 using the center point of the tray window if we can't determine
794 it using the rectangle. */
795 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
800 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
801 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
803 /* be less error-prone, find the nearest monitor */
804 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
810 HMONITOR
GetScreenRect(
811 IN HMONITOR hMonitor
,
814 HMONITOR hMon
= NULL
;
816 if (hMonitor
!= NULL
)
820 mi
.cbSize
= sizeof(mi
);
821 if (!GetMonitorInfo(hMonitor
, &mi
))
823 /* Hm, the monitor is gone? Try to find a monitor where it
824 could be located now */
825 hMon
= GetMonitorFromRect(pRect
);
827 !GetMonitorInfo(hMon
, &mi
))
834 *pRect
= mi
.rcMonitor
;
841 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
842 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
848 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
853 rc
->bottom
-= GetSystemMetrics(SM_CXSIZEFRAME
);
856 rc
->top
+= GetSystemMetrics(SM_CXSIZEFRAME
);
859 rc
->right
-= GetSystemMetrics(SM_CYSIZEFRAME
);
862 rc
->left
+= GetSystemMetrics(SM_CYSIZEFRAME
);
868 VOID
MakeTrayRectWithSize(IN DWORD Position
,
869 IN
const SIZE
*pTraySize
,
875 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
879 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
883 pRect
->left
= pRect
->right
- pTraySize
->cx
;
888 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
893 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
894 IN
const RECT
*pScreen
,
895 IN
const SIZE
*pTraySize OPTIONAL
,
898 if (pTraySize
== NULL
)
899 pTraySize
= &m_TraySize
;
905 /* Move the border outside of the screen */
907 GetSystemMetrics(SM_CXEDGE
),
908 GetSystemMetrics(SM_CYEDGE
));
911 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
914 BOOL
IsPosHorizontal()
916 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
919 HMONITOR
CalculateValidSize(
928 //Horizontal = IsPosHorizontal();
930 szWnd
.cx
= pRect
->right
- pRect
->left
;
931 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
934 hMon
= GetScreenRectFromRect(
936 MONITOR_DEFAULTTONEAREST
);
938 /* Calculate the maximum size of the tray window and limit the window
939 size to half of the screen's size. */
940 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
941 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
942 if (szWnd
.cx
> szMax
.cx
)
944 if (szWnd
.cy
> szMax
.cy
)
947 /* FIXME - calculate */
949 GetTrayRectFromScreenRect(Position
,
959 GetMinimumWindowSize(
964 AdjustWindowRectEx(&rcMin
,
965 GetWindowLong(m_hWnd
,
968 GetWindowLong(m_hWnd
,
976 DWORD
GetDraggingRectFromPt(
979 OUT HMONITOR
*phMonitor
)
981 HMONITOR hMon
, hMonNew
;
982 DWORD PosH
, PosV
, Pos
;
983 SIZE DeltaPt
, ScreenOffset
;
989 /* Determine the screen rectangle */
990 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
995 mi
.cbSize
= sizeof(mi
);
996 if (!GetMonitorInfo(hMon
, &mi
))
999 goto GetPrimaryScreenRect
;
1002 /* make left top corner of the screen zero based to
1003 make calculations easier */
1004 pt
.x
-= mi
.rcMonitor
.left
;
1005 pt
.y
-= mi
.rcMonitor
.top
;
1007 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1008 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1009 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1010 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1014 GetPrimaryScreenRect
:
1015 ScreenOffset
.cx
= 0;
1016 ScreenOffset
.cy
= 0;
1017 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1018 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1021 /* Calculate the nearest screen border */
1022 if (pt
.x
< rcScreen
.right
/ 2)
1029 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1033 if (pt
.y
< rcScreen
.bottom
/ 2)
1040 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1044 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1046 /* Fix the screen origin to be relative to the primary monitor again */
1047 OffsetRect(&rcScreen
,
1051 RECT rcPos
= m_TrayRects
[Pos
];
1053 hMonNew
= GetMonitorFromRect(&rcPos
);
1054 if (hMon
!= hMonNew
)
1058 /* Recalculate the rectangle, we're dragging to another monitor.
1059 We don't need to recalculate the rect on single monitor systems. */
1060 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1061 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1063 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1066 pRect
->left
+= m_AutoHideOffset
.cx
;
1067 pRect
->right
+= m_AutoHideOffset
.cx
;
1068 pRect
->top
+= m_AutoHideOffset
.cy
;
1069 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1075 /* The user is dragging the tray window on the same monitor. We don't need
1076 to recalculate the rectangle */
1080 pRect
->left
+= m_AutoHideOffset
.cx
;
1081 pRect
->right
+= m_AutoHideOffset
.cx
;
1082 pRect
->top
+= m_AutoHideOffset
.cy
;
1083 pRect
->bottom
+= m_AutoHideOffset
.cy
;
1092 DWORD
GetDraggingRectFromRect(
1094 OUT HMONITOR
*phMonitor
)
1098 /* Calculate the center of the rectangle. We call
1099 GetDraggingRectFromPt to calculate a valid
1100 dragging rectangle */
1101 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1102 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1104 return GetDraggingRectFromPt(
1110 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1116 rcTray
.left
= pwp
->x
;
1117 rcTray
.top
= pwp
->y
;
1118 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1119 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1122 rcTray
.left
-= m_AutoHideOffset
.cx
;
1123 rcTray
.right
-= m_AutoHideOffset
.cx
;
1124 rcTray
.top
-= m_AutoHideOffset
.cy
;
1125 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1128 if (!EqualRect(&rcTray
,
1129 &m_TrayRects
[m_DraggingPosition
]))
1131 /* Recalculate the rectangle, the user dragged the tray
1132 window to another monitor or the window was somehow else
1134 m_DraggingPosition
= GetDraggingRectFromRect(
1136 &m_DraggingMonitor
);
1137 //m_TrayRects[DraggingPosition] = rcTray;
1140 //Monitor = CalculateValidSize(DraggingPosition,
1143 m_Monitor
= m_DraggingMonitor
;
1144 m_Position
= m_DraggingPosition
;
1147 m_TrayRects
[m_Position
] = rcTray
;
1150 else if (GetWindowRect(&rcTray
))
1154 if (!(pwp
->flags
& SWP_NOMOVE
))
1156 rcTray
.left
= pwp
->x
;
1157 rcTray
.top
= pwp
->y
;
1160 if (!(pwp
->flags
& SWP_NOSIZE
))
1162 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1163 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1166 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1168 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1175 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1180 rcTray
.left
-= m_AutoHideOffset
.cx
;
1181 rcTray
.right
-= m_AutoHideOffset
.cx
;
1182 rcTray
.top
-= m_AutoHideOffset
.cy
;
1183 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
1185 m_TrayRects
[m_Position
] = rcTray
;
1189 /* If the user isn't resizing the tray window we need to make sure the
1190 new size or position is valid. this is to prevent changes to the window
1191 without user interaction. */
1192 rcTray
= m_TrayRects
[m_Position
];
1196 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1197 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1201 rcTray
.left
+= m_AutoHideOffset
.cx
;
1202 rcTray
.right
+= m_AutoHideOffset
.cx
;
1203 rcTray
.top
+= m_AutoHideOffset
.cy
;
1204 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1207 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1208 pwp
->x
= rcTray
.left
;
1209 pwp
->y
= rcTray
.top
;
1210 pwp
->cx
= m_TraySize
.cx
;
1211 pwp
->cy
= m_TraySize
.cy
;
1215 VOID
ApplyClipping(IN BOOL Clip
)
1217 RECT rcClip
, rcWindow
;
1220 if (GetWindowRect(&rcWindow
))
1222 /* Disable clipping on systems with only one monitor */
1223 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1230 GetScreenRect(m_Monitor
, &rcClip
);
1232 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1241 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1246 /* Set the clipping region or make sure the window isn't clipped
1247 by disabling it explicitly. */
1248 SetWindowRgn(hClipRgn
, TRUE
);
1252 VOID
ResizeWorkArea()
1254 #if !WIN7_DEBUG_MODE
1255 RECT rcTray
, rcWorkArea
;
1257 /* If monitor has changed then fix the previous monitors work area */
1258 if (m_PreviousMonitor
!= m_Monitor
)
1260 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1261 SystemParametersInfoW(SPI_SETWORKAREA
,
1267 rcTray
= m_TrayRects
[m_Position
];
1269 GetScreenRect(m_Monitor
, &rcWorkArea
);
1270 m_PreviousMonitor
= m_Monitor
;
1272 /* If AutoHide is false then change the workarea to exclude
1273 the area that the taskbar covers. */
1279 rcWorkArea
.top
= rcTray
.bottom
;
1282 rcWorkArea
.left
= rcTray
.right
;
1285 rcWorkArea
.right
= rcTray
.left
;
1288 rcWorkArea
.bottom
= rcTray
.top
;
1294 * Resize the current monitor work area. Win32k will also send
1295 * a WM_SIZE message to automatically resize the desktop.
1297 SystemParametersInfoW(SPI_SETWORKAREA
,
1304 VOID
CheckTrayWndPosition()
1308 rcTray
= m_TrayRects
[m_Position
];
1312 rcTray
.left
+= m_AutoHideOffset
.cx
;
1313 rcTray
.right
+= m_AutoHideOffset
.cx
;
1314 rcTray
.top
+= m_AutoHideOffset
.cy
;
1315 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1318 IUnknown_Exec(m_TrayBandSite
,
1320 DBID_BANDINFOCHANGED
,
1325 FitToRebar(&rcTray
);
1326 m_TrayRects
[m_Position
] = rcTray
;
1328 /* Move the tray window */
1332 rcTray
.right
- rcTray
.left
,
1333 rcTray
.bottom
- rcTray
.top
,
1334 SWP_NOZORDER
| SWP_NOACTIVATE
);
1338 ApplyClipping(TRUE
);
1341 typedef struct _TW_STUCKRECTS2
1349 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1351 VOID
RegLoadSettings()
1356 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1357 DWORD cbSize
= sizeof(sr
);
1358 SIZE StartBtnSize
= m_StartButton
.GetSize();
1360 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1361 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1362 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1363 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1365 if (SHGetValue(hkExplorer
,
1366 TEXT("StuckRects2"),
1370 &cbSize
) == ERROR_SUCCESS
&&
1371 sr
.cbSize
== sizeof(sr
))
1373 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1374 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1375 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1376 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1378 /* FIXME: Are there more flags? */
1381 m_Position
= ABE_LEFT
;
1383 if (sr
.Position
> ABE_BOTTOM
)
1384 m_Position
= ABE_BOTTOM
;
1386 m_Position
= sr
.Position
;
1389 /* Try to find out which monitor the tray window was located on last.
1390 Here we're only interested in the monitor screen that we think
1391 is the last one used. We're going to determine on which monitor
1392 we really are after calculating the docked position. */
1394 GetScreenRectFromRect(
1396 MONITOR_DEFAULTTONEAREST
);
1400 m_Position
= ABE_BOTTOM
;
1403 /* Use the minimum size of the taskbar, we'll use the start
1404 button as a minimum for now. Make sure we calculate the
1405 entire window size, not just the client size. However, we
1406 use a thinner border than a standard thick border, so that
1407 the start button and bands are not stuck to the screen border. */
1408 if(!IsThemeActive())
1410 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1411 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1415 sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1416 sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1418 sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1421 /* Use the primary screen by default */
1424 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1425 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1426 GetScreenRectFromRect(
1428 MONITOR_DEFAULTTOPRIMARY
);
1433 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1438 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1440 /* Determine a minimum tray window rectangle. The "client" height is
1441 zero here since we cannot determine an optimal minimum width when
1442 loaded as a vertical tray window. We just need to make sure the values
1443 loaded from the registry are at least. The windows explorer behaves
1444 the same way, it allows the user to save a zero width vertical tray
1445 window, but not a zero height horizontal tray window. */
1446 if(!IsThemeActive())
1448 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1449 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1453 WndSize
.cx
= StartBtnSize
.cx
;
1454 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1457 if (WndSize
.cx
< sr
.Size
.cx
)
1458 WndSize
.cx
= sr
.Size
.cx
;
1459 if (WndSize
.cy
< sr
.Size
.cy
)
1460 WndSize
.cy
= sr
.Size
.cy
;
1462 /* Save the calculated size */
1463 m_TraySize
= WndSize
;
1465 /* Calculate all docking rectangles. We need to do this here so they're
1466 initialized and dragging the tray window to another position gives
1468 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1470 GetTrayRectFromScreenRect(Pos
,
1474 // 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);
1477 /* Determine which monitor we are on. It shouldn't matter which docked
1478 position rectangle we use */
1479 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1482 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1485 SIZE TraySize
, StartSize
;
1486 POINT ptTrayNotify
= { 0, 0 };
1490 m_StartButton
.UpdateSize();
1491 if (prcClient
!= NULL
)
1493 rcClient
= *prcClient
;
1497 if (!GetClientRect(&rcClient
))
1499 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1504 Horizontal
= IsPosHorizontal();
1506 /* We're about to resize/move the start button, the rebar control and
1507 the tray notification control */
1508 dwp
= BeginDeferWindowPos(3);
1511 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1515 /* Limit the Start button width to the client width, if necessary */
1516 StartSize
= m_StartButton
.GetSize();
1517 if (StartSize
.cx
> rcClient
.right
)
1518 StartSize
.cx
= rcClient
.right
;
1520 if (m_StartButton
.m_hWnd
!= NULL
)
1522 /* Resize and reposition the button */
1523 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1529 SWP_NOZORDER
| SWP_NOACTIVATE
);
1532 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1537 /* Determine the size that the tray notification window needs */
1541 TraySize
.cy
= rcClient
.bottom
;
1545 TraySize
.cx
= rcClient
.right
;
1549 if (m_TrayNotify
!= NULL
&&
1550 SendMessage(m_TrayNotify
,
1551 TNWM_GETMINIMUMSIZE
,
1555 /* Move the tray notification window to the desired location */
1557 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1559 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1561 dwp
= ::DeferWindowPos(dwp
,
1568 SWP_NOZORDER
| SWP_NOACTIVATE
);
1571 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1576 /* Resize/Move the rebar control */
1577 if (m_Rebar
!= NULL
)
1579 POINT ptRebar
= { 0, 0 };
1582 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1586 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1587 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1588 szRebar
.cy
= rcClient
.bottom
;
1592 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1593 szRebar
.cx
= rcClient
.right
;
1594 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1597 dwp
= ::DeferWindowPos(dwp
,
1604 SWP_NOZORDER
| SWP_NOACTIVATE
);
1608 EndDeferWindowPos(dwp
);
1610 if (m_TaskSwitch
!= NULL
)
1612 /* Update the task switch window configuration */
1613 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1617 void FitToRebar(PRECT pRect
)
1619 /* Get the rect of the rebar */
1620 RECT rebarRect
, taskbarRect
;
1621 ::GetWindowRect(m_Rebar
, &rebarRect
);
1622 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1623 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1625 /* Calculate the difference of size of the taskbar and the rebar */
1627 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- rebarRect
.right
+ rebarRect
.left
;
1628 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- rebarRect
.bottom
+ rebarRect
.top
;
1630 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1634 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1635 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1636 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1639 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1640 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1641 ERR("rebarRect: %d, %d, %d,%d\n", rebarRect
.top
, rebarRect
.left
, rebarRect
.right
, rebarRect
.bottom
);
1642 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1646 /* FIXME: what to do here? */
1650 CalculateValidSize(m_Position
, pRect
);
1653 void PopupStartMenu()
1655 if (m_StartMenuPopup
!= NULL
)
1661 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1666 pt
.x
= rcExclude
.left
;
1667 pt
.y
= rcExclude
.top
;
1668 dwFlags
|= MPPF_TOP
;
1671 pt
.x
= rcExclude
.left
;
1672 pt
.y
= rcExclude
.bottom
;
1673 dwFlags
|= MPPF_BOTTOM
;
1676 pt
.x
= rcExclude
.right
;
1677 pt
.y
= rcExclude
.top
;
1678 dwFlags
|= MPPF_RIGHT
;
1681 pt
.x
= rcExclude
.left
;
1682 pt
.y
= rcExclude
.top
;
1683 dwFlags
|= MPPF_LEFT
;
1687 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1689 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1694 void ProcessMouseTracking()
1699 UINT state
= m_AutoHideState
;
1702 GetWindowRect(&rcCurrent
);
1703 over
= PtInRect(&rcCurrent
, pt
);
1705 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1712 if (state
== AUTOHIDE_HIDING
)
1714 TRACE("AutoHide cancelling hide.\n");
1715 m_AutoHideState
= AUTOHIDE_SHOWING
;
1716 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1718 else if (state
== AUTOHIDE_HIDDEN
)
1720 TRACE("AutoHide starting show.\n");
1721 m_AutoHideState
= AUTOHIDE_SHOWING
;
1722 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1727 if (state
== AUTOHIDE_SHOWING
)
1729 TRACE("AutoHide cancelling show.\n");
1730 m_AutoHideState
= AUTOHIDE_HIDING
;
1731 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1733 else if (state
== AUTOHIDE_SHOWN
)
1735 TRACE("AutoHide starting hide.\n");
1736 m_AutoHideState
= AUTOHIDE_HIDING
;
1737 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1740 KillTimer(TIMER_ID_MOUSETRACK
);
1744 void ProcessAutoHide()
1746 RECT rc
= m_TrayRects
[m_Position
];
1747 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1748 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1750 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
);
1752 switch (m_AutoHideState
)
1754 case AUTOHIDE_HIDING
:
1758 m_AutoHideOffset
.cy
= 0;
1759 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1760 if (m_AutoHideOffset
.cx
< -w
)
1761 m_AutoHideOffset
.cx
= -w
;
1764 m_AutoHideOffset
.cx
= 0;
1765 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1766 if (m_AutoHideOffset
.cy
< -h
)
1767 m_AutoHideOffset
.cy
= -h
;
1770 m_AutoHideOffset
.cy
= 0;
1771 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1772 if (m_AutoHideOffset
.cx
> w
)
1773 m_AutoHideOffset
.cx
= w
;
1776 m_AutoHideOffset
.cx
= 0;
1777 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1778 if (m_AutoHideOffset
.cy
> h
)
1779 m_AutoHideOffset
.cy
= h
;
1783 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1785 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1790 case AUTOHIDE_HIDDEN
:
1795 m_AutoHideOffset
.cx
= -w
;
1796 m_AutoHideOffset
.cy
= 0;
1799 m_AutoHideOffset
.cx
= 0;
1800 m_AutoHideOffset
.cy
= -h
;
1803 m_AutoHideOffset
.cx
= w
;
1804 m_AutoHideOffset
.cy
= 0;
1807 m_AutoHideOffset
.cx
= 0;
1808 m_AutoHideOffset
.cy
= h
;
1812 KillTimer(TIMER_ID_AUTOHIDE
);
1813 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1816 case AUTOHIDE_SHOWING
:
1817 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1819 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1821 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1823 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1827 m_AutoHideOffset
.cx
= 0;
1830 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1832 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1834 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1836 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1840 m_AutoHideOffset
.cy
= 0;
1843 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1845 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1850 case AUTOHIDE_SHOWN
:
1852 KillTimer(TIMER_ID_AUTOHIDE
);
1853 m_AutoHideState
= AUTOHIDE_SHOWN
;
1857 rc
.left
+= m_AutoHideOffset
.cx
;
1858 rc
.right
+= m_AutoHideOffset
.cx
;
1859 rc
.top
+= m_AutoHideOffset
.cy
;
1860 rc
.bottom
+= m_AutoHideOffset
.cy
;
1862 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
1863 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
1870 /**********************************************************
1871 * ##### taskbar drawing #####
1874 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1880 GetClientRect(&rect
);
1884 GetClientRect(&rect
);
1888 partId
= TBP_BACKGROUNDLEFT
;
1891 partId
= TBP_BACKGROUNDTOP
;
1894 partId
= TBP_BACKGROUNDRIGHT
;
1898 partId
= TBP_BACKGROUNDBOTTOM
;
1901 res
= DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1907 int DrawSizerWithTheme(IN HRGN hRgn
)
1913 GetWindowRect(&rect
);
1914 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1916 hdc
= GetWindowDC();
1921 backgroundPart
= TBP_SIZINGBARLEFT
;
1922 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1925 backgroundPart
= TBP_SIZINGBARTOP
;
1926 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1929 backgroundPart
= TBP_SIZINGBARRIGHT
;
1930 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1934 backgroundPart
= TBP_SIZINGBARBOTTOM
;
1935 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1938 if (IsThemeBackgroundPartiallyTransparent(m_Theme
, backgroundPart
, 0))
1940 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1942 DrawThemeBackground(m_Theme
, hdc
, backgroundPart
, 0, &rect
, 0);
1955 HRESULT STDMETHODCALLTYPE
Open()
1959 /* Check if there's already a window created and try to show it.
1960 If it was somehow destroyed just create a new tray window. */
1961 if (m_hWnd
!= NULL
&& IsWindow())
1966 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1968 dwExStyle
|= WS_EX_TOPMOST
;
1970 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
1971 if(!IsThemeActive())
1973 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
1976 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1977 if (m_Position
!= (DWORD
) -1)
1978 rcWnd
= m_TrayRects
[m_Position
];
1980 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1983 /* Align all controls on the tray window */
1984 AlignControls(NULL
);
1986 /* Move the tray window to the right position and resize it if necessary */
1987 CheckTrayWndPosition();
1992 HRESULT STDMETHODCALLTYPE
Close()
2005 HWND STDMETHODCALLTYPE
GetHWND()
2010 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2012 return (m_hWnd
== hWnd
||
2013 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2016 BOOL STDMETHODCALLTYPE
IsHorizontal()
2018 return IsPosHorizontal();
2021 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2023 BOOL bPrevLock
= Locked
;
2025 if (Locked
!= bLock
)
2029 if (m_TrayBandSite
!= NULL
)
2031 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2041 /* Update cached tray sizes */
2042 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2044 RECT rcGripper
= {0};
2045 AdjustSizerRect(&rcGripper
, Pos
);
2049 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2050 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2051 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2052 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2056 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2057 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2058 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2059 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2063 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2065 ApplyClipping(TRUE
);
2076 /**********************************************************
2077 * ##### message handling #####
2080 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2082 ((ITrayWindow
*)this)->AddRef();
2084 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2086 /* Create the Start button */
2087 m_StartButton
.Create(m_hWnd
);
2089 /* Load the saved tray window settings */
2092 /* Create and initialize the start menu */
2093 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2094 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2096 /* Create the tray band site and its rebar */
2097 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
2098 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2100 /* Create the tray notification window */
2101 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
2105 InitShellServices(&m_ShellServices
);
2109 m_AutoHideState
= AUTOHIDE_HIDING
;
2110 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2113 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2114 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2115 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2116 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2117 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2118 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2119 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2120 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2121 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2122 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2123 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2124 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2129 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2132 CloseThemeData(m_Theme
);
2134 if (IsThemeActive())
2135 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2141 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2145 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2147 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2152 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2154 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2156 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2158 AlignControls(NULL
);
2159 CheckTrayWndPosition();
2165 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2167 HDC hdc
= (HDC
) wParam
;
2175 return EraseBackgroundWithTheme(hdc
);
2178 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2180 /* Move the tray window to the right position and resize it if necessary */
2181 CheckTrayWndPosition();
2186 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2190 TRACE("WM_COPYDATA notify message received. Handling...\n");
2191 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2196 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2204 return DrawSizerWithTheme((HRGN
) wParam
);
2207 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2209 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2210 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2213 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2220 /* The user may not be able to resize the tray window.
2221 Pretend like the window is not sizeable when the user
2222 clicks on the border. */
2226 SetLastError(ERROR_SUCCESS
);
2227 if (GetClientRect(&rcClient
) &&
2228 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2230 pt
.x
= (SHORT
) LOWORD(lParam
);
2231 pt
.y
= (SHORT
) HIWORD(lParam
);
2233 if (PtInRect(&rcClient
,
2236 /* The user is trying to drag the tray window */
2240 /* Depending on the position of the tray window, allow only
2241 changing the border next to the monitor working area */
2245 if (pt
.y
> rcClient
.bottom
)
2249 if (pt
.x
> rcClient
.right
)
2253 if (pt
.x
< rcClient
.left
)
2258 if (pt
.y
< rcClient
.top
)
2267 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2270 PRECT pRect
= (PRECT
) lParam
;
2272 /* We need to ensure that an application can not accidently
2273 move the tray window (using SetWindowPos). However, we still
2274 need to be able to move the window in case the user wants to
2275 drag the tray window to another position or in case the user
2276 wants to resize the tray window. */
2277 if (!Locked
&& GetCursorPos(&ptCursor
))
2280 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2284 *pRect
= m_TrayRects
[m_Position
];
2288 pRect
->left
+= m_AutoHideOffset
.cx
;
2289 pRect
->right
+= m_AutoHideOffset
.cx
;
2290 pRect
->top
+= m_AutoHideOffset
.cy
;
2291 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2297 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2299 PRECT pRect
= (PRECT
) lParam
;
2307 *pRect
= m_TrayRects
[m_Position
];
2311 pRect
->left
+= m_AutoHideOffset
.cx
;
2312 pRect
->right
+= m_AutoHideOffset
.cx
;
2313 pRect
->top
+= m_AutoHideOffset
.cy
;
2314 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2320 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2322 ChangingWinPos((LPWINDOWPOS
) lParam
);
2326 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2329 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2332 /* Clip the tray window on multi monitor systems so the edges can't
2333 overlap into another monitor */
2334 ApplyClipping(TRUE
);
2336 if (!GetClientRect(&rcClient
))
2343 rcClient
.left
= rcClient
.top
= 0;
2344 rcClient
.right
= LOWORD(lParam
);
2345 rcClient
.bottom
= HIWORD(lParam
);
2348 AlignControls(&rcClient
);
2352 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2358 /* Remove the clipping on multi monitor systems while dragging around */
2359 ApplyClipping(FALSE
);
2364 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2369 /* Apply clipping */
2370 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2375 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2381 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2382 The tray window needs to handle this specially, since it normally doesn't have
2385 static const UINT uidDisableItem
[] = {
2395 /* temporarily enable the system menu */
2396 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2398 hSysMenu
= GetSystemMenu(FALSE
);
2399 if (hSysMenu
!= NULL
)
2401 /* Disable all items that are not relevant */
2402 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2404 EnableMenuItem(hSysMenu
,
2406 MF_BYCOMMAND
| MF_GRAYED
);
2409 EnableMenuItem(hSysMenu
,
2412 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2414 /* Display the system menu */
2418 m_StartButton
.m_hWnd
,
2419 m_Position
!= ABE_TOP
,
2423 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2427 /* revert the system menu window style */
2428 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2438 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2440 /* We want the user to be able to get a context menu even on the nonclient
2441 area (including the sizing border)! */
2442 uMsg
= WM_CONTEXTMENU
;
2443 wParam
= (WPARAM
) m_hWnd
;
2445 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2448 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2450 LRESULT Ret
= FALSE
;
2451 POINT pt
, *ppt
= NULL
;
2452 HWND hWndExclude
= NULL
;
2454 /* Check if the administrator has forbidden access to context menus */
2455 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2458 pt
.x
= (SHORT
) LOWORD(lParam
);
2459 pt
.y
= (SHORT
) HIWORD(lParam
);
2461 if (pt
.x
!= -1 || pt
.y
!= -1)
2464 hWndExclude
= m_StartButton
.m_hWnd
;
2466 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2468 /* Make sure we can't track the context menu if the start
2469 menu is currently being shown */
2470 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2472 CComPtr
<IContextMenu
> ctxMenu
;
2473 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2474 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2479 /* See if the context menu should be handled by the task band site */
2480 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2483 POINT ptClient
= *ppt
;
2485 /* Convert the coordinates to client-coordinates */
2486 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2488 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2489 if (hWndAtPt
!= NULL
&&
2490 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2492 /* Check if the user clicked on the task switch window */
2494 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2496 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2497 if (hWndAtPt
== m_TaskSwitch
)
2498 goto HandleTrayContextMenu
;
2500 /* Forward the message to the task band site */
2501 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2504 goto HandleTrayContextMenu
;
2508 HandleTrayContextMenu
:
2509 /* Tray the default tray window context menu */
2510 CComPtr
<IContextMenu
> ctxMenu
;
2511 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2512 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2518 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2520 LRESULT Ret
= FALSE
;
2521 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2522 the rebar control! But we shouldn't forward messages that the band
2523 site doesn't handle, such as other controls (start button, tray window */
2525 HRESULT hr
= E_FAIL
;
2529 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2534 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2536 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2538 if (nmh
->hwndFrom
== m_TrayNotify
)
2543 /* Cause all controls to be aligned */
2544 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2552 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2554 /* We "handle" this message so users can't cause a weird maximize/restore
2555 window animation when double-clicking the tray window! */
2557 /* We should forward mouse messages to child windows here.
2558 Right now, this is only clock double-click */
2560 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2563 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2564 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2565 if (PtInRect(&rcClock
, ptClick
))
2567 //FIXME: use SHRunControlPanel
2568 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2574 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2580 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2583 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2584 if (FAILED_UNEXPECTEDLY(hr
))
2587 if (::IsWindowVisible(hwndStartMenu
))
2589 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2599 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2602 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2603 * to show the shutdown dialog. Also a WM_CLOSE message sent
2604 * by apps should show the dialog.
2606 return DoExitWindows();
2609 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2611 if (wParam
== SC_CLOSE
)
2613 return DoExitWindows();
2620 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2622 return HandleHotKey(wParam
);
2625 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2627 LRESULT Ret
= FALSE
;
2629 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2635 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2637 return HandleCommand(LOWORD(wParam
));
2642 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2646 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2652 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2654 if (wParam
== TIMER_ID_MOUSETRACK
)
2656 ProcessMouseTracking();
2658 else if (wParam
== TIMER_ID_AUTOHIDE
)
2667 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2670 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2671 if(!IsThemeActive() || Locked
)
2682 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2683 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2688 rc
= &prms
->rgrc
[0];
2691 AdjustSizerRect(rc
, m_Position
);
2696 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2699 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2705 ::GetWindowRect(m_hWnd
, &rc
);
2709 rc
.bottom
- rc
.top
};
2711 as
->rcTarget
.right
- as
->rcTarget
.left
,
2712 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2714 as
->rcActual
.right
- as
->rcActual
.left
,
2715 as
->rcActual
.bottom
- as
->rcActual
.top
};
2718 szWindow
.cx
- szTarget
.cx
,
2719 szWindow
.cy
- szTarget
.cx
,
2725 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2728 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2731 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2732 rc
.left
= rc
.right
- szWindow
.cy
;
2735 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2736 rc
.top
= rc
.bottom
- szWindow
.cy
;
2740 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2747 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2749 BEGIN_MSG_MAP(CTrayWindow
)
2750 if (m_StartMenuBand
!= NULL
)
2757 Msg
.wParam
= wParam
;
2758 Msg
.lParam
= lParam
;
2760 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2765 wParam
= Msg
.wParam
;
2766 lParam
= Msg
.lParam
;
2768 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2769 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
2770 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2771 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2772 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2773 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2774 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2775 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2776 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2777 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2778 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2779 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2780 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2781 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2782 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2783 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2784 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2785 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2786 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2787 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2788 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2789 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2790 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2791 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2792 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2793 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2794 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2795 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2796 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2797 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2798 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
2799 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2800 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
2804 /*****************************************************************************/
2806 VOID
TrayProcessMessages()
2810 /* FIXME: We should keep a reference here... */
2812 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2814 if (Msg
.message
== WM_QUIT
)
2817 if (m_StartMenuBand
== NULL
||
2818 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2820 TranslateMessage(&Msg
);
2821 DispatchMessage(&Msg
);
2826 VOID
TrayMessageLoop()
2831 /* FIXME: We should keep a reference here... */
2835 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2837 if (!Ret
|| Ret
== -1)
2840 if (m_StartMenuBand
== NULL
||
2841 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2843 TranslateMessage(&Msg
);
2844 DispatchMessage(&Msg
);
2852 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2853 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2854 * The reason we implement it is because we have to use SHCreateDesktop() so
2855 * that the shell provides the desktop window and all the features that come
2856 * with it (especially positioning of desktop icons)
2859 virtual ULONG STDMETHODCALLTYPE
GetState()
2861 /* FIXME: Return ABS_ flags? */
2862 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2866 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2868 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2869 *phWndTray
= m_hWnd
;
2873 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2875 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2877 m_DesktopWnd
= hWndDesktop
;
2881 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2883 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2887 virtual HRESULT
RaiseStartButton()
2889 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2895 m_Position
= (DWORD
) -1;
2898 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2900 DECLARE_PROTECT_FINAL_CONSTRUCT()
2901 BEGIN_COM_MAP(CTrayWindow
)
2902 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2903 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2907 class CTrayWindowCtxMenu
:
2908 public CComCoClass
<CTrayWindowCtxMenu
>,
2909 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2913 CComPtr
<CTrayWindow
> TrayWnd
;
2914 CComPtr
<IContextMenu
> pcm
;
2917 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2919 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2920 this->hWndOwner
= hWndOwner
;
2924 virtual HRESULT STDMETHODCALLTYPE
2925 QueryContextMenu(HMENU hPopup
,
2931 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
2934 return HRESULT_FROM_WIN32(GetLastError());
2936 int count
= ::GetMenuItemCount(menubase
);
2938 for (int i
= 0; i
< count
; i
++)
2942 MENUITEMINFOW mii
= { 0 };
2943 mii
.cbSize
= sizeof(mii
);
2944 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2945 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2946 mii
.dwTypeData
= label
;
2947 mii
.cch
= _countof(label
);
2948 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2950 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
2952 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
2955 ::DestroyMenu(menubase
);
2957 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2964 CheckMenuItem(hPopup
,
2966 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
2968 if (TrayWnd
->m_TrayBandSite
!= NULL
)
2970 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
2978 WARN("AddContextMenus failed.\n");
2986 virtual HRESULT STDMETHODCALLTYPE
2987 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2989 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
2992 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
2994 CMINVOKECOMMANDINFO cmici
= { 0 };
2998 /* Setup and invoke the shell command */
2999 cmici
.cbSize
= sizeof(cmici
);
3000 cmici
.hwnd
= hWndOwner
;
3001 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- ID_SHELL_CMD_FIRST
);
3002 cmici
.nShow
= SW_NORMAL
;
3004 pcm
->InvokeCommand(&cmici
);
3009 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3016 virtual HRESULT STDMETHODCALLTYPE
3017 GetCommandString(UINT_PTR idCmd
,
3026 CTrayWindowCtxMenu()
3030 virtual ~CTrayWindowCtxMenu()
3034 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3035 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3039 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3041 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3042 mnu
->Initialize(TrayWnd
, hWndOwner
);
3047 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3049 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3051 return E_OUTOFMEMORY
;
3056 *ppTray
= (ITrayWindow
*) Tray
;
3062 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3064 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3065 return TrayWindow
->RaiseStartButton();
3068 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3070 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3071 TrayWindow
->TrayProcessMessages();
3074 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3076 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3077 TrayWindow
->TrayMessageLoop();