4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5 * Copyright 2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
7 * this library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * this library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include <commoncontrols.h>
26 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
28 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
30 #define TIMER_ID_AUTOHIDE 1
31 #define TIMER_ID_MOUSETRACK 2
32 #define MOUSETRACK_INTERVAL 100
33 #define AUTOHIDE_DELAY_HIDE 2000
34 #define AUTOHIDE_DELAY_SHOW 50
35 #define AUTOHIDE_INTERVAL_ANIMATING 10
37 #define AUTOHIDE_SPEED_SHOW 10
38 #define AUTOHIDE_SPEED_HIDE 1
40 #define AUTOHIDE_HIDDEN 0
41 #define AUTOHIDE_SHOWING 1
42 #define AUTOHIDE_SHOWN 2
43 #define AUTOHIDE_HIDING 3
45 #define IDHK_RUN 0x1f4
46 #define IDHK_MINIMIZE_ALL 0x1f5
47 #define IDHK_RESTORE_ALL 0x1f6
48 #define IDHK_HELP 0x1f7
49 #define IDHK_EXPLORE 0x1f8
50 #define IDHK_FIND 0x1f9
51 #define IDHK_FIND_COMPUTER 0x1fa
52 #define IDHK_NEXT_TASK 0x1fb
53 #define IDHK_PREV_TASK 0x1fc
54 #define IDHK_SYS_PROPERTIES 0x1fd
55 #define IDHK_DESKTOP 0x1fe
56 #define IDHK_PAGER 0x1ff
58 static const WCHAR szTrayWndClass
[] = L
"Shell_TrayWnd";
66 BOOL bMustBeInMonitor
;
70 FindEffectiveProc(HWND hwnd
, LPARAM lParam
)
72 EFFECTIVE_INFO
*pei
= (EFFECTIVE_INFO
*)lParam
;
74 if (!IsWindowVisible(hwnd
) || IsIconic(hwnd
))
75 return TRUE
; // continue
77 if (pei
->hTrayWnd
== hwnd
|| pei
->hwndDesktop
== hwnd
||
78 pei
->hwndProgman
== hwnd
)
80 return TRUE
; // continue
83 if (pei
->bMustBeInMonitor
)
85 // is the window in the nearest monitor?
86 HMONITOR hMon
= MonitorFromWindow(hwnd
, MONITOR_DEFAULTTONEAREST
);
90 ZeroMemory(&info
, sizeof(info
));
91 info
.cbSize
= sizeof(info
);
92 if (GetMonitorInfoW(hMon
, &info
))
94 RECT rcWindow
, rcMonitor
, rcIntersect
;
95 rcMonitor
= info
.rcMonitor
;
97 GetWindowRect(hwnd
, &rcWindow
);
99 if (!IntersectRect(&rcIntersect
, &rcMonitor
, &rcWindow
))
100 return TRUE
; // continue
105 pei
->hwndFound
= hwnd
;
106 return FALSE
; // stop if found
110 IsThereAnyEffectiveWindow(BOOL bMustBeInMonitor
)
114 ei
.hwndDesktop
= GetDesktopWindow();
115 ei
.hTrayWnd
= FindWindowW(L
"Shell_TrayWnd", NULL
);
116 ei
.hwndProgman
= FindWindowW(L
"Progman", NULL
);
117 ei
.bMustBeInMonitor
= bMustBeInMonitor
;
119 EnumWindows(FindEffectiveProc
, (LPARAM
)&ei
);
120 if (ei
.hwndFound
&& FALSE
)
122 WCHAR szClass
[64], szText
[64];
123 GetClassNameW(ei
.hwndFound
, szClass
, _countof(szClass
));
124 GetWindowTextW(ei
.hwndFound
, szText
, _countof(szText
));
125 MessageBoxW(NULL
, szText
, szClass
, 0);
127 return ei
.hwndFound
!= NULL
;
130 CSimpleArray
<HWND
> g_MinimizedAll
;
136 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
139 : public CWindowImpl
<CStartButton
>
141 HIMAGELIST m_ImageList
;
154 virtual ~CStartButton()
156 if (m_ImageList
!= NULL
)
157 ImageList_Destroy(m_ImageList
);
160 DeleteObject(m_Font
);
170 SIZE Size
= { 0, 0 };
172 if (m_ImageList
== NULL
||
173 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
175 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
) + GetSystemMetrics(SM_CYCAPTION
) * 3;
178 Size
.cy
= max(Size
.cy
, GetSystemMetrics(SM_CYCAPTION
));
180 /* Save the size of the start button */
186 /* Get the system fonts, we use the caption font, always bold, though. */
187 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
188 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
192 DeleteObject(m_Font
);
194 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
195 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
197 SetFont(m_Font
, FALSE
);
202 SubclassWindow(m_hWnd
);
203 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
205 m_ImageList
= ImageList_LoadImageW(hExplorerInstance
,
206 MAKEINTRESOURCEW(IDB_START
),
209 LR_LOADTRANSPARENT
| LR_CREATEDIBSECTION
);
211 BUTTON_IMAGELIST bil
= {m_ImageList
, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT
};
212 SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
);
216 HWND
Create(HWND hwndParent
)
218 WCHAR szStartCaption
[32];
219 if (!LoadStringW(hExplorerInstance
,
222 _countof(szStartCaption
)))
224 wcscpy(szStartCaption
, L
"Start");
227 DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| BS_PUSHBUTTON
| BS_LEFT
| BS_VCENTER
;
229 m_hWnd
= CreateWindowEx(
236 (HMENU
) IDC_STARTBTN
,
246 LRESULT
OnLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
248 if (uMsg
== WM_KEYUP
&& wParam
!= VK_SPACE
)
251 GetParent().PostMessage(TWM_OPENSTARTMENU
);
255 BEGIN_MSG_MAP(CStartButton
)
256 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
262 public CComCoClass
<CTrayWindow
>,
263 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
264 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
266 public IShellDesktopTray
,
270 CStartButton m_StartButton
;
272 CComPtr
<IMenuBand
> m_StartMenuBand
;
273 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
275 CComPtr
<IDeskBand
> m_TaskBand
;
276 CComPtr
<IContextMenu
> m_ContextMenu
;
286 CComPtr
<IUnknown
> m_TrayNotifyInstance
;
290 HMONITOR m_PreviousMonitor
;
291 DWORD m_DraggingPosition
;
292 HMONITOR m_DraggingMonitor
;
297 HWND m_TrayPropertiesOwner
;
298 HWND m_RunFileDlgOwner
;
300 UINT m_AutoHideState
;
301 SIZE m_AutoHideOffset
;
302 TRACKMOUSEEVENT m_MouseTrackingInfo
;
304 HDPA m_ShellServices
;
307 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
315 DWORD InSizeMove
: 1;
316 DWORD IsDragging
: 1;
317 DWORD NewPosSize
: 1;
332 m_PreviousMonitor(NULL
),
333 m_DraggingPosition(0),
334 m_DraggingMonitor(NULL
),
335 m_TrayPropertiesOwner(NULL
),
336 m_RunFileDlgOwner(NULL
),
337 m_AutoHideState(NULL
),
338 m_ShellServices(NULL
),
341 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
342 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
343 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
344 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
347 virtual ~CTrayWindow()
349 if (m_ShellServices
!= NULL
)
351 ShutdownShellServices(m_ShellServices
);
352 m_ShellServices
= NULL
;
357 DeleteObject(m_Font
);
363 CloseThemeData(m_Theme
);
374 /**********************************************************
375 * ##### command handling #####
378 HRESULT
ExecResourceCmd(int id
)
380 WCHAR szCommand
[256];
381 WCHAR
*pszParameters
;
383 if (!LoadStringW(hExplorerInstance
,
386 _countof(szCommand
)))
391 pszParameters
= wcschr(szCommand
, L
'>');
398 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
402 LRESULT
DoExitWindows()
404 /* Display the ReactOS Shutdown Dialog */
405 ExitWindowsDialog(m_hWnd
);
408 * If the user presses CTRL+ALT+SHIFT while exiting
409 * the shutdown dialog, exit the shell cleanly.
411 if ((GetKeyState(VK_CONTROL
) & 0x8000) &&
412 (GetKeyState(VK_SHIFT
) & 0x8000) &&
413 (GetKeyState(VK_MENU
) & 0x8000))
415 PostMessage(WM_QUIT
, 0, 0);
420 DWORD WINAPI
RunFileDlgThread()
425 m_StartButton
.GetWindowRect(&posRect
);
427 hwnd
= CreateWindowEx(0,
430 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
433 posRect
.right
- posRect
.left
,
434 posRect
.bottom
- posRect
.top
,
440 m_RunFileDlgOwner
= hwnd
;
442 // build the default directory from two environment variables
443 CStringW strDefaultDir
, strHomePath
;
444 strDefaultDir
.GetEnvironmentVariable(L
"HOMEDRIVE");
445 strHomePath
.GetEnvironmentVariable(L
"HOMEPATH");
446 strDefaultDir
+= strHomePath
;
448 RunFileDlg(hwnd
, NULL
, (LPCWSTR
)strDefaultDir
, NULL
, NULL
, RFF_CALCDIRECTORY
);
450 m_RunFileDlgOwner
= NULL
;
451 ::DestroyWindow(hwnd
);
456 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
458 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
459 return This
->RunFileDlgThread();
462 void DisplayRunFileDlg()
465 if (m_RunFileDlgOwner
)
467 hRunDlg
= ::GetLastActivePopup(m_RunFileDlgOwner
);
468 if (hRunDlg
!= NULL
&&
469 hRunDlg
!= m_RunFileDlgOwner
)
471 SetForegroundWindow(hRunDlg
);
476 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
479 DWORD WINAPI
TrayPropertiesThread()
484 m_StartButton
.GetWindowRect(&posRect
);
485 hwnd
= CreateWindowEx(0,
488 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
491 posRect
.right
- posRect
.left
,
492 posRect
.bottom
- posRect
.top
,
498 m_TrayPropertiesOwner
= hwnd
;
500 DisplayTrayProperties(hwnd
, m_hWnd
);
502 m_TrayPropertiesOwner
= NULL
;
503 ::DestroyWindow(hwnd
);
508 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
510 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
512 return This
->TrayPropertiesThread();
515 HWND STDMETHODCALLTYPE
DisplayProperties()
519 if (m_TrayPropertiesOwner
)
521 hTrayProp
= ::GetLastActivePopup(m_TrayPropertiesOwner
);
522 if (hTrayProp
!= NULL
&&
523 hTrayProp
!= m_TrayPropertiesOwner
)
525 SetForegroundWindow(hTrayProp
);
530 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
534 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
536 WCHAR szDir
[MAX_PATH
];
538 if (SHGetSpecialFolderPath(hWndOwner
,
540 CSIDL_COMMON_STARTMENU
,
543 ShellExecute(hWndOwner
,
552 VOID
OpenTaskManager(IN HWND hWndOwner
)
554 ShellExecute(hWndOwner
,
564 if (::IsThereAnyEffectiveWindow(TRUE
))
574 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
578 case ID_SHELL_CMD_PROPERTIES
:
582 case ID_SHELL_CMD_OPEN_ALL_USERS
:
583 OpenCommonStartMenuDirectory(m_hWnd
,
587 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
588 OpenCommonStartMenuDirectory(m_hWnd
,
593 if (SHRestricted(REST_CLASSICSHELL
) == 0)
595 Lock(!g_TaskbarSettings
.bLock
);
599 case ID_SHELL_CMD_OPEN_TASKMGR
:
600 OpenTaskManager(m_hWnd
);
603 case ID_SHELL_CMD_UNDO_ACTION
:
606 case ID_SHELL_CMD_SHOW_DESKTOP
:
610 case ID_SHELL_CMD_TILE_WND_H
:
611 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
614 case ID_SHELL_CMD_TILE_WND_V
:
615 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
618 case ID_SHELL_CMD_CASCADE_WND
:
619 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
622 case ID_SHELL_CMD_CUST_NOTIF
:
623 ShowCustomizeNotifyIcons(hExplorerInstance
, m_hWnd
);
626 case ID_SHELL_CMD_ADJUST_DAT
:
627 //FIXME: Use SHRunControlPanel
628 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
631 case ID_SHELL_CMD_RESTORE_ALL
:
636 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
643 LRESULT
HandleHotKey(DWORD id
)
651 ExecResourceCmd(IDS_HELP_COMMAND
);
654 //FIXME: We don't support this yet:
655 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
656 ShellExecuteW(0, NULL
, L
"explorer.exe", L
"/e ,", NULL
, 1);
659 SHFindFiles(NULL
, NULL
);
661 case IDHK_FIND_COMPUTER
:
662 SHFindComputer(NULL
, NULL
);
664 case IDHK_SYS_PROPERTIES
:
665 //FIXME: Use SHRunControlPanel
666 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
672 case IDHK_MINIMIZE_ALL
:
675 case IDHK_RESTORE_ALL
:
688 LRESULT
HandleCommand(UINT uCommand
)
692 case TRAYCMD_STARTMENU
:
695 case TRAYCMD_RUN_DIALOG
:
698 case TRAYCMD_LOGOFF_DIALOG
:
699 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
701 case TRAYCMD_CASCADE
:
702 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
705 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
708 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
710 case TRAYCMD_TOGGLE_DESKTOP
:
713 case TRAYCMD_DATE_AND_TIME
:
714 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
716 case TRAYCMD_TASKBAR_PROPERTIES
:
719 case TRAYCMD_MINIMIZE_ALL
:
722 case TRAYCMD_RESTORE_ALL
:
725 case TRAYCMD_SHOW_DESKTOP
:
728 case TRAYCMD_SHOW_TASK_MGR
:
729 OpenTaskManager(m_hWnd
);
731 case TRAYCMD_CUSTOMIZE_TASKBAR
:
733 case TRAYCMD_LOCK_TASKBAR
:
734 if (SHRestricted(REST_CLASSICSHELL
) == 0)
736 Lock(!g_TaskbarSettings
.bLock
);
739 case TRAYCMD_HELP_AND_SUPPORT
:
740 ExecResourceCmd(IDS_HELP_COMMAND
);
742 case TRAYCMD_CONTROL_PANEL
:
745 case TRAYCMD_SHUTDOWN_DIALOG
:
748 case TRAYCMD_PRINTERS_AND_FAXES
:
751 case TRAYCMD_LOCK_DESKTOP
:
754 case TRAYCMD_SWITCH_USER_DIALOG
:
757 case TRAYCMD_SEARCH_FILES
:
758 SHFindFiles(NULL
, NULL
);
760 case TRAYCMD_SEARCH_COMPUTERS
:
761 SHFindComputer(NULL
, NULL
);
774 IN POINT
*ppt OPTIONAL
,
775 IN HWND hwndExclude OPTIONAL
,
777 IN BOOL IsContextMenu
)
779 TPMPARAMS tmp
, *ptmp
= NULL
;
784 if (hwndExclude
!= NULL
)
786 /* Get the client rectangle and map it to screen coordinates */
787 if (::GetClientRect(hwndExclude
,
789 ::MapWindowPoints(hwndExclude
,
791 (LPPOINT
) &tmp
.rcExclude
,
801 GetClientRect(&tmp
.rcExclude
) &&
804 (LPPOINT
) &tmp
.rcExclude
,
812 /* NOTE: TrackPopupMenuEx will eventually align the track position
813 for us, no need to take care of it here as long as the
814 coordinates are somewhere within the exclusion rectangle */
815 pt
.x
= ptmp
->rcExclude
.left
;
816 pt
.y
= ptmp
->rcExclude
.top
;
824 tmp
.cbSize
= sizeof(tmp
);
826 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
827 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
829 fuFlags
|= TPM_RIGHTBUTTON
;
831 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
833 cmdId
= TrackPopupMenuEx(hMenu
,
843 HRESULT
TrackCtxMenu(
844 IN IContextMenu
* contextMenu
,
845 IN POINT
*ppt OPTIONAL
,
846 IN HWND hwndExclude OPTIONAL
,
848 IN PVOID Context OPTIONAL
)
855 HMENU popup
= CreatePopupMenu();
866 ::GetWindowRect(m_hWnd
, &rc
);
871 TRACE("Before Query\n");
872 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
873 if (FAILED_UNEXPECTEDLY(hr
))
875 TRACE("Query failed\n");
880 TRACE("Before Tracking\n");
881 ::SetForegroundWindow(m_hWnd
);
884 ::GetWindowRect(hwndExclude
, &rc
);
885 ZeroMemory(¶ms
, sizeof(params
));
886 params
.cbSize
= sizeof(params
);
887 params
.rcExclude
= rc
;
888 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, pt
.x
, pt
.y
, m_hWnd
, ¶ms
);
892 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, pt
.x
, pt
.y
, m_hWnd
, NULL
);
894 ::PostMessage(m_hWnd
, WM_NULL
, 0, 0);
898 TRACE("Before InvokeCommand\n");
899 CMINVOKECOMMANDINFO cmi
= { 0 };
900 cmi
.cbSize
= sizeof(cmi
);
901 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
903 hr
= contextMenu
->InvokeCommand(&cmi
);
907 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
919 /**********************************************************
920 * ##### moving and sizing handling #####
925 /* There is nothing to do if themes are enabled */
929 m_StartButton
.UpdateFont();
931 NONCLIENTMETRICS ncm
= {sizeof(ncm
)};
932 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
934 ERR("SPI_GETNONCLIENTMETRICS failed\n");
939 DeleteObject(m_Font
);
941 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
942 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
945 ERR("CreateFontIndirect failed\n");
949 SendMessage(m_Rebar
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
950 SendMessage(m_TaskSwitch
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
951 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
954 HMONITOR
GetScreenRectFromRect(
961 mi
.cbSize
= sizeof(mi
);
962 hMon
= MonitorFromRect(pRect
, dwFlags
);
964 GetMonitorInfo(hMon
, &mi
))
966 *pRect
= mi
.rcMonitor
;
972 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
973 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
981 HMONITOR
GetMonitorFromRect(
982 IN
const RECT
*pRect
)
986 /* In case the monitor sizes or saved sizes differ a bit (probably
987 not a lot, only so the tray window overlaps into another monitor
988 now), minimize the risk that we determine a wrong monitor by
989 using the center point of the tray window if we can't determine
990 it using the rectangle. */
991 hMon
= MonitorFromRect(pRect
, MONITOR_DEFAULTTONULL
);
996 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
997 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
999 /* be less error-prone, find the nearest monitor */
1000 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONEAREST
);
1006 HMONITOR
GetScreenRect(
1007 IN HMONITOR hMonitor
,
1010 HMONITOR hMon
= NULL
;
1012 if (hMonitor
!= NULL
)
1016 mi
.cbSize
= sizeof(mi
);
1017 if (!GetMonitorInfo(hMonitor
, &mi
))
1019 /* Hm, the monitor is gone? Try to find a monitor where it
1020 could be located now */
1021 hMon
= GetMonitorFromRect(pRect
);
1023 !GetMonitorInfo(hMon
, &mi
))
1026 goto GetPrimaryRect
;
1030 *pRect
= mi
.rcMonitor
;
1037 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
1038 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
1044 VOID
AdjustSizerRect(RECT
*rc
, DWORD pos
)
1046 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
1049 if (pos
> ABE_BOTTOM
)
1052 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[pos
], 0, NULL
, TS_TRUE
, &size
);
1053 if (FAILED_UNEXPECTEDLY(hr
))
1059 rc
->bottom
-= size
.cy
;
1065 rc
->right
-= size
.cx
;
1068 rc
->left
+= size
.cx
;
1073 VOID
MakeTrayRectWithSize(IN DWORD Position
,
1074 IN
const SIZE
*pTraySize
,
1080 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
1084 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
1088 pRect
->left
= pRect
->right
- pTraySize
->cx
;
1093 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
1098 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
1099 IN
const RECT
*pScreen
,
1100 IN
const SIZE
*pTraySize OPTIONAL
,
1103 if (pTraySize
== NULL
)
1104 pTraySize
= &m_TraySize
;
1110 /* Move the border outside of the screen */
1112 GetSystemMetrics(SM_CXEDGE
),
1113 GetSystemMetrics(SM_CYEDGE
));
1116 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
1119 BOOL
IsPosHorizontal()
1121 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
1124 HMONITOR
CalculateValidSize(
1133 //Horizontal = IsPosHorizontal();
1135 szWnd
.cx
= pRect
->right
- pRect
->left
;
1136 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
1139 hMon
= GetScreenRectFromRect(
1141 MONITOR_DEFAULTTONEAREST
);
1143 /* Calculate the maximum size of the tray window and limit the window
1144 size to half of the screen's size. */
1145 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
1146 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
1147 if (szWnd
.cx
> szMax
.cx
)
1148 szWnd
.cx
= szMax
.cx
;
1149 if (szWnd
.cy
> szMax
.cy
)
1150 szWnd
.cy
= szMax
.cy
;
1152 /* FIXME - calculate */
1154 GetTrayRectFromScreenRect(Position
,
1164 GetMinimumWindowSize(
1169 AdjustWindowRectEx(&rcMin
,
1170 GetWindowLong(m_hWnd
,
1173 GetWindowLong(m_hWnd
,
1181 DWORD
GetDraggingRectFromPt(
1184 OUT HMONITOR
*phMonitor
)
1186 HMONITOR hMon
, hMonNew
;
1187 DWORD PosH
, PosV
, Pos
;
1188 SIZE DeltaPt
, ScreenOffset
;
1194 /* Determine the screen rectangle */
1195 hMon
= MonitorFromPoint(pt
, MONITOR_DEFAULTTONULL
);
1200 mi
.cbSize
= sizeof(mi
);
1201 if (!GetMonitorInfo(hMon
, &mi
))
1204 goto GetPrimaryScreenRect
;
1207 /* make left top corner of the screen zero based to
1208 make calculations easier */
1209 pt
.x
-= mi
.rcMonitor
.left
;
1210 pt
.y
-= mi
.rcMonitor
.top
;
1212 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
1213 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
1214 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
1215 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
1219 GetPrimaryScreenRect
:
1220 ScreenOffset
.cx
= 0;
1221 ScreenOffset
.cy
= 0;
1222 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1223 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1226 /* Calculate the nearest screen border */
1227 if (pt
.x
< rcScreen
.right
/ 2)
1234 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
1238 if (pt
.y
< rcScreen
.bottom
/ 2)
1245 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
1249 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
1251 /* Fix the screen origin to be relative to the primary monitor again */
1252 OffsetRect(&rcScreen
,
1256 RECT rcPos
= m_TrayRects
[Pos
];
1258 hMonNew
= GetMonitorFromRect(&rcPos
);
1259 if (hMon
!= hMonNew
)
1263 /* Recalculate the rectangle, we're dragging to another monitor.
1264 We don't need to recalculate the rect on single monitor systems. */
1265 szTray
.cx
= rcPos
.right
- rcPos
.left
;
1266 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
1268 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
1273 /* The user is dragging the tray window on the same monitor. We don't need
1274 to recalculate the rectangle */
1283 DWORD
GetDraggingRectFromRect(
1285 OUT HMONITOR
*phMonitor
)
1289 /* Calculate the center of the rectangle. We call
1290 GetDraggingRectFromPt to calculate a valid
1291 dragging rectangle */
1292 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
1293 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
1295 return GetDraggingRectFromPt(
1301 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
1307 rcTray
.left
= pwp
->x
;
1308 rcTray
.top
= pwp
->y
;
1309 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1310 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1312 if (!EqualRect(&rcTray
,
1313 &m_TrayRects
[m_DraggingPosition
]))
1315 /* Recalculate the rectangle, the user dragged the tray
1316 window to another monitor or the window was somehow else
1318 m_DraggingPosition
= GetDraggingRectFromRect(
1320 &m_DraggingMonitor
);
1321 //m_TrayRects[DraggingPosition] = rcTray;
1324 //Monitor = CalculateValidSize(DraggingPosition,
1327 m_Monitor
= m_DraggingMonitor
;
1328 m_Position
= m_DraggingPosition
;
1331 m_TrayRects
[m_Position
] = rcTray
;
1334 else if (GetWindowRect(&rcTray
))
1338 if (!(pwp
->flags
& SWP_NOMOVE
))
1340 rcTray
.left
= pwp
->x
;
1341 rcTray
.top
= pwp
->y
;
1344 if (!(pwp
->flags
& SWP_NOSIZE
))
1346 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
1347 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
1350 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
1352 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
1359 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
1362 m_TrayRects
[m_Position
] = rcTray
;
1366 /* If the user isn't resizing the tray window we need to make sure the
1367 new size or position is valid. this is to prevent changes to the window
1368 without user interaction. */
1369 rcTray
= m_TrayRects
[m_Position
];
1371 if (g_TaskbarSettings
.sr
.AutoHide
)
1373 rcTray
.left
+= m_AutoHideOffset
.cx
;
1374 rcTray
.right
+= m_AutoHideOffset
.cx
;
1375 rcTray
.top
+= m_AutoHideOffset
.cy
;
1376 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1382 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
1383 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
1385 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
1386 pwp
->x
= rcTray
.left
;
1387 pwp
->y
= rcTray
.top
;
1388 pwp
->cx
= m_TraySize
.cx
;
1389 pwp
->cy
= m_TraySize
.cy
;
1393 VOID
ApplyClipping(IN BOOL Clip
)
1395 RECT rcClip
, rcWindow
;
1398 if (GetWindowRect(&rcWindow
))
1400 /* Disable clipping on systems with only one monitor */
1401 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
1408 GetScreenRect(m_Monitor
, &rcClip
);
1410 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
1419 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
1424 /* Set the clipping region or make sure the window isn't clipped
1425 by disabling it explicitly. */
1426 SetWindowRgn(hClipRgn
, TRUE
);
1430 VOID
ResizeWorkArea()
1432 #if !WIN7_DEBUG_MODE
1433 RECT rcTray
, rcWorkArea
;
1435 /* If monitor has changed then fix the previous monitors work area */
1436 if (m_PreviousMonitor
!= m_Monitor
)
1438 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
1439 SystemParametersInfoW(SPI_SETWORKAREA
,
1445 rcTray
= m_TrayRects
[m_Position
];
1447 GetScreenRect(m_Monitor
, &rcWorkArea
);
1448 m_PreviousMonitor
= m_Monitor
;
1450 /* If AutoHide is false then change the workarea to exclude
1451 the area that the taskbar covers. */
1452 if (!g_TaskbarSettings
.sr
.AutoHide
)
1457 rcWorkArea
.top
= rcTray
.bottom
;
1460 rcWorkArea
.left
= rcTray
.right
;
1463 rcWorkArea
.right
= rcTray
.left
;
1466 rcWorkArea
.bottom
= rcTray
.top
;
1472 * Resize the current monitor work area. Win32k will also send
1473 * a WM_SIZE message to automatically resize the desktop.
1475 SystemParametersInfoW(SPI_SETWORKAREA
,
1482 VOID
CheckTrayWndPosition()
1484 /* Force the rebar bands to resize */
1485 IUnknown_Exec(m_TrayBandSite
,
1487 DBID_BANDINFOCHANGED
,
1492 /* Calculate the size of the taskbar based on the rebar */
1493 FitToRebar(&m_TrayRects
[m_Position
]);
1495 /* Move the tray window */
1496 /* The handler of WM_WINDOWPOSCHANGING will override whatever size
1497 * and position we use here with m_TrayRects */
1498 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOZORDER
| SWP_NOACTIVATE
);
1500 ApplyClipping(TRUE
);
1503 VOID
RegLoadSettings()
1507 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1508 SIZE StartBtnSize
= m_StartButton
.GetSize();
1510 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1511 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1512 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1513 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1515 m_Position
= g_TaskbarSettings
.sr
.Position
;
1516 rcScreen
= g_TaskbarSettings
.sr
.Rect
;
1517 GetScreenRectFromRect(&rcScreen
, MONITOR_DEFAULTTONEAREST
);
1519 if (!g_TaskbarSettings
.sr
.Size
.cx
|| !g_TaskbarSettings
.sr
.Size
.cy
)
1521 /* Use the minimum size of the taskbar, we'll use the start
1522 button as a minimum for now. Make sure we calculate the
1523 entire window size, not just the client size. However, we
1524 use a thinner border than a standard thick border, so that
1525 the start button and bands are not stuck to the screen border. */
1528 g_TaskbarSettings
.sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1529 g_TaskbarSettings
.sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1533 g_TaskbarSettings
.sr
.Size
.cx
= StartBtnSize
.cx
- EdgeSize
.cx
;
1534 g_TaskbarSettings
.sr
.Size
.cy
= StartBtnSize
.cy
- EdgeSize
.cy
;
1535 if(!g_TaskbarSettings
.bLock
)
1536 g_TaskbarSettings
.sr
.Size
.cy
+= GetSystemMetrics(SM_CYSIZEFRAME
);
1539 /* Determine a minimum tray window rectangle. The "client" height is
1540 zero here since we cannot determine an optimal minimum width when
1541 loaded as a vertical tray window. We just need to make sure the values
1542 loaded from the registry are at least. The windows explorer behaves
1543 the same way, it allows the user to save a zero width vertical tray
1544 window, but not a zero height horizontal tray window. */
1547 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1548 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1552 WndSize
.cx
= StartBtnSize
.cx
;
1553 WndSize
.cy
= StartBtnSize
.cy
- EdgeSize
.cx
;
1556 if (WndSize
.cx
< g_TaskbarSettings
.sr
.Size
.cx
)
1557 WndSize
.cx
= g_TaskbarSettings
.sr
.Size
.cx
;
1558 if (WndSize
.cy
< g_TaskbarSettings
.sr
.Size
.cy
)
1559 WndSize
.cy
= g_TaskbarSettings
.sr
.Size
.cy
;
1561 /* Save the calculated size */
1562 m_TraySize
= WndSize
;
1564 /* Calculate all docking rectangles. We need to do this here so they're
1565 initialized and dragging the tray window to another position gives
1567 for (Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
1569 GetTrayRectFromScreenRect(Pos
,
1573 // 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);
1576 /* Determine which monitor we are on. It shouldn't matter which docked
1577 position rectangle we use */
1578 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1581 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1584 SIZE TraySize
, StartSize
;
1585 POINT ptTrayNotify
= { 0, 0 };
1589 m_StartButton
.UpdateSize();
1590 if (prcClient
!= NULL
)
1592 rcClient
= *prcClient
;
1596 if (!GetClientRect(&rcClient
))
1598 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1603 Horizontal
= IsPosHorizontal();
1605 /* We're about to resize/move the start button, the rebar control and
1606 the tray notification control */
1607 dwp
= BeginDeferWindowPos(3);
1610 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1614 /* Limit the Start button width to the client width, if necessary */
1615 StartSize
= m_StartButton
.GetSize();
1616 if (StartSize
.cx
> rcClient
.right
)
1617 StartSize
.cx
= rcClient
.right
;
1621 HWND hwndTaskToolbar
= ::GetWindow(m_TaskSwitch
, GW_CHILD
);
1622 if (hwndTaskToolbar
)
1624 DWORD size
= SendMessageW(hwndTaskToolbar
, TB_GETBUTTONSIZE
, 0, 0);
1625 StartSize
.cy
= HIWORD(size
);
1629 if (m_StartButton
.m_hWnd
!= NULL
)
1631 /* Resize and reposition the button */
1632 dwp
= m_StartButton
.DeferWindowPos(dwp
,
1638 SWP_NOZORDER
| SWP_NOACTIVATE
);
1641 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1646 /* Determine the size that the tray notification window needs */
1650 TraySize
.cy
= rcClient
.bottom
;
1654 TraySize
.cx
= rcClient
.right
;
1658 if (m_TrayNotify
!= NULL
&&
1659 SendMessage(m_TrayNotify
,
1660 TNWM_GETMINIMUMSIZE
,
1664 /* Move the tray notification window to the desired location */
1666 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1668 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1670 dwp
= ::DeferWindowPos(dwp
,
1677 SWP_NOZORDER
| SWP_NOACTIVATE
);
1680 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1685 /* Resize/Move the rebar control */
1686 if (m_Rebar
!= NULL
)
1688 POINT ptRebar
= { 0, 0 };
1691 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1695 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1696 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1697 szRebar
.cy
= rcClient
.bottom
;
1701 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1702 szRebar
.cx
= rcClient
.right
;
1703 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1706 dwp
= ::DeferWindowPos(dwp
,
1713 SWP_NOZORDER
| SWP_NOACTIVATE
);
1717 EndDeferWindowPos(dwp
);
1719 if (m_TaskSwitch
!= NULL
)
1721 /* Update the task switch window configuration */
1722 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1726 void FitToRebar(PRECT pRect
)
1728 /* Get the rect of the rebar */
1729 RECT rebarRect
, taskbarRect
, clientRect
;
1730 ::GetWindowRect(m_Rebar
, &rebarRect
);
1731 ::GetWindowRect(m_hWnd
, &taskbarRect
);
1732 ::GetClientRect(m_hWnd
, &clientRect
);
1733 OffsetRect(&rebarRect
, -taskbarRect
.left
, -taskbarRect
.top
);
1735 /* Calculate the difference of size of the taskbar and the rebar */
1737 margins
.cx
= taskbarRect
.right
- taskbarRect
.left
- clientRect
.right
+ clientRect
.left
;
1738 margins
.cy
= taskbarRect
.bottom
- taskbarRect
.top
- clientRect
.bottom
+ clientRect
.top
;
1740 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
1744 rebarRect
.bottom
= rebarRect
.top
+ pRect
->bottom
- pRect
->top
- margins
.cy
;
1745 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1746 pRect
->bottom
= pRect
->top
+ rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
;
1749 rebarRect
.top
= rebarRect
.bottom
- (pRect
->bottom
- pRect
->top
- margins
.cy
);
1750 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1751 pRect
->top
= pRect
->bottom
- (rebarRect
.bottom
- rebarRect
.top
+ margins
.cy
);
1754 rebarRect
.right
= rebarRect
.left
+ (pRect
->right
- pRect
->left
- margins
.cx
);
1755 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1756 pRect
->right
= pRect
->left
+ (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1759 rebarRect
.left
= rebarRect
.right
- (pRect
->right
- pRect
->left
- margins
.cx
);
1760 ::SendMessageW(m_Rebar
, RB_SIZETORECT
, RBSTR_CHANGERECT
, (LPARAM
)&rebarRect
);
1761 pRect
->left
= pRect
->right
- (rebarRect
.right
- rebarRect
.left
+ margins
.cx
);
1765 CalculateValidSize(m_Position
, pRect
);
1768 void PopupStartMenu()
1770 if (m_StartMenuPopup
!= NULL
)
1776 if (m_StartButton
.GetWindowRect((RECT
*) &rcExclude
))
1781 pt
.x
= rcExclude
.left
;
1782 pt
.y
= rcExclude
.top
;
1783 dwFlags
|= MPPF_TOP
;
1786 pt
.x
= rcExclude
.left
;
1787 pt
.y
= rcExclude
.bottom
;
1788 dwFlags
|= MPPF_BOTTOM
;
1791 pt
.x
= rcExclude
.right
;
1792 pt
.y
= rcExclude
.top
;
1793 dwFlags
|= MPPF_RIGHT
;
1796 pt
.x
= rcExclude
.left
;
1797 pt
.y
= rcExclude
.top
;
1798 dwFlags
|= MPPF_LEFT
;
1802 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1804 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1809 void ProcessMouseTracking()
1814 UINT state
= m_AutoHideState
;
1817 GetWindowRect(&rcCurrent
);
1818 over
= PtInRect(&rcCurrent
, pt
);
1820 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
1827 if (state
== AUTOHIDE_HIDING
)
1829 TRACE("AutoHide cancelling hide.\n");
1830 m_AutoHideState
= AUTOHIDE_SHOWING
;
1831 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1833 else if (state
== AUTOHIDE_HIDDEN
)
1835 TRACE("AutoHide starting show.\n");
1836 m_AutoHideState
= AUTOHIDE_SHOWING
;
1837 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
1842 if (state
== AUTOHIDE_SHOWING
)
1844 TRACE("AutoHide cancelling show.\n");
1845 m_AutoHideState
= AUTOHIDE_HIDING
;
1846 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1848 else if (state
== AUTOHIDE_SHOWN
)
1850 TRACE("AutoHide starting hide.\n");
1851 m_AutoHideState
= AUTOHIDE_HIDING
;
1852 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1855 KillTimer(TIMER_ID_MOUSETRACK
);
1859 void ProcessAutoHide()
1861 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
1862 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
1864 switch (m_AutoHideState
)
1866 case AUTOHIDE_HIDING
:
1870 m_AutoHideOffset
.cy
= 0;
1871 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
1872 if (m_AutoHideOffset
.cx
< -w
)
1873 m_AutoHideOffset
.cx
= -w
;
1876 m_AutoHideOffset
.cx
= 0;
1877 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
1878 if (m_AutoHideOffset
.cy
< -h
)
1879 m_AutoHideOffset
.cy
= -h
;
1882 m_AutoHideOffset
.cy
= 0;
1883 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
1884 if (m_AutoHideOffset
.cx
> w
)
1885 m_AutoHideOffset
.cx
= w
;
1888 m_AutoHideOffset
.cx
= 0;
1889 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
1890 if (m_AutoHideOffset
.cy
> h
)
1891 m_AutoHideOffset
.cy
= h
;
1895 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
1897 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1902 case AUTOHIDE_HIDDEN
:
1907 m_AutoHideOffset
.cx
= -w
;
1908 m_AutoHideOffset
.cy
= 0;
1911 m_AutoHideOffset
.cx
= 0;
1912 m_AutoHideOffset
.cy
= -h
;
1915 m_AutoHideOffset
.cx
= w
;
1916 m_AutoHideOffset
.cy
= 0;
1919 m_AutoHideOffset
.cx
= 0;
1920 m_AutoHideOffset
.cy
= h
;
1924 KillTimer(TIMER_ID_AUTOHIDE
);
1925 m_AutoHideState
= AUTOHIDE_HIDDEN
;
1928 case AUTOHIDE_SHOWING
:
1929 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
1931 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
1933 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
1935 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
1939 m_AutoHideOffset
.cx
= 0;
1942 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
1944 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
1946 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
1948 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
1952 m_AutoHideOffset
.cy
= 0;
1955 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
1957 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
1962 case AUTOHIDE_SHOWN
:
1964 KillTimer(TIMER_ID_AUTOHIDE
);
1965 m_AutoHideState
= AUTOHIDE_SHOWN
;
1969 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOZORDER
);
1976 /**********************************************************
1977 * ##### taskbar drawing #####
1980 LRESULT
EraseBackgroundWithTheme(HDC hdc
)
1983 int iSBkgndPart
[4] = {TBP_BACKGROUNDLEFT
, TBP_BACKGROUNDTOP
, TBP_BACKGROUNDRIGHT
, TBP_BACKGROUNDBOTTOM
};
1985 ASSERT(m_Position
<= ABE_BOTTOM
);
1989 GetClientRect(&rect
);
1990 DrawThemeBackground(m_Theme
, hdc
, iSBkgndPart
[m_Position
], 0, &rect
, 0);
1996 int DrawSizerWithTheme(IN HRGN hRgn
)
2000 int iSizerPart
[4] = {TBP_SIZINGBARLEFT
, TBP_SIZINGBARTOP
, TBP_SIZINGBARRIGHT
, TBP_SIZINGBARBOTTOM
};
2003 ASSERT(m_Position
<= ABE_BOTTOM
);
2005 HRESULT hr
= GetThemePartSize(m_Theme
, NULL
, iSizerPart
[m_Position
], 0, NULL
, TS_TRUE
, &size
);
2006 if (FAILED_UNEXPECTEDLY(hr
))
2009 GetWindowRect(&rect
);
2010 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
2012 hdc
= GetWindowDC();
2017 rect
.left
= rect
.right
- size
.cx
;
2020 rect
.top
= rect
.bottom
- size
.cy
;
2023 rect
.right
= rect
.left
+ size
.cx
;
2027 rect
.bottom
= rect
.top
+ size
.cy
;
2031 DrawThemeBackground(m_Theme
, hdc
, iSizerPart
[m_Position
], 0, &rect
, 0);
2044 HRESULT STDMETHODCALLTYPE
Open()
2048 /* Check if there's already a window created and try to show it.
2049 If it was somehow destroyed just create a new tray window. */
2050 if (m_hWnd
!= NULL
&& IsWindow())
2055 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
2056 if (g_TaskbarSettings
.sr
.AlwaysOnTop
)
2057 dwExStyle
|= WS_EX_TOPMOST
;
2059 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
;
2062 dwStyle
|= WS_THICKFRAME
| WS_BORDER
;
2065 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
2066 if (m_Position
!= (DWORD
) -1)
2067 rcWnd
= m_TrayRects
[m_Position
];
2069 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
2072 /* Align all controls on the tray window */
2073 AlignControls(NULL
);
2075 /* Move the tray window to the right position and resize it if necessary */
2076 CheckTrayWndPosition();
2081 HRESULT STDMETHODCALLTYPE
Close()
2094 HWND STDMETHODCALLTYPE
GetHWND()
2099 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
2101 return (m_hWnd
== hWnd
||
2102 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
2105 BOOL STDMETHODCALLTYPE
IsHorizontal()
2107 return IsPosHorizontal();
2110 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
2112 BOOL bPrevLock
= g_TaskbarSettings
.bLock
;
2114 if (g_TaskbarSettings
.bLock
!= bLock
)
2116 g_TaskbarSettings
.bLock
= bLock
;
2118 if (m_TrayBandSite
!= NULL
)
2120 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
2123 g_TaskbarSettings
.bLock
= bPrevLock
;
2130 /* Update cached tray sizes */
2131 for(DWORD Pos
= ABE_LEFT
; Pos
<= ABE_BOTTOM
; Pos
++)
2133 RECT rcGripper
= {0};
2134 AdjustSizerRect(&rcGripper
, Pos
);
2136 if(g_TaskbarSettings
.bLock
)
2138 m_TrayRects
[Pos
].top
+= rcGripper
.top
;
2139 m_TrayRects
[Pos
].left
+= rcGripper
.left
;
2140 m_TrayRects
[Pos
].bottom
+= rcGripper
.bottom
;
2141 m_TrayRects
[Pos
].right
+= rcGripper
.right
;
2145 m_TrayRects
[Pos
].top
-= rcGripper
.top
;
2146 m_TrayRects
[Pos
].left
-= rcGripper
.left
;
2147 m_TrayRects
[Pos
].bottom
-= rcGripper
.bottom
;
2148 m_TrayRects
[Pos
].right
-= rcGripper
.right
;
2152 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2154 ApplyClipping(TRUE
);
2164 HRESULT STDMETHODCALLTYPE
QueryContextMenu(HMENU hPopup
,
2172 HRESULT hr
= TrayWindowCtxMenuCreator(this, m_hWnd
, &m_ContextMenu
);
2173 if (FAILED_UNEXPECTEDLY(hr
))
2177 return m_ContextMenu
->QueryContextMenu(hPopup
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
2180 HRESULT STDMETHODCALLTYPE
InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
2183 return E_INVALIDARG
;
2185 return m_ContextMenu
->InvokeCommand(lpici
);
2188 HRESULT STDMETHODCALLTYPE
GetCommandString(UINT_PTR idCmd
,
2195 return E_INVALIDARG
;
2197 return m_ContextMenu
->GetCommandString(idCmd
, uType
, pwReserved
, pszName
, cchMax
);
2201 /**********************************************************
2202 * ##### message handling #####
2205 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2209 ((ITrayWindow
*)this)->AddRef();
2211 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
2213 /* Create the Start button */
2214 m_StartButton
.Create(m_hWnd
);
2216 /* Load the saved tray window settings */
2219 /* Create and initialize the start menu */
2220 HBITMAP hbmBanner
= LoadBitmapW(hExplorerInstance
, MAKEINTRESOURCEW(IDB_STARTMENU
));
2221 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
2223 /* Create the task band */
2224 hRet
= CTaskBand_CreateInstance(this, m_StartButton
.m_hWnd
, IID_PPV_ARG(IDeskBand
, &m_TaskBand
));
2225 if (FAILED_UNEXPECTEDLY(hRet
))
2228 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2229 hRet
= CTrayBandSite_CreateInstance(this, m_TaskBand
, &m_TrayBandSite
);
2230 if (FAILED_UNEXPECTEDLY(hRet
))
2233 /* Create the tray notification window */
2234 hRet
= CTrayNotifyWnd_CreateInstance(m_hWnd
, IID_PPV_ARG(IUnknown
, &m_TrayNotifyInstance
));
2235 if (FAILED_UNEXPECTEDLY(hRet
))
2238 /* Get the hwnd of the rebar */
2239 hRet
= IUnknown_GetWindow(m_TrayBandSite
, &m_Rebar
);
2240 if (FAILED_UNEXPECTEDLY(hRet
))
2243 /* Get the hwnd of the tasks toolbar */
2244 hRet
= IUnknown_GetWindow(m_TaskBand
, &m_TaskSwitch
);
2245 if (FAILED_UNEXPECTEDLY(hRet
))
2248 /* Get the hwnd of the tray notification window */
2249 hRet
= IUnknown_GetWindow(m_TrayNotifyInstance
, &m_TrayNotify
);
2250 if (FAILED_UNEXPECTEDLY(hRet
))
2253 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
2257 InitShellServices(&m_ShellServices
);
2259 if (g_TaskbarSettings
.sr
.AutoHide
)
2261 m_AutoHideState
= AUTOHIDE_HIDING
;
2262 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2265 /* Set the initial lock state in the band site */
2266 m_TrayBandSite
->Lock(g_TaskbarSettings
.bLock
);
2268 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
2269 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
2270 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
2271 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
2272 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
2273 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
2274 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
2275 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
2276 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
2277 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
2278 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
2279 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
2284 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2287 CloseThemeData(m_Theme
);
2289 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
2293 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
2297 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
2299 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
2304 LRESULT
OnSettingChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2306 if (wParam
== SPI_SETNONCLIENTMETRICS
)
2308 SendMessage(m_TrayNotify
, uMsg
, wParam
, lParam
);
2309 SendMessage(m_TaskSwitch
, uMsg
, wParam
, lParam
);
2311 AlignControls(NULL
);
2312 CheckTrayWndPosition();
2318 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2320 HDC hdc
= (HDC
) wParam
;
2328 return EraseBackgroundWithTheme(hdc
);
2331 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2333 /* Load the saved tray window settings */
2336 /* Move the tray window to the right position and resize it if necessary */
2337 CheckTrayWndPosition();
2342 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2345 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2349 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2356 else if (g_TaskbarSettings
.bLock
)
2361 return DrawSizerWithTheme((HRGN
) wParam
);
2364 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2366 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2367 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2370 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2375 if (g_TaskbarSettings
.bLock
)
2377 /* The user may not be able to resize the tray window.
2378 Pretend like the window is not sizeable when the user
2379 clicks on the border. */
2383 SetLastError(ERROR_SUCCESS
);
2384 if (GetClientRect(&rcClient
) &&
2385 (MapWindowPoints(NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2387 pt
.x
= (SHORT
) LOWORD(lParam
);
2388 pt
.y
= (SHORT
) HIWORD(lParam
);
2390 if (PtInRect(&rcClient
, pt
))
2392 /* The user is trying to drag the tray window */
2396 /* Depending on the position of the tray window, allow only
2397 changing the border next to the monitor working area */
2401 if (pt
.y
> rcClient
.bottom
)
2405 if (pt
.x
> rcClient
.right
)
2409 if (pt
.x
< rcClient
.left
)
2414 if (pt
.y
< rcClient
.top
)
2422 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2425 PRECT pRect
= (PRECT
) lParam
;
2427 /* We need to ensure that an application can not accidently
2428 move the tray window (using SetWindowPos). However, we still
2429 need to be able to move the window in case the user wants to
2430 drag the tray window to another position or in case the user
2431 wants to resize the tray window. */
2432 if (!g_TaskbarSettings
.bLock
&& GetCursorPos(&ptCursor
))
2435 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2439 *pRect
= m_TrayRects
[m_Position
];
2444 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2446 PRECT pRect
= (PRECT
) lParam
;
2448 if (!g_TaskbarSettings
.bLock
)
2454 *pRect
= m_TrayRects
[m_Position
];
2459 LRESULT
OnWindowPosChanging(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2461 ChangingWinPos((LPWINDOWPOS
) lParam
);
2465 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2468 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2471 /* Clip the tray window on multi monitor systems so the edges can't
2472 overlap into another monitor */
2473 ApplyClipping(TRUE
);
2475 if (!GetClientRect(&rcClient
))
2482 rcClient
.left
= rcClient
.top
= 0;
2483 rcClient
.right
= LOWORD(lParam
);
2484 rcClient
.bottom
= HIWORD(lParam
);
2487 AlignControls(&rcClient
);
2491 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2495 if (!g_TaskbarSettings
.bLock
)
2497 /* Remove the clipping on multi monitor systems while dragging around */
2498 ApplyClipping(FALSE
);
2503 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2506 if (!g_TaskbarSettings
.bLock
)
2508 FitToRebar(&m_TrayRects
[m_Position
]);
2510 /* Apply clipping */
2511 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2516 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2522 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2523 The tray window needs to handle this specially, since it normally doesn't have
2526 static const UINT uidDisableItem
[] = {
2536 /* temporarily enable the system menu */
2537 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2539 hSysMenu
= GetSystemMenu(FALSE
);
2540 if (hSysMenu
!= NULL
)
2542 /* Disable all items that are not relevant */
2543 for (i
= 0; i
< _countof(uidDisableItem
); i
++)
2545 EnableMenuItem(hSysMenu
,
2547 MF_BYCOMMAND
| MF_GRAYED
);
2550 EnableMenuItem(hSysMenu
,
2553 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2555 /* Display the system menu */
2559 m_StartButton
.m_hWnd
,
2560 m_Position
!= ABE_TOP
,
2564 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2568 /* revert the system menu window style */
2569 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2579 LRESULT
OnNcLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2581 /* This handler implements the trick that makes the start button to
2582 get pressed when the user clicked left or below the button */
2584 POINT pt
= {GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)};
2585 WINDOWINFO wi
= {sizeof(WINDOWINFO
)};
2590 m_StartButton
.GetWindowRect(&rcStartBtn
);
2591 GetWindowInfo(m_hWnd
, &wi
);
2598 if (pt
.x
> rcStartBtn
.right
|| pt
.y
> rcStartBtn
.bottom
)
2604 if (pt
.x
< rcStartBtn
.left
|| pt
.y
> rcStartBtn
.bottom
)
2607 if (rcStartBtn
.right
+ (int)wi
.cxWindowBorders
* 2 + 1 < wi
.rcWindow
.right
&&
2608 pt
.x
> rcStartBtn
.right
)
2616 if (pt
.x
> rcStartBtn
.right
|| pt
.y
< rcStartBtn
.top
)
2621 if (rcStartBtn
.bottom
+ (int)wi
.cyWindowBorders
* 2 + 1 < wi
.rcWindow
.bottom
&&
2622 pt
.y
> rcStartBtn
.bottom
)
2636 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2638 /* We want the user to be able to get a context menu even on the nonclient
2639 area (including the sizing border)! */
2640 uMsg
= WM_CONTEXTMENU
;
2641 wParam
= (WPARAM
) m_hWnd
;
2643 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2646 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2648 LRESULT Ret
= FALSE
;
2649 POINT pt
, *ppt
= NULL
;
2650 HWND hWndExclude
= NULL
;
2652 /* Check if the administrator has forbidden access to context menus */
2653 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2656 pt
.x
= (SHORT
) LOWORD(lParam
);
2657 pt
.y
= (SHORT
) HIWORD(lParam
);
2659 if (pt
.x
!= -1 || pt
.y
!= -1)
2662 hWndExclude
= m_StartButton
.m_hWnd
;
2664 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2666 /* Make sure we can't track the context menu if the start
2667 menu is currently being shown */
2668 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2670 CComPtr
<IContextMenu
> ctxMenu
;
2671 CStartMenuBtnCtxMenu_CreateInstance(this, m_hWnd
, &ctxMenu
);
2672 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2677 /* See if the context menu should be handled by the task band site */
2678 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2681 POINT ptClient
= *ppt
;
2683 /* Convert the coordinates to client-coordinates */
2684 ::MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2686 hWndAtPt
= ChildWindowFromPoint(ptClient
);
2687 if (hWndAtPt
!= NULL
&&
2688 (hWndAtPt
== m_Rebar
|| ::IsChild(m_Rebar
, hWndAtPt
)))
2690 /* Check if the user clicked on the task switch window */
2692 ::MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2694 hWndAtPt
= ::ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2695 if (hWndAtPt
== m_TaskSwitch
)
2696 goto HandleTrayContextMenu
;
2698 /* Forward the message to the task band site */
2699 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2702 goto HandleTrayContextMenu
;
2706 HandleTrayContextMenu
:
2707 /* Tray the default tray window context menu */
2708 TrackCtxMenu(this, ppt
, NULL
, FALSE
, this);
2714 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2716 LRESULT Ret
= FALSE
;
2717 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2718 the rebar control! But we shouldn't forward messages that the band
2719 site doesn't handle, such as other controls (start button, tray window */
2721 HRESULT hr
= E_FAIL
;
2725 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2730 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2732 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2734 if (nmh
->hwndFrom
== m_TrayNotify
)
2739 /* Cause all controls to be aligned */
2740 PostMessage(WM_SIZE
, SIZE_RESTORED
, 0);
2748 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2750 /* Let the clock handle the double click */
2751 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
2753 /* We "handle" this message so users can't cause a weird maximize/restore
2754 window animation when double-clicking the tray window! */
2758 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2764 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2767 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2768 if (FAILED_UNEXPECTEDLY(hr
))
2771 if (::IsWindowVisible(hwndStartMenu
))
2773 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2783 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2786 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2787 * to show the shutdown dialog. Also a WM_CLOSE message sent
2788 * by apps should show the dialog.
2790 return DoExitWindows();
2793 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2795 if (wParam
== SC_CLOSE
)
2797 return DoExitWindows();
2804 LRESULT
OnGetTaskSwitch(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2807 return (LRESULT
)m_TaskSwitch
;
2810 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2812 return HandleHotKey(wParam
);
2815 struct MINIMIZE_INFO
2821 CSimpleArray
<HWND
> *pMinimizedAll
;
2825 static BOOL
IsDialog(HWND hwnd
)
2828 GetClassNameW(hwnd
, szClass
, _countof(szClass
));
2829 return wcscmp(szClass
, L
"#32770") == 0;
2832 static BOOL CALLBACK
MinimizeWindowsProc(HWND hwnd
, LPARAM lParam
)
2834 MINIMIZE_INFO
*info
= (MINIMIZE_INFO
*)lParam
;
2835 if (hwnd
== info
->hwndDesktop
|| hwnd
== info
->hTrayWnd
||
2836 hwnd
== info
->hwndProgman
)
2840 if (!info
->bShowDesktop
)
2842 if (!::IsWindowEnabled(hwnd
) || IsDialog(hwnd
))
2844 HWND hwndOwner
= ::GetWindow(hwnd
, GW_OWNER
);
2845 if (hwndOwner
&& !::IsWindowEnabled(hwndOwner
))
2848 if (::IsWindowVisible(hwnd
) && !::IsIconic(hwnd
))
2850 ::ShowWindowAsync(hwnd
, SW_MINIMIZE
);
2852 info
->pMinimizedAll
->Add(hwnd
);
2857 VOID
MinimizeAll(BOOL bShowDesktop
= FALSE
)
2860 info
.hwndDesktop
= GetDesktopWindow();;
2861 info
.hTrayWnd
= FindWindowW(L
"Shell_TrayWnd", NULL
);
2862 info
.hwndProgman
= FindWindowW(L
"Progman", NULL
);
2864 info
.pMinimizedAll
= &g_MinimizedAll
;
2865 info
.bShowDesktop
= bShowDesktop
;
2866 EnumWindows(MinimizeWindowsProc
, (LPARAM
)&info
);
2868 // invalid handles should be cleared to avoid mismatch of handles
2869 for (INT i
= 0; i
< g_MinimizedAll
.GetSize(); ++i
)
2871 if (!::IsWindow(g_MinimizedAll
[i
]))
2872 g_MinimizedAll
[i
] = NULL
;
2875 ::SetForegroundWindow(m_DesktopWnd
);
2876 ::SetFocus(m_DesktopWnd
);
2886 for (INT i
= g_MinimizedAll
.GetSize() - 1; i
>= 0; --i
)
2888 HWND hwnd
= g_MinimizedAll
[i
];
2889 if (::IsWindowVisible(hwnd
) && ::IsIconic(hwnd
))
2891 ::ShowWindow(hwnd
, SW_RESTORE
);
2894 g_MinimizedAll
.RemoveAll();
2897 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2899 LRESULT Ret
= FALSE
;
2901 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2906 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2908 return HandleCommand(LOWORD(wParam
));
2913 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2915 if (g_TaskbarSettings
.sr
.AutoHide
)
2917 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2923 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2925 if (wParam
== TIMER_ID_MOUSETRACK
)
2927 ProcessMouseTracking();
2929 else if (wParam
== TIMER_ID_AUTOHIDE
)
2938 LRESULT
OnNcCalcSize(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2941 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
2942 if(!m_Theme
|| g_TaskbarSettings
.bLock
)
2953 NCCALCSIZE_PARAMS
*prms
= (NCCALCSIZE_PARAMS
*)lParam
;
2954 if(prms
->lppos
->flags
& SWP_NOSENDCHANGING
)
2959 rc
= &prms
->rgrc
[0];
2962 AdjustSizerRect(rc
, m_Position
);
2967 LRESULT
OnInitMenuPopup(INT code
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2969 HMENU hMenu
= (HMENU
)wParam
;
2970 if (::IsThereAnyEffectiveWindow(FALSE
))
2972 ::EnableMenuItem(hMenu
, ID_SHELL_CMD_CASCADE_WND
, MF_BYCOMMAND
| MF_ENABLED
);
2973 ::EnableMenuItem(hMenu
, ID_SHELL_CMD_TILE_WND_H
, MF_BYCOMMAND
| MF_ENABLED
);
2974 ::EnableMenuItem(hMenu
, ID_SHELL_CMD_TILE_WND_V
, MF_BYCOMMAND
| MF_ENABLED
);
2978 ::EnableMenuItem(hMenu
, ID_SHELL_CMD_CASCADE_WND
, MF_BYCOMMAND
| MF_GRAYED
);
2979 ::EnableMenuItem(hMenu
, ID_SHELL_CMD_TILE_WND_H
, MF_BYCOMMAND
| MF_GRAYED
);
2980 ::EnableMenuItem(hMenu
, ID_SHELL_CMD_TILE_WND_V
, MF_BYCOMMAND
| MF_GRAYED
);
2985 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2988 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2994 ::GetWindowRect(m_hWnd
, &rc
);
2998 rc
.bottom
- rc
.top
};
3000 as
->rcTarget
.right
- as
->rcTarget
.left
,
3001 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
3003 as
->rcActual
.right
- as
->rcActual
.left
,
3004 as
->rcActual
.bottom
- as
->rcActual
.top
};
3007 szWindow
.cx
- szTarget
.cx
,
3008 szWindow
.cy
- szTarget
.cx
,
3014 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
3017 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
3020 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
3021 rc
.left
= rc
.right
- szWindow
.cy
;
3024 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
3025 rc
.top
= rc
.bottom
- szWindow
.cy
;
3029 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
3036 LRESULT
OnTaskbarSettingsChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
3038 TaskbarSettings
* newSettings
= (TaskbarSettings
*)lParam
;
3040 /* Propagate the new settings to the children */
3041 ::SendMessageW(m_TaskSwitch
, uMsg
, wParam
, lParam
);
3042 ::SendMessageW(m_TrayNotify
, uMsg
, wParam
, lParam
);
3044 /* Toggle autohide */
3045 if (newSettings
->sr
.AutoHide
!= g_TaskbarSettings
.sr
.AutoHide
)
3047 g_TaskbarSettings
.sr
.AutoHide
= newSettings
->sr
.AutoHide
;
3048 memset(&m_AutoHideOffset
, 0, sizeof(m_AutoHideOffset
));
3049 m_AutoHideState
= AUTOHIDE_SHOWN
;
3050 if (!newSettings
->sr
.AutoHide
)
3051 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOZORDER
);
3053 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
3056 /* Toggle lock state */
3057 Lock(newSettings
->bLock
);
3059 /* Toggle OnTop state */
3060 if (newSettings
->sr
.AlwaysOnTop
!= g_TaskbarSettings
.sr
.AlwaysOnTop
)
3062 g_TaskbarSettings
.sr
.AlwaysOnTop
= newSettings
->sr
.AlwaysOnTop
;
3063 HWND hWndInsertAfter
= newSettings
->sr
.AlwaysOnTop
? HWND_TOPMOST
: HWND_BOTTOM
;
3064 SetWindowPos(hWndInsertAfter
, 0, 0, 0, 0, SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_SHOWWINDOW
);
3067 g_TaskbarSettings
.Save();
3071 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
3073 BEGIN_MSG_MAP(CTrayWindow
)
3074 if (m_StartMenuBand
!= NULL
)
3081 Msg
.wParam
= wParam
;
3082 Msg
.lParam
= lParam
;
3084 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
3089 wParam
= Msg
.wParam
;
3090 lParam
= Msg
.lParam
;
3092 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
3093 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChanged
)
3094 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
3095 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
3096 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
3097 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
3098 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
3099 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
3100 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
3101 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
3102 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
3103 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
3104 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
3105 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
3106 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
3107 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
3108 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
3109 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
3110 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
3111 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChanging
)
3112 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
3113 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
3114 MESSAGE_HANDLER(WM_NCLBUTTONDOWN
, OnNcLButtonDown
)
3115 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
3116 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
3117 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
3118 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
3119 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
3120 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
3121 MESSAGE_HANDLER(WM_CLOSE
, OnDoExitWindows
)
3122 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
3123 MESSAGE_HANDLER(WM_NCCALCSIZE
, OnNcCalcSize
)
3124 MESSAGE_HANDLER(WM_INITMENUPOPUP
, OnInitMenuPopup
)
3125 MESSAGE_HANDLER(TWM_SETTINGSCHANGED
, OnTaskbarSettingsChanged
)
3126 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
3127 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
3128 MESSAGE_HANDLER(TWM_GETTASKSWITCH
, OnGetTaskSwitch
)
3132 /*****************************************************************************/
3134 VOID
TrayProcessMessages()
3138 /* FIXME: We should keep a reference here... */
3140 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
3142 if (Msg
.message
== WM_QUIT
)
3145 if (m_StartMenuBand
== NULL
||
3146 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
3148 TranslateMessage(&Msg
);
3149 DispatchMessage(&Msg
);
3154 VOID
TrayMessageLoop()
3159 /* FIXME: We should keep a reference here... */
3163 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
3165 if (!Ret
|| Ret
== -1)
3168 if (m_StartMenuBand
== NULL
||
3169 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
3171 TranslateMessage(&Msg
);
3172 DispatchMessage(&Msg
);
3180 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
3181 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
3182 * The reason we implement it is because we have to use SHCreateDesktop() so
3183 * that the shell provides the desktop window and all the features that come
3184 * with it (especially positioning of desktop icons)
3187 virtual ULONG STDMETHODCALLTYPE
GetState()
3189 /* FIXME: Return ABS_ flags? */
3190 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3194 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
3196 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
3197 *phWndTray
= m_hWnd
;
3201 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
3203 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
3205 m_DesktopWnd
= hWndDesktop
;
3209 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
3211 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
3215 virtual HRESULT
RaiseStartButton()
3217 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
3221 HRESULT WINAPI
GetWindow(HWND
* phwnd
)
3224 return E_INVALIDARG
;
3229 HRESULT WINAPI
ContextSensitiveHelp(BOOL fEnterMode
)
3236 m_Position
= (DWORD
) -1;
3239 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
3241 DECLARE_PROTECT_FINAL_CONSTRUCT()
3242 BEGIN_COM_MAP(CTrayWindow
)
3243 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3244 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
3245 COM_INTERFACE_ENTRY_IID(IID_IOleWindow
, IOleWindow
)
3246 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3250 class CTrayWindowCtxMenu
:
3251 public CComCoClass
<CTrayWindowCtxMenu
>,
3252 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
3256 CComPtr
<CTrayWindow
> TrayWnd
;
3257 CComPtr
<IContextMenu
> pcm
;
3258 UINT m_idCmdCmFirst
;
3261 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3263 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3264 this->hWndOwner
= hWndOwner
;
3265 this->m_idCmdCmFirst
= 0;
3269 virtual HRESULT STDMETHODCALLTYPE
3270 QueryContextMenu(HMENU hPopup
,
3278 hMenuBase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCEW(IDM_TRAYWND
));
3280 if (g_MinimizedAll
.GetSize() != 0 && !::IsThereAnyEffectiveWindow(TRUE
))
3282 CStringW
strRestoreAll(MAKEINTRESOURCEW(IDS_RESTORE_ALL
));
3283 MENUITEMINFOW mii
= { sizeof(mii
) };
3284 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
3285 mii
.wID
= ID_SHELL_CMD_RESTORE_ALL
;
3286 mii
.fType
= MFT_STRING
;
3287 mii
.dwTypeData
= const_cast<LPWSTR
>(&strRestoreAll
[0]);
3288 SetMenuItemInfoW(hMenuBase
, ID_SHELL_CMD_SHOW_DESKTOP
, FALSE
, &mii
);
3292 return HRESULT_FROM_WIN32(GetLastError());
3294 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3301 CheckMenuItem(hMenuBase
,
3303 MF_BYCOMMAND
| (g_TaskbarSettings
.bLock
? MF_CHECKED
: MF_UNCHECKED
));
3306 idCmdNext
= Shell_MergeMenus(hPopup
, hMenuBase
, indexMenu
, idCmdFirst
, idCmdLast
, MM_SUBMENUSHAVEIDS
| MM_ADDSEPARATOR
);
3307 m_idCmdCmFirst
= idCmdNext
- idCmdFirst
;
3309 ::DestroyMenu(hMenuBase
);
3311 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3313 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3321 WARN("AddContextMenus failed.\n");
3329 virtual HRESULT STDMETHODCALLTYPE
3330 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3332 UINT uiCmdId
= PtrToUlong(lpici
->lpVerb
);
3335 if (uiCmdId
>= m_idCmdCmFirst
)
3337 CMINVOKECOMMANDINFO cmici
= { 0 };
3341 /* Setup and invoke the shell command */
3342 cmici
.cbSize
= sizeof(cmici
);
3343 cmici
.hwnd
= hWndOwner
;
3344 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCEW(uiCmdId
- m_idCmdCmFirst
);
3345 cmici
.nShow
= SW_NORMAL
;
3347 pcm
->InvokeCommand(&cmici
);
3352 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3359 virtual HRESULT STDMETHODCALLTYPE
3360 GetCommandString(UINT_PTR idCmd
,
3369 CTrayWindowCtxMenu()
3373 virtual ~CTrayWindowCtxMenu()
3377 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3378 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3382 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3384 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3385 mnu
->Initialize(TrayWnd
, hWndOwner
);
3390 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3392 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3394 return E_OUTOFMEMORY
;
3399 *ppTray
= (ITrayWindow
*) Tray
;
3405 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3407 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3408 return TrayWindow
->RaiseStartButton();
3411 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3413 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3414 TrayWindow
->TrayProcessMessages();
3417 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3419 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3420 TrayWindow
->TrayMessageLoop();