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 extern HRESULT
InitShellServices(HDPA
* phdpa
);
25 extern HRESULT
ShutdownShellServices(HDPA hdpa
);
27 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
29 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
31 #define TIMER_ID_AUTOHIDE 1
32 #define TIMER_ID_MOUSETRACK 2
33 #define MOUSETRACK_INTERVAL 100
34 #define AUTOHIDE_DELAY_HIDE 2000
35 #define AUTOHIDE_DELAY_SHOW 50
36 #define AUTOHIDE_INTERVAL_ANIMATING 10
38 #define AUTOHIDE_SPEED_SHOW 10
39 #define AUTOHIDE_SPEED_HIDE 1
41 #define AUTOHIDE_HIDDEN 0
42 #define AUTOHIDE_SHOWING 1
43 #define AUTOHIDE_SHOWN 2
44 #define AUTOHIDE_HIDING 3
46 static LONG TrayWndCount
= 0;
48 static const WCHAR szTrayWndClass
[] = TEXT("Shell_TrayWnd");
54 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
57 public CComCoClass
<CTrayWindow
>,
58 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
59 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
61 public IShellDesktopTray
63 CContainedWindow StartButton
;
68 IImageList
* himlStartBtn
;
79 HMONITOR PreviousMonitor
;
80 DWORD DraggingPosition
;
81 HMONITOR DraggingMonitor
;
90 CComPtr
<IMenuBand
> StartMenuBand
;
91 CComPtr
<IMenuPopup
> StartMenuPopup
;
94 HWND hwndTrayPropertiesOwner
;
95 HWND hwndRunFileDlgOwner
;
99 TRACKMOUSEEVENT MouseTrackingInfo
;
101 HDPA hdpaShellServices
;
104 CComPtr
<ITrayBandSite
> TrayBandSite
;
111 DWORD AlwaysOnTop
: 1;
112 DWORD SmSmallIcons
: 1;
117 DWORD InSizeMove
: 1;
118 DWORD IsDragging
: 1;
119 DWORD NewPosSize
: 1;
125 StartButton(this, 1),
132 hwndTaskSwitch(NULL
),
133 hwndTrayNotify(NULL
),
136 PreviousMonitor(NULL
),
138 DraggingMonitor(NULL
),
141 hwndTrayPropertiesOwner(NULL
),
142 hwndRunFileDlgOwner(NULL
),
144 hdpaShellServices(NULL
),
147 ZeroMemory(&StartBtnSize
, sizeof(StartBtnSize
));
148 ZeroMemory(&rcTrayWnd
, sizeof(rcTrayWnd
));
149 ZeroMemory(&rcNewPosSize
, sizeof(rcNewPosSize
));
150 ZeroMemory(&TraySize
, sizeof(TraySize
));
151 ZeroMemory(&ncm
, sizeof(ncm
));
152 ZeroMemory(&AutoHideOffset
, sizeof(AutoHideOffset
));
153 ZeroMemory(&MouseTrackingInfo
, sizeof(MouseTrackingInfo
));
156 virtual ~CTrayWindow()
158 (void) InterlockedExchangePointer((PVOID
*) &m_hWnd
, NULL
);
161 if (hdpaShellServices
!= NULL
)
163 ShutdownShellServices(hdpaShellServices
);
164 hdpaShellServices
= NULL
;
167 if (himlStartBtn
!= NULL
)
169 himlStartBtn
->Release();
173 if (hCaptionFont
!= NULL
)
175 DeleteObject(hCaptionFont
);
179 if (hStartBtnFont
!= NULL
)
181 DeleteObject(hStartBtnFont
);
182 hStartBtnFont
= NULL
;
191 if (hbmStartMenu
!= NULL
)
193 DeleteObject(hbmStartMenu
);
199 CloseThemeData(TaskbarTheme
);
203 if (InterlockedDecrement(&TrayWndCount
) == 0)
207 BOOL
LaunchCPanel(HWND hwnd
, LPCTSTR applet
)
209 WCHAR szParams
[MAX_PATH
];
211 StringCbCopy(szParams
, sizeof(szParams
),
212 TEXT("shell32.dll,Control_RunDLL "));
213 if (FAILED_UNEXPECTEDLY(StringCbCat(szParams
, sizeof(szParams
),
217 return (ShellExecute(hwnd
, TEXT("open"), TEXT("rundll32.exe"), szParams
, NULL
, SW_SHOWDEFAULT
) > (HINSTANCE
) 32);
224 BOOL
UpdateNonClientMetrics()
226 ncm
.cbSize
= sizeof(ncm
);
227 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
232 hFont
= CreateFontIndirect(&ncm
.lfMessageFont
);
239 VOID
SetWindowsFont()
241 if (hwndTrayNotify
!= NULL
)
243 SendMessage(hwndTrayNotify
, WM_SETFONT
, (WPARAM
) hFont
, TRUE
);
247 HMONITOR
GetScreenRectFromRect(
254 mi
.cbSize
= sizeof(mi
);
255 hMon
= MonitorFromRect(pRect
,
261 *pRect
= mi
.rcMonitor
;
267 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
268 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
276 HMONITOR
GetMonitorFromRect(
277 IN
const RECT
*pRect
)
281 /* In case the monitor sizes or saved sizes differ a bit (probably
282 not a lot, only so the tray window overlaps into another monitor
283 now), minimize the risk that we determine a wrong monitor by
284 using the center point of the tray window if we can't determine
285 it using the rectangle. */
286 hMon
= MonitorFromRect(pRect
,
287 MONITOR_DEFAULTTONULL
);
292 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
293 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
295 /* be less error-prone, find the nearest monitor */
296 hMon
= MonitorFromPoint(pt
,
297 MONITOR_DEFAULTTONEAREST
);
303 HMONITOR
GetScreenRect(
304 IN HMONITOR hMonitor
,
307 HMONITOR hMon
= NULL
;
309 if (hMonitor
!= NULL
)
313 mi
.cbSize
= sizeof(mi
);
314 if (!GetMonitorInfo(hMonitor
,
317 /* Hm, the monitor is gone? Try to find a monitor where it
318 could be located now */
319 hMon
= GetMonitorFromRect(
322 !GetMonitorInfo(hMon
,
330 *pRect
= mi
.rcMonitor
;
337 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
338 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
344 VOID
MakeTrayRectWithSize(IN DWORD Position
,
345 IN
const SIZE
*pTraySize
,
351 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
355 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
359 pRect
->left
= pRect
->right
- pTraySize
->cx
;
364 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
369 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
370 IN
const RECT
*pScreen
,
371 IN
const SIZE
*pTraySize OPTIONAL
,
374 if (pTraySize
== NULL
)
375 pTraySize
= &TraySize
;
379 /* Move the border outside of the screen */
381 GetSystemMetrics(SM_CXEDGE
),
382 GetSystemMetrics(SM_CYEDGE
));
384 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
390 return Position
== ABE_TOP
|| Position
== ABE_BOTTOM
;
403 //Horizontal = IsPosHorizontal();
405 szWnd
.cx
= pRect
->right
- pRect
->left
;
406 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
409 hMon
= GetScreenRectFromRect(
411 MONITOR_DEFAULTTONEAREST
);
413 /* Calculate the maximum size of the tray window and limit the window
414 size to half of the screen's size. */
415 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
416 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
417 if (szWnd
.cx
> szMax
.cx
)
419 if (szWnd
.cy
> szMax
.cy
)
422 /* FIXME - calculate */
424 GetTrayRectFromScreenRect(
435 GetMinimumWindowSize(
440 AdjustWindowRectEx(&rcMin
,
441 GetWindowLong(m_hWnd
,
444 GetWindowLong(m_hWnd
,
453 GetDraggingRectFromPt(
456 OUT HMONITOR
*phMonitor
)
458 HMONITOR hMon
, hMonNew
;
459 DWORD PosH
, PosV
, Pos
;
460 SIZE DeltaPt
, ScreenOffset
;
466 /* Determine the screen rectangle */
467 hMon
= MonitorFromPoint(pt
,
468 MONITOR_DEFAULTTONULL
);
474 mi
.cbSize
= sizeof(mi
);
475 if (!GetMonitorInfo(hMon
,
479 goto GetPrimaryScreenRect
;
482 /* make left top corner of the screen zero based to
483 make calculations easier */
484 pt
.x
-= mi
.rcMonitor
.left
;
485 pt
.y
-= mi
.rcMonitor
.top
;
487 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
488 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
489 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
490 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
494 GetPrimaryScreenRect
:
497 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
498 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
501 /* Calculate the nearest screen border */
502 if (pt
.x
< rcScreen
.right
/ 2)
509 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
513 if (pt
.y
< rcScreen
.bottom
/ 2)
520 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
524 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
526 /* Fix the screen origin to be relative to the primary monitor again */
527 OffsetRect(&rcScreen
,
531 hMonNew
= GetMonitorFromRect(
537 /* Recalculate the rectangle, we're dragging to another monitor.
538 We don't need to recalculate the rect on single monitor systems. */
539 szTray
.cx
= rcTrayWnd
[Pos
].right
- rcTrayWnd
[Pos
].left
;
540 szTray
.cy
= rcTrayWnd
[Pos
].bottom
- rcTrayWnd
[Pos
].top
;
542 GetTrayRectFromScreenRect(
549 pRect
->left
+= AutoHideOffset
.cx
;
550 pRect
->right
+= AutoHideOffset
.cx
;
551 pRect
->top
+= AutoHideOffset
.cy
;
552 pRect
->bottom
+= AutoHideOffset
.cy
;
558 /* The user is dragging the tray window on the same monitor. We don't need
559 to recalculate the rectangle */
560 *pRect
= rcTrayWnd
[Pos
];
563 pRect
->left
+= AutoHideOffset
.cx
;
564 pRect
->right
+= AutoHideOffset
.cx
;
565 pRect
->top
+= AutoHideOffset
.cy
;
566 pRect
->bottom
+= AutoHideOffset
.cy
;
576 GetDraggingRectFromRect(
578 OUT HMONITOR
*phMonitor
)
582 /* Calculate the center of the rectangle. We call
583 GetDraggingRectFromPt to calculate a valid
584 dragging rectangle */
585 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
586 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
588 return GetDraggingRectFromPt(
596 IN OUT LPWINDOWPOS pwp
)
602 rcTray
.left
= pwp
->x
;
604 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
605 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
608 rcTray
.left
-= AutoHideOffset
.cx
;
609 rcTray
.right
-= AutoHideOffset
.cx
;
610 rcTray
.top
-= AutoHideOffset
.cy
;
611 rcTray
.bottom
-= AutoHideOffset
.cy
;
614 if (!EqualRect(&rcTray
,
615 &rcTrayWnd
[DraggingPosition
]))
617 /* Recalculate the rectangle, the user dragged the tray
618 window to another monitor or the window was somehow else
620 DraggingPosition
= GetDraggingRectFromRect(
623 //rcTrayWnd[DraggingPosition] = rcTray;
626 //Monitor = CalculateValidSize(
630 Monitor
= DraggingMonitor
;
631 Position
= DraggingPosition
;
634 rcTrayWnd
[Position
] = rcTray
;
637 else if (GetWindowRect(m_hWnd
, &rcTray
))
641 if (!(pwp
->flags
& SWP_NOMOVE
))
643 rcTray
.left
= pwp
->x
;
647 if (!(pwp
->flags
& SWP_NOSIZE
))
649 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
650 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
653 Position
= GetDraggingRectFromRect(
657 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
664 MakeTrayRectWithSize(Position
, &szWnd
, &rcTray
);
669 rcTray
.left
-= AutoHideOffset
.cx
;
670 rcTray
.right
-= AutoHideOffset
.cx
;
671 rcTray
.top
-= AutoHideOffset
.cy
;
672 rcTray
.bottom
-= AutoHideOffset
.cy
;
674 rcTrayWnd
[Position
] = rcTray
;
678 /* If the user isn't resizing the tray window we need to make sure the
679 new size or position is valid. this is to prevent changes to the window
680 without user interaction. */
681 rcTray
= rcTrayWnd
[Position
];
685 TraySize
.cx
= rcTray
.right
- rcTray
.left
;
686 TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
690 rcTray
.left
+= AutoHideOffset
.cx
;
691 rcTray
.right
+= AutoHideOffset
.cx
;
692 rcTray
.top
+= AutoHideOffset
.cy
;
693 rcTray
.bottom
+= AutoHideOffset
.cy
;
696 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
697 pwp
->x
= rcTray
.left
;
699 pwp
->cx
= TraySize
.cx
;
700 pwp
->cy
= TraySize
.cy
;
705 ApplyClipping(IN BOOL Clip
)
707 RECT rcClip
, rcWindow
;
710 if (GetWindowRect(m_hWnd
, &rcWindow
))
712 /* Disable clipping on systems with only one monitor */
713 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
720 GetScreenRect(Monitor
, &rcClip
);
722 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
731 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
736 /* Set the clipping region or make sure the window isn't clipped
737 by disabling it explicitly. */
738 SetWindowRgn(m_hWnd
, hClipRgn
, TRUE
);
742 VOID
ResizeWorkArea()
744 #if !WIN7_COMPAT_MODE
745 RECT rcTray
, rcWorkArea
;
747 /* If monitor has changed then fix the previous monitors work area */
748 if (PreviousMonitor
!= Monitor
)
753 SystemParametersInfo(SPI_SETWORKAREA
,
759 rcTray
= rcTrayWnd
[Position
];
764 PreviousMonitor
= Monitor
;
766 /* If AutoHide is false then change the workarea to exclude the area that
767 the taskbar covers. */
773 rcWorkArea
.top
= rcTray
.bottom
;
776 rcWorkArea
.left
= rcTray
.right
;
779 rcWorkArea
.right
= rcTray
.left
;
782 rcWorkArea
.bottom
= rcTray
.top
;
787 SystemParametersInfo(SPI_SETWORKAREA
,
794 VOID
CheckTrayWndPosition()
798 rcTray
= rcTrayWnd
[Position
];
802 rcTray
.left
+= AutoHideOffset
.cx
;
803 rcTray
.right
+= AutoHideOffset
.cx
;
804 rcTray
.top
+= AutoHideOffset
.cy
;
805 rcTray
.bottom
+= AutoHideOffset
.cy
;
808 // TRACE("CheckTray: %d: %d,%d,%d,%d\n", Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
810 /* Move the tray window */
814 rcTray
.right
- rcTray
.left
,
815 rcTray
.bottom
- rcTray
.top
,
823 typedef struct _TW_STUCKRECTS2
831 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
839 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
840 DWORD cbSize
= sizeof(sr
);
842 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
843 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
844 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
845 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
847 if (SHGetValue(hkExplorer
,
852 &cbSize
) == ERROR_SUCCESS
&&
853 sr
.cbSize
== sizeof(sr
))
855 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
856 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
857 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
858 HideClock
= (sr
.dwFlags
& 0x8) != 0;
860 /* FIXME: Are there more flags? */
865 if (sr
.Position
> ABE_BOTTOM
)
866 Position
= ABE_BOTTOM
;
868 Position
= sr
.Position
;
871 /* Try to find out which monitor the tray window was located on last.
872 Here we're only interested in the monitor screen that we think
873 is the last one used. We're going to determine on which monitor
874 we really are after calculating the docked position. */
876 GetScreenRectFromRect(
878 MONITOR_DEFAULTTONEAREST
);
882 Position
= ABE_BOTTOM
;
885 /* Use the minimum size of the taskbar, we'll use the start
886 button as a minimum for now. Make sure we calculate the
887 entire window size, not just the client size. However, we
888 use a thinner border than a standard thick border, so that
889 the start button and bands are not stuck to the screen border. */
890 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
891 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
893 /* Use the primary screen by default */
896 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
897 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
898 GetScreenRectFromRect(
900 MONITOR_DEFAULTTOPRIMARY
);
905 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
910 SWP_NOMOVE
| SWP_NOSIZE
);
912 /* Determine a minimum tray window rectangle. The "client" height is
913 zero here since we cannot determine an optimal minimum width when
914 loaded as a vertical tray window. We just need to make sure the values
915 loaded from the registry are at least. The windows explorer behaves
916 the same way, it allows the user to save a zero width vertical tray
917 window, but not a zero height horizontal tray window. */
918 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
919 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
921 if (WndSize
.cx
< sr
.Size
.cx
)
922 WndSize
.cx
= sr
.Size
.cx
;
923 if (WndSize
.cy
< sr
.Size
.cy
)
924 WndSize
.cy
= sr
.Size
.cy
;
926 /* Save the calculated size */
929 /* Calculate all docking rectangles. We need to do this here so they're
930 initialized and dragging the tray window to another position gives
936 GetTrayRectFromScreenRect(
941 // TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, rcTrayWnd[Pos].left, rcTrayWnd[Pos].top, rcTrayWnd[Pos].right, rcTrayWnd[Pos].bottom);
944 /* Determine which monitor we are on. It shouldn't matter which docked
945 position rectangle we use */
946 Monitor
= GetMonitorFromRect(
947 &rcTrayWnd
[ABE_LEFT
]);
953 IN POINT
*ppt OPTIONAL
,
954 IN HWND hwndExclude OPTIONAL
,
956 IN BOOL IsContextMenu
)
958 TPMPARAMS tmp
, *ptmp
= NULL
;
963 if (hwndExclude
!= NULL
)
965 /* Get the client rectangle and map it to screen coordinates */
966 if (::GetClientRect(hwndExclude
,
968 MapWindowPoints(hwndExclude
,
970 (LPPOINT
) &tmp
.rcExclude
,
980 GetClientRect(&tmp
.rcExclude
) &&
981 MapWindowPoints(m_hWnd
,
983 (LPPOINT
) &tmp
.rcExclude
,
991 /* NOTE: TrackPopupMenuEx will eventually align the track position
992 for us, no need to take care of it here as long as the
993 coordinates are somewhere within the exclusion rectangle */
994 pt
.x
= ptmp
->rcExclude
.left
;
995 pt
.y
= ptmp
->rcExclude
.top
;
1003 tmp
.cbSize
= sizeof(tmp
);
1005 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
1006 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
1008 fuFlags
|= TPM_RIGHTBUTTON
;
1010 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
1012 cmdId
= TrackPopupMenuEx(hMenu
,
1022 HRESULT
TrackCtxMenu(
1023 IN IContextMenu
* contextMenu
,
1024 IN POINT
*ppt OPTIONAL
,
1025 IN HWND hwndExclude OPTIONAL
,
1027 IN PVOID Context OPTIONAL
)
1033 HMENU popup
= CreatePopupMenu();
1038 TRACE("Before Query\n");
1039 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
1040 if (FAILED_UNEXPECTEDLY(hr
))
1042 TRACE("Query failed\n");
1047 TRACE("Before Tracking\n");
1048 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
1052 TRACE("Before InvokeCommand\n");
1053 CMINVOKECOMMANDINFO cmi
= { 0 };
1054 cmi
.cbSize
= sizeof(cmi
);
1055 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
1057 hr
= contextMenu
->InvokeCommand(&cmi
);
1061 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
1070 VOID
UpdateStartButton(IN HBITMAP hbmStart OPTIONAL
)
1072 SIZE Size
= { 0, 0 };
1074 if (himlStartBtn
== NULL
||
1075 !StartButton
.SendMessage(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
1077 Size
.cx
= GetSystemMetrics(SM_CXEDGE
);
1078 Size
.cy
= GetSystemMetrics(SM_CYEDGE
);
1080 if (hbmStart
== NULL
)
1082 hbmStart
= (HBITMAP
) StartButton
.SendMessage(BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1085 if (hbmStart
!= NULL
)
1089 if (GetObject(hbmStart
,
1093 Size
.cx
+= bmp
.bmWidth
;
1094 Size
.cy
+= max(bmp
.bmHeight
,
1095 GetSystemMetrics(SM_CYCAPTION
));
1099 /* Huh?! Shouldn't happen... */
1106 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
1107 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
1111 /* Save the size of the start button */
1112 StartBtnSize
= Size
;
1116 AlignControls(IN PRECT prcClient OPTIONAL
)
1119 SIZE TraySize
, StartSize
;
1120 POINT ptTrayNotify
= { 0, 0 };
1124 UpdateStartButton(NULL
);
1125 if (prcClient
!= NULL
)
1127 rcClient
= *prcClient
;
1131 if (!GetClientRect(&rcClient
))
1137 Horizontal
= IsPosHorizontal();
1139 /* We're about to resize/move the start button, the rebar control and
1140 the tray notification control */
1141 dwp
= BeginDeferWindowPos(3);
1145 /* Limit the Start button width to the client width, if neccessary */
1146 StartSize
= StartBtnSize
;
1147 if (StartSize
.cx
> rcClient
.right
)
1148 StartSize
.cx
= rcClient
.right
;
1150 if (StartButton
.m_hWnd
!= NULL
)
1152 /* Resize and reposition the button */
1153 dwp
= DeferWindowPos(dwp
,
1160 SWP_NOZORDER
| SWP_NOACTIVATE
);
1165 /* Determine the size that the tray notification window needs */
1169 TraySize
.cy
= rcClient
.bottom
;
1173 TraySize
.cx
= rcClient
.right
;
1177 if (hwndTrayNotify
!= NULL
&&
1178 SendMessage(hwndTrayNotify
,
1179 TNWM_GETMINIMUMSIZE
,
1180 (WPARAM
) Horizontal
,
1181 (LPARAM
) &TraySize
))
1183 /* Move the tray notification window to the desired location */
1185 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1187 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1189 dwp
= DeferWindowPos(dwp
,
1196 SWP_NOZORDER
| SWP_NOACTIVATE
);
1201 /* Resize/Move the rebar control */
1202 if (hwndRebar
!= NULL
)
1204 POINT ptRebar
= { 0, 0 };
1207 SetWindowStyle(hwndRebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1211 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1212 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1213 szRebar
.cy
= rcClient
.bottom
;
1217 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1218 szRebar
.cx
= rcClient
.right
;
1219 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1222 dwp
= DeferWindowPos(dwp
,
1229 SWP_NOZORDER
| SWP_NOACTIVATE
);
1233 EndDeferWindowPos(dwp
);
1235 if (hwndTaskSwitch
!= NULL
)
1237 /* Update the task switch window configuration */
1238 SendMessage(hwndTaskSwitch
,
1239 TSWM_UPDATETASKBARPOS
,
1246 CreateStartBtnImageList()
1251 if (himlStartBtn
!= NULL
)
1254 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
1255 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
1257 /* Load the start button icon and create a image list for it */
1258 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
1259 MAKEINTRESOURCE(IDI_START
),
1263 LR_SHARED
| LR_DEFAULTCOLOR
);
1265 if (hIconStart
!= NULL
)
1267 himlStartBtn
= (IImageList
*) ImageList_Create(IconSize
.cx
,
1269 ILC_COLOR32
| ILC_MASK
,
1272 if (himlStartBtn
!= NULL
)
1275 himlStartBtn
->ReplaceIcon(-1, hIconStart
, &s
);
1281 /* Failed to add the icon! */
1282 himlStartBtn
->Release();
1283 himlStartBtn
= NULL
;
1290 HBITMAP
CreateStartButtonBitmap()
1292 WCHAR szStartCaption
[32];
1295 HDC hDCScreen
= NULL
;
1296 SIZE Size
, SmallIcon
;
1297 HBITMAP hbmpOld
, hbmp
= NULL
;
1298 HBITMAP hBitmap
= NULL
;
1304 /* NOTE: this is the backwards compatibility code that is used if the
1305 Common Controls Version 6.0 are not available! */
1307 if (!LoadString(hExplorerInstance
,
1310 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1315 /* Load the start button icon */
1316 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
1317 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
1318 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
1319 MAKEINTRESOURCE(IDI_START
),
1323 LR_SHARED
| LR_DEFAULTCOLOR
);
1325 hDCScreen
= GetDC(NULL
);
1326 if (hDCScreen
== NULL
)
1329 hDC
= CreateCompatibleDC(hDCScreen
);
1333 hFontOld
= (HFONT
) SelectObject(hDC
, hStartBtnFont
);
1335 Ret
= GetTextExtentPoint32(hDC
,
1337 _tcslen(szStartCaption
),
1345 /* Make sure the height is at least the size of a caption icon. */
1346 if (hIconStart
!= NULL
)
1347 Size
.cx
+= SmallIcon
.cx
+ 4;
1348 Size
.cy
= max(Size
.cy
, SmallIcon
.cy
);
1350 /* Create the bitmap */
1351 hbmp
= CreateCompatibleBitmap(hDCScreen
,
1357 /* Caluclate the button rect */
1360 rcButton
.right
= Size
.cx
;
1361 rcButton
.bottom
= Size
.cy
;
1363 /* Draw the button */
1364 hbmpOld
= (HBITMAP
) SelectObject(hDC
, hbmp
);
1366 Flags
= DC_TEXT
| DC_INBUTTON
;
1367 if (hIconStart
!= NULL
)
1370 if (DrawCapTemp
!= NULL
)
1372 Ret
= DrawCapTemp(NULL
,
1387 /* We successfully created the bitmap! */
1392 if (hDCScreen
!= NULL
)
1407 LRESULT
OnThemeChanged()
1410 CloseThemeData(TaskbarTheme
);
1412 if (IsThemeActive())
1413 TaskbarTheme
= OpenThemeData(m_hWnd
, L
"TaskBar");
1415 TaskbarTheme
= NULL
;
1419 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1423 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1429 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1431 return OnThemeChanged();
1434 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1436 WCHAR szStartCaption
[32];
1438 ((ITrayWindow
*)this)->AddRef();
1440 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1443 InterlockedIncrement(&TrayWndCount
);
1445 if (!LoadString(hExplorerInstance
,
1448 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1450 szStartCaption
[0] = TEXT('\0');
1453 if (hStartBtnFont
== NULL
|| hCaptionFont
== NULL
)
1455 NONCLIENTMETRICS ncm
;
1457 /* Get the system fonts, we use the caption font,
1458 always bold, though. */
1459 ncm
.cbSize
= sizeof(ncm
);
1460 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1465 if (hCaptionFont
== NULL
)
1467 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1468 hCaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1471 if (hStartBtnFont
== NULL
)
1473 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
1474 hStartBtnFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1479 /* Create the Start button */
1480 StartButton
.SubclassWindow(CreateWindowEx(
1484 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1485 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1491 (HMENU
) IDC_STARTBTN
,
1494 if (StartButton
.m_hWnd
)
1496 SetWindowTheme(StartButton
.m_hWnd
, L
"Start", NULL
);
1497 StartButton
.SendMessage(WM_SETFONT
, (WPARAM
) hStartBtnFont
, FALSE
);
1499 if (CreateStartBtnImageList())
1501 BUTTON_IMAGELIST bil
;
1503 /* Try to set the start button image. this requires the Common
1504 Controls 6.0 to be present (XP and later) */
1505 bil
.himl
= (HIMAGELIST
) himlStartBtn
;
1506 bil
.margin
.left
= bil
.margin
.right
= 1;
1507 bil
.margin
.top
= bil
.margin
.bottom
= 1;
1508 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
1510 if (!StartButton
.SendMessage(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
))
1512 /* Fall back to the deprecated method on older systems that don't
1513 support Common Controls 6.0 */
1514 himlStartBtn
->Release();
1515 himlStartBtn
= NULL
;
1517 goto SetStartBtnImage
;
1520 /* We're using the image list, remove the BS_BITMAP style and
1521 don't center it horizontally */
1522 SetWindowStyle(StartButton
.m_hWnd
, BS_BITMAP
| BS_RIGHT
, 0);
1524 UpdateStartButton(NULL
);
1528 HBITMAP hbmStart
, hbmOld
;
1531 hbmStart
= CreateStartButtonBitmap();
1532 if (hbmStart
!= NULL
)
1534 UpdateStartButton(hbmStart
);
1536 hbmOld
= (HBITMAP
) StartButton
.SendMessage(BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbmStart
);
1539 DeleteObject(hbmOld
);
1544 /* Load the saved tray window settings */
1547 /* Create and initialize the start menu */
1548 hbmStartMenu
= LoadBitmap(hExplorerInstance
,
1549 MAKEINTRESOURCE(IDB_STARTMENU
));
1550 StartMenuPopup
= CreateStartMenu(this, &StartMenuBand
, hbmStartMenu
, 0);
1552 /* Load the tray band site */
1553 if (TrayBandSite
!= NULL
)
1555 TrayBandSite
.Release();
1558 TrayBandSite
= CreateTrayBandSite(this, &hwndRebar
, &hwndTaskSwitch
);
1559 SetWindowTheme(hwndRebar
, L
"TaskBar", NULL
);
1561 /* Create the tray notification window */
1562 hwndTrayNotify
= CreateTrayNotifyWnd(this, HideClock
);
1564 if (UpdateNonClientMetrics())
1569 /* Move the tray window to the right position and resize it if neccessary */
1570 CheckTrayWndPosition();
1572 /* Align all controls on the tray window */
1576 InitShellServices(&(hdpaShellServices
));
1580 AutoHideState
= AUTOHIDE_HIDING
;
1581 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1586 HRESULT STDMETHODCALLTYPE
Open()
1590 /* Check if there's already a window created and try to show it.
1591 If it was somehow destroyed just create a new tray window. */
1592 if (m_hWnd
!= NULL
&& IsWindow())
1594 if (!IsWindowVisible(m_hWnd
))
1596 CheckTrayWndPosition();
1598 ShowWindow(SW_SHOW
);
1604 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1606 dwExStyle
|= WS_EX_TOPMOST
;
1608 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1609 WS_BORDER
| WS_THICKFRAME
;
1611 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1612 if (Position
!= (DWORD
) -1)
1613 rcWnd
= rcTrayWnd
[Position
];
1615 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1621 HRESULT STDMETHODCALLTYPE
Close()
1634 HWND STDMETHODCALLTYPE
GetHWND()
1639 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1641 return (m_hWnd
== hWnd
||
1642 (hWndDesktop
!= NULL
&& m_hWnd
== hWndDesktop
));
1645 BOOL STDMETHODCALLTYPE
1648 return IsPosHorizontal();
1651 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1653 if (phBoldCaption
!= NULL
)
1654 *phBoldCaption
= hStartBtnFont
;
1656 return hCaptionFont
;
1659 DWORD WINAPI
TrayPropertiesThread()
1664 GetWindowRect(StartButton
.m_hWnd
, &posRect
);
1665 hwnd
= CreateWindowEx(0,
1668 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1671 posRect
.right
- posRect
.left
,
1672 posRect
.bottom
- posRect
.top
,
1678 hwndTrayPropertiesOwner
= hwnd
;
1680 DisplayTrayProperties(hwnd
);
1682 hwndTrayPropertiesOwner
= NULL
;
1688 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1690 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1692 return This
->TrayPropertiesThread();
1695 HWND STDMETHODCALLTYPE
DisplayProperties()
1699 if (hwndTrayPropertiesOwner
)
1701 hTrayProp
= GetLastActivePopup(hwndTrayPropertiesOwner
);
1702 if (hTrayProp
!= NULL
&&
1703 hTrayProp
!= hwndTrayPropertiesOwner
)
1705 SetForegroundWindow(hTrayProp
);
1710 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1714 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1716 WCHAR szDir
[MAX_PATH
];
1718 if (SHGetSpecialFolderPath(hWndOwner
,
1720 CSIDL_COMMON_STARTMENU
,
1723 ShellExecute(hWndOwner
,
1732 VOID
OpenTaskManager(IN HWND hWndOwner
)
1734 ShellExecute(hWndOwner
,
1736 TEXT("taskmgr.exe"),
1742 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1744 BOOL bHandled
= TRUE
;
1748 case ID_SHELL_CMD_PROPERTIES
:
1749 DisplayProperties();
1752 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1753 OpenCommonStartMenuDirectory(m_hWnd
,
1757 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1758 OpenCommonStartMenuDirectory(m_hWnd
,
1762 case ID_LOCKTASKBAR
:
1763 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1769 case ID_SHELL_CMD_OPEN_TASKMGR
:
1770 OpenTaskManager(m_hWnd
);
1773 case ID_SHELL_CMD_UNDO_ACTION
:
1776 case ID_SHELL_CMD_SHOW_DESKTOP
:
1779 case ID_SHELL_CMD_TILE_WND_H
:
1780 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1783 case ID_SHELL_CMD_TILE_WND_V
:
1784 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1787 case ID_SHELL_CMD_CASCADE_WND
:
1788 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1791 case ID_SHELL_CMD_CUST_NOTIF
:
1794 case ID_SHELL_CMD_ADJUST_DAT
:
1795 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
1799 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1807 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1812 if (Locked
!= bLock
)
1816 if (TrayBandSite
!= NULL
)
1818 if (!SUCCEEDED(TrayBandSite
->Lock(
1831 LRESULT
DrawBackground(HDC hdc
)
1836 GetClientRect(&rect
);
1840 GetClientRect(&rect
);
1844 partId
= TBP_BACKGROUNDLEFT
;
1847 partId
= TBP_BACKGROUNDTOP
;
1850 partId
= TBP_BACKGROUNDRIGHT
;
1854 partId
= TBP_BACKGROUNDBOTTOM
;
1858 if (IsThemeBackgroundPartiallyTransparent(TaskbarTheme
, partId
, 0))
1860 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1863 DrawThemeBackground(TaskbarTheme
, hdc
, partId
, 0, &rect
, 0);
1869 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1871 HDC hdc
= (HDC
) wParam
;
1879 return DrawBackground(hdc
);
1882 int DrawSizer(IN HRGN hRgn
)
1888 GetWindowRect(m_hWnd
, &rect
);
1889 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1891 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1896 backoundPart
= TBP_SIZINGBARLEFT
;
1897 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1900 backoundPart
= TBP_SIZINGBARTOP
;
1901 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1904 backoundPart
= TBP_SIZINGBARRIGHT
;
1905 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1909 backoundPart
= TBP_SIZINGBARBOTTOM
;
1910 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1914 DrawThemeBackground(TaskbarTheme
, hdc
, backoundPart
, 0, &rect
, 0);
1916 ReleaseDC(m_hWnd
, hdc
);
1920 DWORD WINAPI
RunFileDlgThread()
1923 RUNFILEDLG RunFileDlg
;
1927 GetWindowRect(StartButton
.m_hWnd
, &posRect
);
1929 hwnd
= CreateWindowEx(0,
1932 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1935 posRect
.right
- posRect
.left
,
1936 posRect
.bottom
- posRect
.top
,
1942 hwndRunFileDlgOwner
= hwnd
;
1944 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
1945 RunFileDlg
= (RUNFILEDLG
) GetProcAddress(hShell32
, (LPCSTR
) 61);
1947 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1949 hwndRunFileDlgOwner
= NULL
;
1950 ::DestroyWindow(hwnd
);
1955 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1957 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1958 return This
->RunFileDlgThread();
1961 void DisplayRunFileDlg()
1964 if (hwndRunFileDlgOwner
)
1966 hRunDlg
= GetLastActivePopup(hwndRunFileDlgOwner
);
1967 if (hRunDlg
!= NULL
&&
1968 hRunDlg
!= hwndRunFileDlgOwner
)
1970 SetForegroundWindow(hRunDlg
);
1975 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1978 void PopupStartMenu()
1980 if (StartMenuPopup
!= NULL
)
1986 if (GetWindowRect(StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1991 pt
.x
= rcExclude
.left
;
1992 pt
.y
= rcExclude
.top
;
1993 dwFlags
|= MPPF_BOTTOM
;
1997 pt
.x
= rcExclude
.left
;
1998 pt
.y
= rcExclude
.bottom
;
1999 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
2002 pt
.x
= rcExclude
.right
;
2003 pt
.y
= rcExclude
.bottom
;
2004 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
2008 StartMenuPopup
->Popup(
2013 StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
2018 void ProcessMouseTracking()
2023 UINT state
= AutoHideState
;
2026 GetWindowRect(m_hWnd
, &rcCurrent
);
2027 over
= PtInRect(&rcCurrent
, pt
);
2029 if (StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2036 if (state
== AUTOHIDE_HIDING
)
2038 TRACE("AutoHide cancelling hide.\n");
2039 AutoHideState
= AUTOHIDE_SHOWING
;
2040 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2042 else if (state
== AUTOHIDE_HIDDEN
)
2044 TRACE("AutoHide starting show.\n");
2045 AutoHideState
= AUTOHIDE_SHOWING
;
2046 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2051 if (state
== AUTOHIDE_SHOWING
)
2053 TRACE("AutoHide cancelling show.\n");
2054 AutoHideState
= AUTOHIDE_HIDING
;
2055 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2057 else if (state
== AUTOHIDE_SHOWN
)
2059 TRACE("AutoHide starting hide.\n");
2060 AutoHideState
= AUTOHIDE_HIDING
;
2061 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2064 KillTimer(TIMER_ID_MOUSETRACK
);
2068 void ProcessAutoHide()
2070 RECT rc
= rcTrayWnd
[Position
];
2071 INT w
= TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2072 INT h
= TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2074 TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", AutoHideState
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, w
, h
);
2076 switch (AutoHideState
)
2078 case AUTOHIDE_HIDING
:
2082 AutoHideOffset
.cy
= 0;
2083 AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2084 if (AutoHideOffset
.cx
< -w
)
2085 AutoHideOffset
.cx
= -w
;
2088 AutoHideOffset
.cx
= 0;
2089 AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2090 if (AutoHideOffset
.cy
< -h
)
2091 AutoHideOffset
.cy
= -h
;
2094 AutoHideOffset
.cy
= 0;
2095 AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2096 if (AutoHideOffset
.cx
> w
)
2097 AutoHideOffset
.cx
= w
;
2100 AutoHideOffset
.cx
= 0;
2101 AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2102 if (AutoHideOffset
.cy
> h
)
2103 AutoHideOffset
.cy
= h
;
2107 if (AutoHideOffset
.cx
!= w
&& AutoHideOffset
.cy
!= h
)
2109 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2114 case AUTOHIDE_HIDDEN
:
2119 AutoHideOffset
.cx
= -w
;
2120 AutoHideOffset
.cy
= 0;
2123 AutoHideOffset
.cx
= 0;
2124 AutoHideOffset
.cy
= -h
;
2127 AutoHideOffset
.cx
= w
;
2128 AutoHideOffset
.cy
= 0;
2131 AutoHideOffset
.cx
= 0;
2132 AutoHideOffset
.cy
= h
;
2136 KillTimer(TIMER_ID_AUTOHIDE
);
2137 AutoHideState
= AUTOHIDE_HIDDEN
;
2140 case AUTOHIDE_SHOWING
:
2141 if (AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2143 AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2145 else if (AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2147 AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2151 AutoHideOffset
.cx
= 0;
2154 if (AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2156 AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2158 else if (AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2160 AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2164 AutoHideOffset
.cy
= 0;
2167 if (AutoHideOffset
.cx
!= 0 || AutoHideOffset
.cy
!= 0)
2169 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2174 case AUTOHIDE_SHOWN
:
2176 KillTimer(TIMER_ID_AUTOHIDE
);
2177 AutoHideState
= AUTOHIDE_SHOWN
;
2181 rc
.left
+= AutoHideOffset
.cx
;
2182 rc
.right
+= AutoHideOffset
.cx
;
2183 rc
.top
+= AutoHideOffset
.cy
;
2184 rc
.bottom
+= AutoHideOffset
.cy
;
2186 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, AutoHideState
);
2187 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2190 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2192 /* Load the saved tray window settings */
2195 /* Move the tray window to the right position and resize it if neccessary */
2196 CheckTrayWndPosition();
2198 /* Align all controls on the tray window */
2199 AlignControls(NULL
);
2204 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2208 TrayNotify_NotifyMsg(wParam
, lParam
);
2213 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2221 return DrawSizer((HRGN
) wParam
);
2224 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2226 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2227 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2230 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2237 /* The user may not be able to resize the tray window.
2238 Pretend like the window is not sizeable when the user
2239 clicks on the border. */
2243 SetLastError(ERROR_SUCCESS
);
2244 if (GetClientRect(&rcClient
) &&
2245 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2247 pt
.x
= (SHORT
) LOWORD(lParam
);
2248 pt
.y
= (SHORT
) HIWORD(lParam
);
2250 if (PtInRect(&rcClient
,
2253 /* The user is trying to drag the tray window */
2257 /* Depending on the position of the tray window, allow only
2258 changing the border next to the monitor working area */
2262 if (pt
.y
> rcClient
.bottom
)
2266 if (pt
.x
> rcClient
.right
)
2270 if (pt
.x
< rcClient
.left
)
2275 if (pt
.y
< rcClient
.top
)
2284 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2287 PRECT pRect
= (PRECT
) lParam
;
2289 /* We need to ensure that an application can not accidently
2290 move the tray window (using SetWindowPos). However, we still
2291 need to be able to move the window in case the user wants to
2292 drag the tray window to another position or in case the user
2293 wants to resize the tray window. */
2294 if (!Locked
&& GetCursorPos(&ptCursor
))
2297 DraggingPosition
= GetDraggingRectFromPt(
2304 *pRect
= rcTrayWnd
[Position
];
2308 pRect
->left
+= AutoHideOffset
.cx
;
2309 pRect
->right
+= AutoHideOffset
.cx
;
2310 pRect
->top
+= AutoHideOffset
.cy
;
2311 pRect
->bottom
+= AutoHideOffset
.cy
;
2317 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2319 PRECT pRect
= (PRECT
) lParam
;
2323 CalculateValidSize(Position
, pRect
);
2327 *pRect
= rcTrayWnd
[Position
];
2331 pRect
->left
+= AutoHideOffset
.cx
;
2332 pRect
->right
+= AutoHideOffset
.cx
;
2333 pRect
->top
+= AutoHideOffset
.cy
;
2334 pRect
->bottom
+= AutoHideOffset
.cy
;
2340 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2342 ChangingWinPos((LPWINDOWPOS
) lParam
);
2346 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2349 InvalidateRect(NULL
, TRUE
);
2350 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2353 /* Clip the tray window on multi monitor systems so the edges can't
2354 overlap into another monitor */
2355 ApplyClipping(TRUE
);
2357 if (!GetClientRect(&rcClient
))
2364 rcClient
.left
= rcClient
.top
= 0;
2365 rcClient
.right
= LOWORD(lParam
);
2366 rcClient
.bottom
= HIWORD(lParam
);
2369 AlignControls(&rcClient
);
2373 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2379 /* Remove the clipping on multi monitor systems while dragging around */
2380 ApplyClipping(FALSE
);
2385 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2390 /* Apply clipping */
2391 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2396 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2402 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2403 The tray window needs to handle this specially, since it normally doesn't have
2406 static const UINT uidDisableItem
[] = {
2417 /* temporarily enable the system menu */
2418 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2420 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2421 if (hSysMenu
!= NULL
)
2423 /* Disable all items that are not relevant */
2424 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2426 EnableMenuItem(hSysMenu
,
2428 MF_BYCOMMAND
| MF_GRAYED
);
2431 EnableMenuItem(hSysMenu
,
2434 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2436 /* Display the system menu */
2441 Position
!= ABE_TOP
,
2452 /* revert the system menu window style */
2453 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2463 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2465 /* We want the user to be able to get a context menu even on the nonclient
2466 area (including the sizing border)! */
2467 uMsg
= WM_CONTEXTMENU
;
2468 wParam
= (WPARAM
) m_hWnd
;
2470 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2473 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2475 LRESULT Ret
= FALSE
;
2476 POINT pt
, *ppt
= NULL
;
2477 HWND hWndExclude
= NULL
;
2479 /* Check if the administrator has forbidden access to context menus */
2480 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2483 pt
.x
= (SHORT
) LOWORD(lParam
);
2484 pt
.y
= (SHORT
) HIWORD(lParam
);
2486 if (pt
.x
!= -1 || pt
.y
!= -1)
2489 hWndExclude
= StartButton
.m_hWnd
;
2491 if ((HWND
) wParam
== StartButton
.m_hWnd
)
2493 /* Make sure we can't track the context menu if the start
2494 menu is currently being shown */
2495 if (!(StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2497 CComPtr
<IContextMenu
> ctxMenu
;
2498 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2499 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, Position
== ABE_BOTTOM
, this);
2504 /* See if the context menu should be handled by the task band site */
2505 if (ppt
!= NULL
&& TrayBandSite
!= NULL
)
2508 POINT ptClient
= *ppt
;
2510 /* Convert the coordinates to client-coordinates */
2511 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2513 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2514 if (hWndAtPt
!= NULL
&&
2515 (hWndAtPt
== hwndRebar
|| IsChild(hwndRebar
,
2518 /* Check if the user clicked on the task switch window */
2520 MapWindowPoints(NULL
, hwndRebar
, &ptClient
, 1);
2522 hWndAtPt
= ChildWindowFromPointEx(hwndRebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2523 if (hWndAtPt
== hwndTaskSwitch
)
2524 goto HandleTrayContextMenu
;
2526 /* Forward the message to the task band site */
2527 TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2530 goto HandleTrayContextMenu
;
2534 HandleTrayContextMenu
:
2535 /* Tray the default tray window context menu */
2536 CComPtr
<IContextMenu
> ctxMenu
;
2537 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2538 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2544 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2546 LRESULT Ret
= FALSE
;
2547 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2548 the rebar control! But we shouldn't forward messages that the band
2549 site doesn't handle, such as other controls (start button, tray window */
2551 HRESULT hr
= E_FAIL
;
2555 hr
= TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2560 if (TrayBandSite
== NULL
|| FAILED(hr
))
2562 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2564 if (nmh
->hwndFrom
== hwndTrayNotify
)
2569 /* Cause all controls to be aligned */
2570 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2578 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2580 /* We "handle" this message so users can't cause a weird maximize/restore
2581 window animation when double-clicking the tray window! */
2583 /* We should forward mouse messages to child windows here.
2584 Right now, this is only clock double-click */
2586 if (TrayNotify_GetClockRect(&rcClock
))
2589 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2590 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2591 if (PtInRect(&rcClock
, ptClick
))
2592 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
2597 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2603 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2606 HRESULT hr
= IUnknown_GetWindow((IUnknown
*) StartMenuPopup
, &hwndStartMenu
);
2607 if (FAILED_UNEXPECTEDLY(hr
))
2610 if (IsWindowVisible(hwndStartMenu
))
2612 StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2622 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2624 LRESULT Ret
= FALSE
;
2626 if ((HWND
) lParam
== StartButton
.m_hWnd
)
2632 if (TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2634 switch (LOWORD(wParam
))
2636 /* FIXME: Handle these commands as well */
2637 case IDM_TASKBARANDSTARTMENU
:
2639 DisplayProperties();
2645 case IDM_HELPANDSUPPORT
:
2647 /* TODO: Implement properly */
2649 LPCWSTR strSite
= L
"https://www.reactos.org/";
2651 /* TODO: Make localizable */
2652 LPCWSTR strCaption
= L
"Sorry";
2653 LPCWSTR strMessage
= L
"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed.";
2654 WCHAR tmpMessage
[512];
2656 /* TODO: Read from the registry */
2657 LPCWSTR strVerb
= NULL
; /* default */
2658 LPCWSTR strPath
= strSite
;
2659 LPCWSTR strParams
= NULL
;
2661 /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */
2662 int result
= (int) ShellExecuteW(m_hWnd
, strVerb
, strPath
, strParams
, NULL
, SW_SHOWNORMAL
);
2665 StringCchPrintfW(tmpMessage
, 512, strMessage
, strSite
, result
);
2666 MessageBoxExW(m_hWnd
, tmpMessage
, strCaption
, MB_OK
, 0);
2673 DisplayRunFileDlg();
2677 /* FIXME: Handle these commands as well */
2678 case IDM_SYNCHRONIZE
:
2680 case IDM_DISCONNECT
:
2681 case IDM_UNDOCKCOMPUTER
:
2687 EXITWINDLG ExitWinDlg
;
2689 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2690 ExitWinDlg
= (EXITWINDLG
) GetProcAddress(hShell32
, (LPCSTR
) 60);
2700 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2704 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2710 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2712 if (wParam
== TIMER_ID_MOUSETRACK
)
2714 ProcessMouseTracking();
2716 else if (wParam
== TIMER_ID_AUTOHIDE
)
2725 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2728 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2734 ::GetWindowRect(m_hWnd
, &rc
);
2738 rc
.bottom
- rc
.top
};
2740 as
->rcTarget
.right
- as
->rcTarget
.left
,
2741 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2743 as
->rcActual
.right
- as
->rcActual
.left
,
2744 as
->rcActual
.bottom
- as
->rcActual
.top
};
2747 szWindow
.cx
- szTarget
.cx
,
2748 szWindow
.cy
- szTarget
.cx
,
2754 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2757 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2760 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2761 rc
.left
= rc
.right
- szWindow
.cy
;
2764 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2765 rc
.top
= rc
.bottom
- szWindow
.cy
;
2769 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2776 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2778 BEGIN_MSG_MAP(CTrayWindow
)
2779 if (StartMenuBand
!= NULL
)
2786 Msg
.wParam
= wParam
;
2787 Msg
.lParam
= lParam
;
2789 if (StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2794 wParam
= Msg
.wParam
;
2795 lParam
= Msg
.lParam
;
2797 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2798 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2799 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2800 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2801 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2802 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2803 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2804 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2805 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2806 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2807 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2808 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2809 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2810 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2811 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2812 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2813 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2814 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2815 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2816 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2817 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2818 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2819 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2820 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2821 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2822 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2823 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2827 /*****************************************************************************/
2829 VOID
TrayProcessMessages()
2833 /* FIXME: We should keep a reference here... */
2835 while (PeekMessage(&Msg
,
2841 if (Msg
.message
== WM_QUIT
)
2844 if (StartMenuBand
== NULL
||
2845 StartMenuBand
->IsMenuMessage(
2848 TranslateMessage(&Msg
);
2849 DispatchMessage(&Msg
);
2854 VOID
TrayMessageLoop()
2859 /* FIXME: We should keep a reference here... */
2863 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2865 if (!Ret
|| Ret
== -1)
2868 if (Msg
.message
== WM_HOTKEY
)
2872 case IDHK_RUN
: /* Win+R */
2873 DisplayRunFileDlg();
2878 if (StartMenuBand
== NULL
||
2879 StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2881 TranslateMessage(&Msg
);
2882 DispatchMessage(&Msg
);
2890 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2891 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2892 * The reason we implement it is because we have to use SHCreateDesktop() so
2893 * that the shell provides the desktop window and all the features that come
2894 * with it (especially positioning of desktop icons)
2897 virtual ULONG STDMETHODCALLTYPE
GetState()
2899 /* FIXME: Return ABS_ flags? */
2900 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2904 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2906 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2907 *phWndTray
= m_hWnd
;
2911 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2913 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2915 this->hWndDesktop
= hWndDesktop
;
2919 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2921 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2925 virtual HRESULT
RaiseStartButton()
2927 StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2933 Position
= (DWORD
) -1;
2936 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2938 DECLARE_PROTECT_FINAL_CONSTRUCT()
2939 BEGIN_COM_MAP(CTrayWindow
)
2940 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2941 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2945 class CTrayWindowCtxMenu
:
2946 public CComCoClass
<CTrayWindowCtxMenu
>,
2947 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2951 CComPtr
<CTrayWindow
> TrayWnd
;
2952 CComPtr
<IContextMenu
> pcm
;
2955 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2957 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2958 this->hWndOwner
= hWndOwner
;
2962 virtual HRESULT STDMETHODCALLTYPE
2963 QueryContextMenu(HMENU hPopup
,
2969 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
2973 int count
= ::GetMenuItemCount(menubase
);
2975 for (int i
= 0; i
< count
; i
++)
2979 MENUITEMINFOW mii
= { 0 };
2980 mii
.cbSize
= sizeof(mii
);
2981 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2982 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2983 mii
.dwTypeData
= label
;
2984 mii
.cch
= _countof(label
);
2985 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2987 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
2989 mii
.fType
|= MFT_RADIOCHECK
;
2991 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
2994 ::DestroyMenu(menubase
);
2996 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3003 CheckMenuItem(hPopup
,
3005 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3007 if (TrayWnd
->TrayBandSite
!= NULL
)
3009 if (SUCCEEDED(TrayWnd
->TrayBandSite
->AddContextMenus(
3026 virtual HRESULT STDMETHODCALLTYPE
3027 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3029 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3032 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3034 CMINVOKECOMMANDINFO cmici
= { 0 };
3038 /* Setup and invoke the shell command */
3039 cmici
.cbSize
= sizeof(cmici
);
3040 cmici
.hwnd
= hWndOwner
;
3041 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3042 cmici
.nShow
= SW_NORMAL
;
3044 pcm
->InvokeCommand(&cmici
);
3049 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3056 virtual HRESULT STDMETHODCALLTYPE
3057 GetCommandString(UINT_PTR idCmd
,
3066 CTrayWindowCtxMenu()
3070 virtual ~CTrayWindowCtxMenu()
3074 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3075 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3079 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3081 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3082 mnu
->Initialize(TrayWnd
, hWndOwner
);
3087 CTrayWindow
* g_TrayWindow
;
3090 Tray_OnStartMenuDismissed()
3092 return g_TrayWindow
->RaiseStartButton();
3096 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3098 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3100 return E_OUTOFMEMORY
;
3104 g_TrayWindow
= Tray
;
3106 *ppTray
= (ITrayWindow
*) Tray
;
3111 VOID
TrayProcessMessages(ITrayWindow
*)
3113 g_TrayWindow
->TrayProcessMessages();
3116 VOID
TrayMessageLoop(ITrayWindow
*)
3118 g_TrayWindow
->TrayMessageLoop();