4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * this library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * this library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
26 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
28 #define TIMER_ID_AUTOHIDE 1
29 #define TIMER_ID_MOUSETRACK 2
30 #define MOUSETRACK_INTERVAL 100
31 #define AUTOHIDE_DELAY_HIDE 2000
32 #define AUTOHIDE_DELAY_SHOW 50
33 #define AUTOHIDE_INTERVAL_ANIMATING 10
35 #define AUTOHIDE_SPEED_SHOW 10
36 #define AUTOHIDE_SPEED_HIDE 1
38 #define AUTOHIDE_HIDDEN 0
39 #define AUTOHIDE_SHOWING 1
40 #define AUTOHIDE_SHOWN 2
41 #define AUTOHIDE_HIDING 3
43 static LONG TrayWndCount
= 0;
45 static const WCHAR szTrayWndClass
[] = TEXT("Shell_TrayWnd");
51 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
54 public CComCoClass
<CTrayWindow
>,
55 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
56 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
58 public IShellDesktopTray
60 CContainedWindow StartButton
;
65 IImageList
* himlStartBtn
;
76 HMONITOR PreviousMonitor
;
77 DWORD DraggingPosition
;
78 HMONITOR DraggingMonitor
;
87 CComPtr
<IMenuBand
> StartMenuBand
;
88 CComPtr
<IMenuPopup
> StartMenuPopup
;
91 HWND hwndTrayPropertiesOwner
;
92 HWND hwndRunFileDlgOwner
;
96 TRACKMOUSEEVENT MouseTrackingInfo
;
98 HDPA hdpaShellServices
;
101 CComPtr
<ITrayBandSite
> TrayBandSite
;
108 DWORD AlwaysOnTop
: 1;
109 DWORD SmSmallIcons
: 1;
114 DWORD InSizeMove
: 1;
115 DWORD IsDragging
: 1;
116 DWORD NewPosSize
: 1;
122 StartButton(this, 1),
129 hwndTaskSwitch(NULL
),
130 hwndTrayNotify(NULL
),
133 PreviousMonitor(NULL
),
135 DraggingMonitor(NULL
),
138 hwndTrayPropertiesOwner(NULL
),
139 hwndRunFileDlgOwner(NULL
),
141 hdpaShellServices(NULL
),
144 ZeroMemory(&StartBtnSize
, sizeof(StartBtnSize
));
145 ZeroMemory(&rcTrayWnd
, sizeof(rcTrayWnd
));
146 ZeroMemory(&rcNewPosSize
, sizeof(rcNewPosSize
));
147 ZeroMemory(&TraySize
, sizeof(TraySize
));
148 ZeroMemory(&ncm
, sizeof(ncm
));
149 ZeroMemory(&AutoHideOffset
, sizeof(AutoHideOffset
));
150 ZeroMemory(&MouseTrackingInfo
, sizeof(MouseTrackingInfo
));
153 virtual ~CTrayWindow()
155 (void) InterlockedExchangePointer((PVOID
*) &m_hWnd
, NULL
);
158 if (hdpaShellServices
!= NULL
)
160 ShutdownShellServices(hdpaShellServices
);
161 hdpaShellServices
= NULL
;
164 if (himlStartBtn
!= NULL
)
166 himlStartBtn
->Release();
170 if (hCaptionFont
!= NULL
)
172 DeleteObject(hCaptionFont
);
176 if (hStartBtnFont
!= NULL
)
178 DeleteObject(hStartBtnFont
);
179 hStartBtnFont
= NULL
;
188 if (hbmStartMenu
!= NULL
)
190 DeleteObject(hbmStartMenu
);
196 CloseThemeData(TaskbarTheme
);
200 if (InterlockedDecrement(&TrayWndCount
) == 0)
204 BOOL
LaunchCPanel(HWND hwnd
, LPCTSTR applet
)
206 WCHAR szParams
[MAX_PATH
];
208 StringCbCopy(szParams
, sizeof(szParams
),
209 TEXT("shell32.dll,Control_RunDLL "));
210 if (FAILED_UNEXPECTEDLY(StringCbCat(szParams
, sizeof(szParams
),
214 return (ShellExecute(hwnd
, TEXT("open"), TEXT("rundll32.exe"), szParams
, NULL
, SW_SHOWDEFAULT
) > (HINSTANCE
) 32);
221 BOOL
UpdateNonClientMetrics()
223 ncm
.cbSize
= sizeof(ncm
);
224 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
229 hFont
= CreateFontIndirect(&ncm
.lfMessageFont
);
236 VOID
SetWindowsFont()
238 if (hwndTrayNotify
!= NULL
)
240 SendMessage(hwndTrayNotify
, WM_SETFONT
, (WPARAM
) hFont
, TRUE
);
244 HMONITOR
GetScreenRectFromRect(
251 mi
.cbSize
= sizeof(mi
);
252 hMon
= MonitorFromRect(pRect
,
258 *pRect
= mi
.rcMonitor
;
264 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
265 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
273 HMONITOR
GetMonitorFromRect(
274 IN
const RECT
*pRect
)
278 /* In case the monitor sizes or saved sizes differ a bit (probably
279 not a lot, only so the tray window overlaps into another monitor
280 now), minimize the risk that we determine a wrong monitor by
281 using the center point of the tray window if we can't determine
282 it using the rectangle. */
283 hMon
= MonitorFromRect(pRect
,
284 MONITOR_DEFAULTTONULL
);
289 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
290 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
292 /* be less error-prone, find the nearest monitor */
293 hMon
= MonitorFromPoint(pt
,
294 MONITOR_DEFAULTTONEAREST
);
300 HMONITOR
GetScreenRect(
301 IN HMONITOR hMonitor
,
304 HMONITOR hMon
= NULL
;
306 if (hMonitor
!= NULL
)
310 mi
.cbSize
= sizeof(mi
);
311 if (!GetMonitorInfo(hMonitor
,
314 /* Hm, the monitor is gone? Try to find a monitor where it
315 could be located now */
316 hMon
= GetMonitorFromRect(
319 !GetMonitorInfo(hMon
,
327 *pRect
= mi
.rcMonitor
;
334 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
335 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
341 VOID
MakeTrayRectWithSize(IN DWORD Position
,
342 IN
const SIZE
*pTraySize
,
348 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
352 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
356 pRect
->left
= pRect
->right
- pTraySize
->cx
;
361 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
366 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
367 IN
const RECT
*pScreen
,
368 IN
const SIZE
*pTraySize OPTIONAL
,
371 if (pTraySize
== NULL
)
372 pTraySize
= &TraySize
;
376 /* Move the border outside of the screen */
378 GetSystemMetrics(SM_CXEDGE
),
379 GetSystemMetrics(SM_CYEDGE
));
381 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
387 return Position
== ABE_TOP
|| Position
== ABE_BOTTOM
;
400 //Horizontal = IsPosHorizontal();
402 szWnd
.cx
= pRect
->right
- pRect
->left
;
403 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
406 hMon
= GetScreenRectFromRect(
408 MONITOR_DEFAULTTONEAREST
);
410 /* Calculate the maximum size of the tray window and limit the window
411 size to half of the screen's size. */
412 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
413 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
414 if (szWnd
.cx
> szMax
.cx
)
416 if (szWnd
.cy
> szMax
.cy
)
419 /* FIXME - calculate */
421 GetTrayRectFromScreenRect(
432 GetMinimumWindowSize(
437 AdjustWindowRectEx(&rcMin
,
438 GetWindowLong(m_hWnd
,
441 GetWindowLong(m_hWnd
,
450 GetDraggingRectFromPt(
453 OUT HMONITOR
*phMonitor
)
455 HMONITOR hMon
, hMonNew
;
456 DWORD PosH
, PosV
, Pos
;
457 SIZE DeltaPt
, ScreenOffset
;
463 /* Determine the screen rectangle */
464 hMon
= MonitorFromPoint(pt
,
465 MONITOR_DEFAULTTONULL
);
471 mi
.cbSize
= sizeof(mi
);
472 if (!GetMonitorInfo(hMon
,
476 goto GetPrimaryScreenRect
;
479 /* make left top corner of the screen zero based to
480 make calculations easier */
481 pt
.x
-= mi
.rcMonitor
.left
;
482 pt
.y
-= mi
.rcMonitor
.top
;
484 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
485 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
486 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
487 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
491 GetPrimaryScreenRect
:
494 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
495 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
498 /* Calculate the nearest screen border */
499 if (pt
.x
< rcScreen
.right
/ 2)
506 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
510 if (pt
.y
< rcScreen
.bottom
/ 2)
517 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
521 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
523 /* Fix the screen origin to be relative to the primary monitor again */
524 OffsetRect(&rcScreen
,
528 hMonNew
= GetMonitorFromRect(
534 /* Recalculate the rectangle, we're dragging to another monitor.
535 We don't need to recalculate the rect on single monitor systems. */
536 szTray
.cx
= rcTrayWnd
[Pos
].right
- rcTrayWnd
[Pos
].left
;
537 szTray
.cy
= rcTrayWnd
[Pos
].bottom
- rcTrayWnd
[Pos
].top
;
539 GetTrayRectFromScreenRect(
546 pRect
->left
+= AutoHideOffset
.cx
;
547 pRect
->right
+= AutoHideOffset
.cx
;
548 pRect
->top
+= AutoHideOffset
.cy
;
549 pRect
->bottom
+= AutoHideOffset
.cy
;
555 /* The user is dragging the tray window on the same monitor. We don't need
556 to recalculate the rectangle */
557 *pRect
= rcTrayWnd
[Pos
];
560 pRect
->left
+= AutoHideOffset
.cx
;
561 pRect
->right
+= AutoHideOffset
.cx
;
562 pRect
->top
+= AutoHideOffset
.cy
;
563 pRect
->bottom
+= AutoHideOffset
.cy
;
573 GetDraggingRectFromRect(
575 OUT HMONITOR
*phMonitor
)
579 /* Calculate the center of the rectangle. We call
580 GetDraggingRectFromPt to calculate a valid
581 dragging rectangle */
582 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
583 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
585 return GetDraggingRectFromPt(
593 IN OUT LPWINDOWPOS pwp
)
599 rcTray
.left
= pwp
->x
;
601 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
602 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
605 rcTray
.left
-= AutoHideOffset
.cx
;
606 rcTray
.right
-= AutoHideOffset
.cx
;
607 rcTray
.top
-= AutoHideOffset
.cy
;
608 rcTray
.bottom
-= AutoHideOffset
.cy
;
611 if (!EqualRect(&rcTray
,
612 &rcTrayWnd
[DraggingPosition
]))
614 /* Recalculate the rectangle, the user dragged the tray
615 window to another monitor or the window was somehow else
617 DraggingPosition
= GetDraggingRectFromRect(
620 //rcTrayWnd[DraggingPosition] = rcTray;
623 //Monitor = CalculateValidSize(
627 Monitor
= DraggingMonitor
;
628 Position
= DraggingPosition
;
631 rcTrayWnd
[Position
] = rcTray
;
634 else if (GetWindowRect(m_hWnd
, &rcTray
))
638 if (!(pwp
->flags
& SWP_NOMOVE
))
640 rcTray
.left
= pwp
->x
;
644 if (!(pwp
->flags
& SWP_NOSIZE
))
646 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
647 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
650 Position
= GetDraggingRectFromRect(
654 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
661 MakeTrayRectWithSize(Position
, &szWnd
, &rcTray
);
666 rcTray
.left
-= AutoHideOffset
.cx
;
667 rcTray
.right
-= AutoHideOffset
.cx
;
668 rcTray
.top
-= AutoHideOffset
.cy
;
669 rcTray
.bottom
-= AutoHideOffset
.cy
;
671 rcTrayWnd
[Position
] = rcTray
;
675 /* If the user isn't resizing the tray window we need to make sure the
676 new size or position is valid. this is to prevent changes to the window
677 without user interaction. */
678 rcTray
= rcTrayWnd
[Position
];
682 TraySize
.cx
= rcTray
.right
- rcTray
.left
;
683 TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
687 rcTray
.left
+= AutoHideOffset
.cx
;
688 rcTray
.right
+= AutoHideOffset
.cx
;
689 rcTray
.top
+= AutoHideOffset
.cy
;
690 rcTray
.bottom
+= AutoHideOffset
.cy
;
693 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
694 pwp
->x
= rcTray
.left
;
696 pwp
->cx
= TraySize
.cx
;
697 pwp
->cy
= TraySize
.cy
;
702 ApplyClipping(IN BOOL Clip
)
704 RECT rcClip
, rcWindow
;
707 if (GetWindowRect(m_hWnd
, &rcWindow
))
709 /* Disable clipping on systems with only one monitor */
710 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
717 GetScreenRect(Monitor
, &rcClip
);
719 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
728 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
733 /* Set the clipping region or make sure the window isn't clipped
734 by disabling it explicitly. */
735 SetWindowRgn(m_hWnd
, hClipRgn
, TRUE
);
739 VOID
ResizeWorkArea()
741 #if !WIN7_COMPAT_MODE
742 RECT rcTray
, rcWorkArea
;
744 /* If monitor has changed then fix the previous monitors work area */
745 if (PreviousMonitor
!= Monitor
)
750 SystemParametersInfo(SPI_SETWORKAREA
,
756 rcTray
= rcTrayWnd
[Position
];
761 PreviousMonitor
= Monitor
;
763 /* If AutoHide is false then change the workarea to exclude the area that
764 the taskbar covers. */
770 rcWorkArea
.top
= rcTray
.bottom
;
773 rcWorkArea
.left
= rcTray
.right
;
776 rcWorkArea
.right
= rcTray
.left
;
779 rcWorkArea
.bottom
= rcTray
.top
;
784 SystemParametersInfo(SPI_SETWORKAREA
,
791 VOID
CheckTrayWndPosition()
795 rcTray
= rcTrayWnd
[Position
];
799 rcTray
.left
+= AutoHideOffset
.cx
;
800 rcTray
.right
+= AutoHideOffset
.cx
;
801 rcTray
.top
+= AutoHideOffset
.cy
;
802 rcTray
.bottom
+= AutoHideOffset
.cy
;
805 // TRACE("CheckTray: %d: %d,%d,%d,%d\n", Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
807 /* Move the tray window */
811 rcTray
.right
- rcTray
.left
,
812 rcTray
.bottom
- rcTray
.top
,
820 typedef struct _TW_STUCKRECTS2
828 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
836 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
837 DWORD cbSize
= sizeof(sr
);
839 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
840 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
841 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
842 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
844 if (SHGetValue(hkExplorer
,
849 &cbSize
) == ERROR_SUCCESS
&&
850 sr
.cbSize
== sizeof(sr
))
852 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
853 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
854 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
855 HideClock
= (sr
.dwFlags
& 0x8) != 0;
857 /* FIXME: Are there more flags? */
862 if (sr
.Position
> ABE_BOTTOM
)
863 Position
= ABE_BOTTOM
;
865 Position
= sr
.Position
;
868 /* Try to find out which monitor the tray window was located on last.
869 Here we're only interested in the monitor screen that we think
870 is the last one used. We're going to determine on which monitor
871 we really are after calculating the docked position. */
873 GetScreenRectFromRect(
875 MONITOR_DEFAULTTONEAREST
);
879 Position
= ABE_BOTTOM
;
882 /* Use the minimum size of the taskbar, we'll use the start
883 button as a minimum for now. Make sure we calculate the
884 entire window size, not just the client size. However, we
885 use a thinner border than a standard thick border, so that
886 the start button and bands are not stuck to the screen border. */
887 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
888 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
890 /* Use the primary screen by default */
893 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
894 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
895 GetScreenRectFromRect(
897 MONITOR_DEFAULTTOPRIMARY
);
902 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
907 SWP_NOMOVE
| SWP_NOSIZE
);
909 /* Determine a minimum tray window rectangle. The "client" height is
910 zero here since we cannot determine an optimal minimum width when
911 loaded as a vertical tray window. We just need to make sure the values
912 loaded from the registry are at least. The windows explorer behaves
913 the same way, it allows the user to save a zero width vertical tray
914 window, but not a zero height horizontal tray window. */
915 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
916 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
918 if (WndSize
.cx
< sr
.Size
.cx
)
919 WndSize
.cx
= sr
.Size
.cx
;
920 if (WndSize
.cy
< sr
.Size
.cy
)
921 WndSize
.cy
= sr
.Size
.cy
;
923 /* Save the calculated size */
926 /* Calculate all docking rectangles. We need to do this here so they're
927 initialized and dragging the tray window to another position gives
933 GetTrayRectFromScreenRect(
938 // TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, rcTrayWnd[Pos].left, rcTrayWnd[Pos].top, rcTrayWnd[Pos].right, rcTrayWnd[Pos].bottom);
941 /* Determine which monitor we are on. It shouldn't matter which docked
942 position rectangle we use */
943 Monitor
= GetMonitorFromRect(
944 &rcTrayWnd
[ABE_LEFT
]);
950 IN POINT
*ppt OPTIONAL
,
951 IN HWND hwndExclude OPTIONAL
,
953 IN BOOL IsContextMenu
)
955 TPMPARAMS tmp
, *ptmp
= NULL
;
960 if (hwndExclude
!= NULL
)
962 /* Get the client rectangle and map it to screen coordinates */
963 if (::GetClientRect(hwndExclude
,
965 MapWindowPoints(hwndExclude
,
967 (LPPOINT
) &tmp
.rcExclude
,
977 GetClientRect(&tmp
.rcExclude
) &&
978 MapWindowPoints(m_hWnd
,
980 (LPPOINT
) &tmp
.rcExclude
,
988 /* NOTE: TrackPopupMenuEx will eventually align the track position
989 for us, no need to take care of it here as long as the
990 coordinates are somewhere within the exclusion rectangle */
991 pt
.x
= ptmp
->rcExclude
.left
;
992 pt
.y
= ptmp
->rcExclude
.top
;
1000 tmp
.cbSize
= sizeof(tmp
);
1002 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
1003 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
1005 fuFlags
|= TPM_RIGHTBUTTON
;
1007 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
1009 cmdId
= TrackPopupMenuEx(hMenu
,
1019 HRESULT
TrackCtxMenu(
1020 IN IContextMenu
* contextMenu
,
1021 IN POINT
*ppt OPTIONAL
,
1022 IN HWND hwndExclude OPTIONAL
,
1024 IN PVOID Context OPTIONAL
)
1030 HMENU popup
= CreatePopupMenu();
1035 TRACE("Before Query\n");
1036 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
1037 if (FAILED_UNEXPECTEDLY(hr
))
1039 TRACE("Query failed\n");
1044 TRACE("Before Tracking\n");
1045 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
1049 TRACE("Before InvokeCommand\n");
1050 CMINVOKECOMMANDINFO cmi
= { 0 };
1051 cmi
.cbSize
= sizeof(cmi
);
1052 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
1054 hr
= contextMenu
->InvokeCommand(&cmi
);
1058 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
1067 VOID
UpdateStartButton(IN HBITMAP hbmStart OPTIONAL
)
1069 SIZE Size
= { 0, 0 };
1071 if (himlStartBtn
== NULL
||
1072 !StartButton
.SendMessage(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
1074 Size
.cx
= GetSystemMetrics(SM_CXEDGE
);
1075 Size
.cy
= GetSystemMetrics(SM_CYEDGE
);
1077 if (hbmStart
== NULL
)
1079 hbmStart
= (HBITMAP
) StartButton
.SendMessage(BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1082 if (hbmStart
!= NULL
)
1086 if (GetObject(hbmStart
,
1090 Size
.cx
+= bmp
.bmWidth
;
1091 Size
.cy
+= max(bmp
.bmHeight
,
1092 GetSystemMetrics(SM_CYCAPTION
));
1096 /* Huh?! Shouldn't happen... */
1103 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
1104 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
1108 /* Save the size of the start button */
1109 StartBtnSize
= Size
;
1113 AlignControls(IN PRECT prcClient OPTIONAL
)
1116 SIZE TraySize
, StartSize
;
1117 POINT ptTrayNotify
= { 0, 0 };
1121 UpdateStartButton(NULL
);
1122 if (prcClient
!= NULL
)
1124 rcClient
= *prcClient
;
1128 if (!GetClientRect(&rcClient
))
1134 Horizontal
= IsPosHorizontal();
1136 /* We're about to resize/move the start button, the rebar control and
1137 the tray notification control */
1138 dwp
= BeginDeferWindowPos(3);
1142 /* Limit the Start button width to the client width, if neccessary */
1143 StartSize
= StartBtnSize
;
1144 if (StartSize
.cx
> rcClient
.right
)
1145 StartSize
.cx
= rcClient
.right
;
1147 if (StartButton
.m_hWnd
!= NULL
)
1149 /* Resize and reposition the button */
1150 dwp
= DeferWindowPos(dwp
,
1157 SWP_NOZORDER
| SWP_NOACTIVATE
);
1162 /* Determine the size that the tray notification window needs */
1166 TraySize
.cy
= rcClient
.bottom
;
1170 TraySize
.cx
= rcClient
.right
;
1174 if (hwndTrayNotify
!= NULL
&&
1175 SendMessage(hwndTrayNotify
,
1176 TNWM_GETMINIMUMSIZE
,
1177 (WPARAM
) Horizontal
,
1178 (LPARAM
) &TraySize
))
1180 /* Move the tray notification window to the desired location */
1182 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1184 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1186 dwp
= DeferWindowPos(dwp
,
1193 SWP_NOZORDER
| SWP_NOACTIVATE
);
1198 /* Resize/Move the rebar control */
1199 if (hwndRebar
!= NULL
)
1201 POINT ptRebar
= { 0, 0 };
1204 SetWindowStyle(hwndRebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1208 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1209 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1210 szRebar
.cy
= rcClient
.bottom
;
1214 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1215 szRebar
.cx
= rcClient
.right
;
1216 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1219 dwp
= DeferWindowPos(dwp
,
1226 SWP_NOZORDER
| SWP_NOACTIVATE
);
1230 EndDeferWindowPos(dwp
);
1232 if (hwndTaskSwitch
!= NULL
)
1234 /* Update the task switch window configuration */
1235 SendMessage(hwndTaskSwitch
,
1236 TSWM_UPDATETASKBARPOS
,
1243 CreateStartBtnImageList()
1248 if (himlStartBtn
!= NULL
)
1251 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
1252 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
1254 /* Load the start button icon and create a image list for it */
1255 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
1256 MAKEINTRESOURCE(IDI_START
),
1260 LR_SHARED
| LR_DEFAULTCOLOR
);
1262 if (hIconStart
!= NULL
)
1264 himlStartBtn
= (IImageList
*) ImageList_Create(IconSize
.cx
,
1266 ILC_COLOR32
| ILC_MASK
,
1269 if (himlStartBtn
!= NULL
)
1272 himlStartBtn
->ReplaceIcon(-1, hIconStart
, &s
);
1278 /* Failed to add the icon! */
1279 himlStartBtn
->Release();
1280 himlStartBtn
= NULL
;
1287 HBITMAP
CreateStartButtonBitmap()
1289 WCHAR szStartCaption
[32];
1292 HDC hDCScreen
= NULL
;
1293 SIZE Size
, SmallIcon
;
1294 HBITMAP hbmpOld
, hbmp
= NULL
;
1295 HBITMAP hBitmap
= NULL
;
1301 /* NOTE: this is the backwards compatibility code that is used if the
1302 Common Controls Version 6.0 are not available! */
1304 if (!LoadString(hExplorerInstance
,
1307 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1312 /* Load the start button icon */
1313 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
1314 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
1315 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
1316 MAKEINTRESOURCE(IDI_START
),
1320 LR_SHARED
| LR_DEFAULTCOLOR
);
1322 hDCScreen
= GetDC(NULL
);
1323 if (hDCScreen
== NULL
)
1326 hDC
= CreateCompatibleDC(hDCScreen
);
1330 hFontOld
= (HFONT
) SelectObject(hDC
, hStartBtnFont
);
1332 Ret
= GetTextExtentPoint32(hDC
,
1334 _tcslen(szStartCaption
),
1342 /* Make sure the height is at least the size of a caption icon. */
1343 if (hIconStart
!= NULL
)
1344 Size
.cx
+= SmallIcon
.cx
+ 4;
1345 Size
.cy
= max(Size
.cy
, SmallIcon
.cy
);
1347 /* Create the bitmap */
1348 hbmp
= CreateCompatibleBitmap(hDCScreen
,
1354 /* Caluclate the button rect */
1357 rcButton
.right
= Size
.cx
;
1358 rcButton
.bottom
= Size
.cy
;
1360 /* Draw the button */
1361 hbmpOld
= (HBITMAP
) SelectObject(hDC
, hbmp
);
1363 Flags
= DC_TEXT
| DC_INBUTTON
;
1364 if (hIconStart
!= NULL
)
1367 if (DrawCapTemp
!= NULL
)
1369 Ret
= DrawCapTemp(NULL
,
1384 /* We successfully created the bitmap! */
1389 if (hDCScreen
!= NULL
)
1404 LRESULT
OnThemeChanged()
1407 CloseThemeData(TaskbarTheme
);
1409 if (IsThemeActive())
1410 TaskbarTheme
= OpenThemeData(m_hWnd
, L
"TaskBar");
1412 TaskbarTheme
= NULL
;
1416 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1420 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1426 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1428 return OnThemeChanged();
1431 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1433 WCHAR szStartCaption
[32];
1435 ((ITrayWindow
*)this)->AddRef();
1437 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1440 InterlockedIncrement(&TrayWndCount
);
1442 if (!LoadString(hExplorerInstance
,
1445 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1447 szStartCaption
[0] = TEXT('\0');
1450 if (hStartBtnFont
== NULL
|| hCaptionFont
== NULL
)
1452 NONCLIENTMETRICS ncm
;
1454 /* Get the system fonts, we use the caption font,
1455 always bold, though. */
1456 ncm
.cbSize
= sizeof(ncm
);
1457 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1462 if (hCaptionFont
== NULL
)
1464 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1465 hCaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1468 if (hStartBtnFont
== NULL
)
1470 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
1471 hStartBtnFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1476 /* Create the Start button */
1477 StartButton
.SubclassWindow(CreateWindowEx(
1481 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1482 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1488 (HMENU
) IDC_STARTBTN
,
1491 if (StartButton
.m_hWnd
)
1493 SetWindowTheme(StartButton
.m_hWnd
, L
"Start", NULL
);
1494 StartButton
.SendMessage(WM_SETFONT
, (WPARAM
) hStartBtnFont
, FALSE
);
1496 if (CreateStartBtnImageList())
1498 BUTTON_IMAGELIST bil
;
1500 /* Try to set the start button image. this requires the Common
1501 Controls 6.0 to be present (XP and later) */
1502 bil
.himl
= (HIMAGELIST
) himlStartBtn
;
1503 bil
.margin
.left
= bil
.margin
.right
= 1;
1504 bil
.margin
.top
= bil
.margin
.bottom
= 1;
1505 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
1507 if (!StartButton
.SendMessage(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
))
1509 /* Fall back to the deprecated method on older systems that don't
1510 support Common Controls 6.0 */
1511 himlStartBtn
->Release();
1512 himlStartBtn
= NULL
;
1514 goto SetStartBtnImage
;
1517 /* We're using the image list, remove the BS_BITMAP style and
1518 don't center it horizontally */
1519 SetWindowStyle(StartButton
.m_hWnd
, BS_BITMAP
| BS_RIGHT
, 0);
1521 UpdateStartButton(NULL
);
1525 HBITMAP hbmStart
, hbmOld
;
1528 hbmStart
= CreateStartButtonBitmap();
1529 if (hbmStart
!= NULL
)
1531 UpdateStartButton(hbmStart
);
1533 hbmOld
= (HBITMAP
) StartButton
.SendMessage(BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbmStart
);
1536 DeleteObject(hbmOld
);
1541 /* Load the saved tray window settings */
1544 /* Create and initialize the start menu */
1545 hbmStartMenu
= LoadBitmap(hExplorerInstance
,
1546 MAKEINTRESOURCE(IDB_STARTMENU
));
1547 StartMenuPopup
= CreateStartMenu(this, &StartMenuBand
, hbmStartMenu
, 0);
1549 /* Load the tray band site */
1550 if (TrayBandSite
!= NULL
)
1552 TrayBandSite
.Release();
1555 TrayBandSite
= CreateTrayBandSite(this, &hwndRebar
, &hwndTaskSwitch
);
1556 SetWindowTheme(hwndRebar
, L
"TaskBar", NULL
);
1558 /* Create the tray notification window */
1559 hwndTrayNotify
= CreateTrayNotifyWnd(this, HideClock
);
1561 if (UpdateNonClientMetrics())
1566 /* Move the tray window to the right position and resize it if neccessary */
1567 CheckTrayWndPosition();
1569 /* Align all controls on the tray window */
1573 InitShellServices(&(hdpaShellServices
));
1577 AutoHideState
= AUTOHIDE_HIDING
;
1578 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1583 HRESULT STDMETHODCALLTYPE
Open()
1587 /* Check if there's already a window created and try to show it.
1588 If it was somehow destroyed just create a new tray window. */
1589 if (m_hWnd
!= NULL
&& IsWindow())
1591 if (!IsWindowVisible(m_hWnd
))
1593 CheckTrayWndPosition();
1595 ShowWindow(SW_SHOW
);
1601 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1603 dwExStyle
|= WS_EX_TOPMOST
;
1605 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1606 WS_BORDER
| WS_THICKFRAME
;
1608 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1609 if (Position
!= (DWORD
) -1)
1610 rcWnd
= rcTrayWnd
[Position
];
1612 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1618 HRESULT STDMETHODCALLTYPE
Close()
1631 HWND STDMETHODCALLTYPE
GetHWND()
1636 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1638 return (m_hWnd
== hWnd
||
1639 (hWndDesktop
!= NULL
&& m_hWnd
== hWndDesktop
));
1642 BOOL STDMETHODCALLTYPE
1645 return IsPosHorizontal();
1648 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1650 if (phBoldCaption
!= NULL
)
1651 *phBoldCaption
= hStartBtnFont
;
1653 return hCaptionFont
;
1656 DWORD WINAPI
TrayPropertiesThread()
1661 GetWindowRect(StartButton
.m_hWnd
, &posRect
);
1662 hwnd
= CreateWindowEx(0,
1665 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1668 posRect
.right
- posRect
.left
,
1669 posRect
.bottom
- posRect
.top
,
1675 hwndTrayPropertiesOwner
= hwnd
;
1677 DisplayTrayProperties(hwnd
);
1679 hwndTrayPropertiesOwner
= NULL
;
1685 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1687 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1689 return This
->TrayPropertiesThread();
1692 HWND STDMETHODCALLTYPE
DisplayProperties()
1696 if (hwndTrayPropertiesOwner
)
1698 hTrayProp
= GetLastActivePopup(hwndTrayPropertiesOwner
);
1699 if (hTrayProp
!= NULL
&&
1700 hTrayProp
!= hwndTrayPropertiesOwner
)
1702 SetForegroundWindow(hTrayProp
);
1707 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1711 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1713 WCHAR szDir
[MAX_PATH
];
1715 if (SHGetSpecialFolderPath(hWndOwner
,
1717 CSIDL_COMMON_STARTMENU
,
1720 ShellExecute(hWndOwner
,
1729 VOID
OpenTaskManager(IN HWND hWndOwner
)
1731 ShellExecute(hWndOwner
,
1733 TEXT("taskmgr.exe"),
1739 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1741 BOOL bHandled
= TRUE
;
1745 case ID_SHELL_CMD_PROPERTIES
:
1746 DisplayProperties();
1749 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1750 OpenCommonStartMenuDirectory(m_hWnd
,
1754 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1755 OpenCommonStartMenuDirectory(m_hWnd
,
1759 case ID_LOCKTASKBAR
:
1760 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1766 case ID_SHELL_CMD_OPEN_TASKMGR
:
1767 OpenTaskManager(m_hWnd
);
1770 case ID_SHELL_CMD_UNDO_ACTION
:
1773 case ID_SHELL_CMD_SHOW_DESKTOP
:
1776 case ID_SHELL_CMD_TILE_WND_H
:
1777 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1780 case ID_SHELL_CMD_TILE_WND_V
:
1781 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1784 case ID_SHELL_CMD_CASCADE_WND
:
1785 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1788 case ID_SHELL_CMD_CUST_NOTIF
:
1791 case ID_SHELL_CMD_ADJUST_DAT
:
1792 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
1796 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1804 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1809 if (Locked
!= bLock
)
1813 if (TrayBandSite
!= NULL
)
1815 if (!SUCCEEDED(TrayBandSite
->Lock(
1828 LRESULT
DrawBackground(HDC hdc
)
1833 GetClientRect(&rect
);
1837 GetClientRect(&rect
);
1841 partId
= TBP_BACKGROUNDLEFT
;
1844 partId
= TBP_BACKGROUNDTOP
;
1847 partId
= TBP_BACKGROUNDRIGHT
;
1851 partId
= TBP_BACKGROUNDBOTTOM
;
1855 DrawThemeBackground(TaskbarTheme
, hdc
, partId
, 0, &rect
, 0);
1861 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1863 HDC hdc
= (HDC
) wParam
;
1871 return DrawBackground(hdc
);
1874 int DrawSizer(IN HRGN hRgn
)
1880 GetWindowRect(m_hWnd
, &rect
);
1881 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1883 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1888 backoundPart
= TBP_SIZINGBARLEFT
;
1889 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1892 backoundPart
= TBP_SIZINGBARTOP
;
1893 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1896 backoundPart
= TBP_SIZINGBARRIGHT
;
1897 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1901 backoundPart
= TBP_SIZINGBARBOTTOM
;
1902 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1906 DrawThemeBackground(TaskbarTheme
, hdc
, backoundPart
, 0, &rect
, 0);
1908 ReleaseDC(m_hWnd
, hdc
);
1912 DWORD WINAPI
RunFileDlgThread()
1915 RUNFILEDLG RunFileDlg
;
1919 GetWindowRect(StartButton
.m_hWnd
, &posRect
);
1921 hwnd
= CreateWindowEx(0,
1924 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1927 posRect
.right
- posRect
.left
,
1928 posRect
.bottom
- posRect
.top
,
1934 hwndRunFileDlgOwner
= hwnd
;
1936 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
1937 RunFileDlg
= (RUNFILEDLG
) GetProcAddress(hShell32
, (LPCSTR
) 61);
1939 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1941 hwndRunFileDlgOwner
= NULL
;
1942 ::DestroyWindow(hwnd
);
1947 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1949 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1950 return This
->RunFileDlgThread();
1953 void DisplayRunFileDlg()
1956 if (hwndRunFileDlgOwner
)
1958 hRunDlg
= GetLastActivePopup(hwndRunFileDlgOwner
);
1959 if (hRunDlg
!= NULL
&&
1960 hRunDlg
!= hwndRunFileDlgOwner
)
1962 SetForegroundWindow(hRunDlg
);
1967 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1970 void PopupStartMenu()
1972 if (StartMenuPopup
!= NULL
)
1978 if (GetWindowRect(StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1983 pt
.x
= rcExclude
.left
;
1984 pt
.y
= rcExclude
.top
;
1985 dwFlags
|= MPPF_BOTTOM
;
1989 pt
.x
= rcExclude
.left
;
1990 pt
.y
= rcExclude
.bottom
;
1991 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
1994 pt
.x
= rcExclude
.right
;
1995 pt
.y
= rcExclude
.bottom
;
1996 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
2000 StartMenuPopup
->Popup(
2005 StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
2010 void ProcessMouseTracking()
2015 UINT state
= AutoHideState
;
2018 GetWindowRect(m_hWnd
, &rcCurrent
);
2019 over
= PtInRect(&rcCurrent
, pt
);
2021 if (StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2028 if (state
== AUTOHIDE_HIDING
)
2030 TRACE("AutoHide cancelling hide.\n");
2031 AutoHideState
= AUTOHIDE_SHOWING
;
2032 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2034 else if (state
== AUTOHIDE_HIDDEN
)
2036 TRACE("AutoHide starting show.\n");
2037 AutoHideState
= AUTOHIDE_SHOWING
;
2038 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2043 if (state
== AUTOHIDE_SHOWING
)
2045 TRACE("AutoHide cancelling show.\n");
2046 AutoHideState
= AUTOHIDE_HIDING
;
2047 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2049 else if (state
== AUTOHIDE_SHOWN
)
2051 TRACE("AutoHide starting hide.\n");
2052 AutoHideState
= AUTOHIDE_HIDING
;
2053 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2056 KillTimer(TIMER_ID_MOUSETRACK
);
2060 void ProcessAutoHide()
2062 RECT rc
= rcTrayWnd
[Position
];
2063 INT w
= TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2064 INT h
= TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2066 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
);
2068 switch (AutoHideState
)
2070 case AUTOHIDE_HIDING
:
2074 AutoHideOffset
.cy
= 0;
2075 AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2076 if (AutoHideOffset
.cx
< -w
)
2077 AutoHideOffset
.cx
= -w
;
2080 AutoHideOffset
.cx
= 0;
2081 AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2082 if (AutoHideOffset
.cy
< -h
)
2083 AutoHideOffset
.cy
= -h
;
2086 AutoHideOffset
.cy
= 0;
2087 AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2088 if (AutoHideOffset
.cx
> w
)
2089 AutoHideOffset
.cx
= w
;
2092 AutoHideOffset
.cx
= 0;
2093 AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2094 if (AutoHideOffset
.cy
> h
)
2095 AutoHideOffset
.cy
= h
;
2099 if (AutoHideOffset
.cx
!= w
&& AutoHideOffset
.cy
!= h
)
2101 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2106 case AUTOHIDE_HIDDEN
:
2111 AutoHideOffset
.cx
= -w
;
2112 AutoHideOffset
.cy
= 0;
2115 AutoHideOffset
.cx
= 0;
2116 AutoHideOffset
.cy
= -h
;
2119 AutoHideOffset
.cx
= w
;
2120 AutoHideOffset
.cy
= 0;
2123 AutoHideOffset
.cx
= 0;
2124 AutoHideOffset
.cy
= h
;
2128 KillTimer(TIMER_ID_AUTOHIDE
);
2129 AutoHideState
= AUTOHIDE_HIDDEN
;
2132 case AUTOHIDE_SHOWING
:
2133 if (AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2135 AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2137 else if (AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2139 AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2143 AutoHideOffset
.cx
= 0;
2146 if (AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2148 AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2150 else if (AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2152 AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2156 AutoHideOffset
.cy
= 0;
2159 if (AutoHideOffset
.cx
!= 0 || AutoHideOffset
.cy
!= 0)
2161 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2166 case AUTOHIDE_SHOWN
:
2168 KillTimer(TIMER_ID_AUTOHIDE
);
2169 AutoHideState
= AUTOHIDE_SHOWN
;
2173 rc
.left
+= AutoHideOffset
.cx
;
2174 rc
.right
+= AutoHideOffset
.cx
;
2175 rc
.top
+= AutoHideOffset
.cy
;
2176 rc
.bottom
+= AutoHideOffset
.cy
;
2178 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, AutoHideState
);
2179 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2182 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2184 /* Load the saved tray window settings */
2187 /* Move the tray window to the right position and resize it if neccessary */
2188 CheckTrayWndPosition();
2190 /* Align all controls on the tray window */
2191 AlignControls(NULL
);
2196 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2200 TrayNotify_NotifyMsg(wParam
, lParam
);
2205 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2213 return DrawSizer((HRGN
) wParam
);
2216 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2218 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2219 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2222 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2229 /* The user may not be able to resize the tray window.
2230 Pretend like the window is not sizeable when the user
2231 clicks on the border. */
2235 SetLastError(ERROR_SUCCESS
);
2236 if (GetClientRect(&rcClient
) &&
2237 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2239 pt
.x
= (SHORT
) LOWORD(lParam
);
2240 pt
.y
= (SHORT
) HIWORD(lParam
);
2242 if (PtInRect(&rcClient
,
2245 /* The user is trying to drag the tray window */
2249 /* Depending on the position of the tray window, allow only
2250 changing the border next to the monitor working area */
2254 if (pt
.y
> rcClient
.bottom
)
2258 if (pt
.x
> rcClient
.right
)
2262 if (pt
.x
< rcClient
.left
)
2267 if (pt
.y
< rcClient
.top
)
2276 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2279 PRECT pRect
= (PRECT
) lParam
;
2281 /* We need to ensure that an application can not accidently
2282 move the tray window (using SetWindowPos). However, we still
2283 need to be able to move the window in case the user wants to
2284 drag the tray window to another position or in case the user
2285 wants to resize the tray window. */
2286 if (!Locked
&& GetCursorPos(&ptCursor
))
2289 DraggingPosition
= GetDraggingRectFromPt(
2296 *pRect
= rcTrayWnd
[Position
];
2300 pRect
->left
+= AutoHideOffset
.cx
;
2301 pRect
->right
+= AutoHideOffset
.cx
;
2302 pRect
->top
+= AutoHideOffset
.cy
;
2303 pRect
->bottom
+= AutoHideOffset
.cy
;
2309 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2311 PRECT pRect
= (PRECT
) lParam
;
2315 CalculateValidSize(Position
, pRect
);
2319 *pRect
= rcTrayWnd
[Position
];
2323 pRect
->left
+= AutoHideOffset
.cx
;
2324 pRect
->right
+= AutoHideOffset
.cx
;
2325 pRect
->top
+= AutoHideOffset
.cy
;
2326 pRect
->bottom
+= AutoHideOffset
.cy
;
2332 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2334 ChangingWinPos((LPWINDOWPOS
) lParam
);
2338 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2341 InvalidateRect(NULL
, TRUE
);
2342 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2345 /* Clip the tray window on multi monitor systems so the edges can't
2346 overlap into another monitor */
2347 ApplyClipping(TRUE
);
2349 if (!GetClientRect(&rcClient
))
2356 rcClient
.left
= rcClient
.top
= 0;
2357 rcClient
.right
= LOWORD(lParam
);
2358 rcClient
.bottom
= HIWORD(lParam
);
2361 AlignControls(&rcClient
);
2365 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2371 /* Remove the clipping on multi monitor systems while dragging around */
2372 ApplyClipping(FALSE
);
2377 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2382 /* Apply clipping */
2383 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2388 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2394 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2395 The tray window needs to handle this specially, since it normally doesn't have
2398 static const UINT uidDisableItem
[] = {
2409 /* temporarily enable the system menu */
2410 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2412 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2413 if (hSysMenu
!= NULL
)
2415 /* Disable all items that are not relevant */
2416 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2418 EnableMenuItem(hSysMenu
,
2420 MF_BYCOMMAND
| MF_GRAYED
);
2423 EnableMenuItem(hSysMenu
,
2426 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2428 /* Display the system menu */
2433 Position
!= ABE_TOP
,
2444 /* revert the system menu window style */
2445 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2455 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2457 /* We want the user to be able to get a context menu even on the nonclient
2458 area (including the sizing border)! */
2459 uMsg
= WM_CONTEXTMENU
;
2460 wParam
= (WPARAM
) m_hWnd
;
2462 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2465 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2467 LRESULT Ret
= FALSE
;
2468 POINT pt
, *ppt
= NULL
;
2469 HWND hWndExclude
= NULL
;
2471 /* Check if the administrator has forbidden access to context menus */
2472 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2475 pt
.x
= (SHORT
) LOWORD(lParam
);
2476 pt
.y
= (SHORT
) HIWORD(lParam
);
2478 if (pt
.x
!= -1 || pt
.y
!= -1)
2481 hWndExclude
= StartButton
.m_hWnd
;
2483 if ((HWND
) wParam
== StartButton
.m_hWnd
)
2485 /* Make sure we can't track the context menu if the start
2486 menu is currently being shown */
2487 if (!(StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2489 CComPtr
<IContextMenu
> ctxMenu
;
2490 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2491 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, Position
== ABE_BOTTOM
, this);
2496 /* See if the context menu should be handled by the task band site */
2497 if (ppt
!= NULL
&& TrayBandSite
!= NULL
)
2500 POINT ptClient
= *ppt
;
2502 /* Convert the coordinates to client-coordinates */
2503 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2505 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2506 if (hWndAtPt
!= NULL
&&
2507 (hWndAtPt
== hwndRebar
|| IsChild(hwndRebar
,
2510 /* Check if the user clicked on the task switch window */
2512 MapWindowPoints(NULL
, hwndRebar
, &ptClient
, 1);
2514 hWndAtPt
= ChildWindowFromPointEx(hwndRebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2515 if (hWndAtPt
== hwndTaskSwitch
)
2516 goto HandleTrayContextMenu
;
2518 /* Forward the message to the task band site */
2519 TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2522 goto HandleTrayContextMenu
;
2526 HandleTrayContextMenu
:
2527 /* Tray the default tray window context menu */
2528 CComPtr
<IContextMenu
> ctxMenu
;
2529 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2530 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2536 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2538 LRESULT Ret
= FALSE
;
2539 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2540 the rebar control! But we shouldn't forward messages that the band
2541 site doesn't handle, such as other controls (start button, tray window */
2543 HRESULT hr
= E_FAIL
;
2547 hr
= TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2552 if (TrayBandSite
== NULL
|| FAILED(hr
))
2554 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2556 if (nmh
->hwndFrom
== hwndTrayNotify
)
2561 /* Cause all controls to be aligned */
2562 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2570 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2572 /* We "handle" this message so users can't cause a weird maximize/restore
2573 window animation when double-clicking the tray window! */
2575 /* We should forward mouse messages to child windows here.
2576 Right now, this is only clock double-click */
2578 if (TrayNotify_GetClockRect(&rcClock
))
2581 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2582 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2583 if (PtInRect(&rcClock
, ptClick
))
2584 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
2589 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2595 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2598 HRESULT hr
= IUnknown_GetWindow((IUnknown
*) StartMenuPopup
, &hwndStartMenu
);
2599 if (FAILED_UNEXPECTEDLY(hr
))
2602 if (IsWindowVisible(hwndStartMenu
))
2604 StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2614 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2616 LRESULT Ret
= FALSE
;
2618 if ((HWND
) lParam
== StartButton
.m_hWnd
)
2624 if (TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2626 switch (LOWORD(wParam
))
2628 /* FIXME: Handle these commands as well */
2629 case IDM_TASKBARANDSTARTMENU
:
2631 DisplayProperties();
2637 case IDM_HELPANDSUPPORT
:
2639 /* TODO: Implement properly */
2641 LPCWSTR strSite
= L
"https://www.reactos.org/";
2643 /* TODO: Make localizable */
2644 LPCWSTR strCaption
= L
"Sorry";
2645 LPCWSTR strMessage
= L
"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed.";
2646 WCHAR tmpMessage
[512];
2648 /* TODO: Read from the registry */
2649 LPCWSTR strVerb
= NULL
; /* default */
2650 LPCWSTR strPath
= strSite
;
2651 LPCWSTR strParams
= NULL
;
2653 /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */
2654 int result
= (int) ShellExecuteW(m_hWnd
, strVerb
, strPath
, strParams
, NULL
, SW_SHOWNORMAL
);
2657 StringCchPrintfW(tmpMessage
, 512, strMessage
, strSite
, result
);
2658 MessageBoxExW(m_hWnd
, tmpMessage
, strCaption
, MB_OK
, 0);
2665 DisplayRunFileDlg();
2669 /* FIXME: Handle these commands as well */
2670 case IDM_SYNCHRONIZE
:
2672 case IDM_DISCONNECT
:
2673 case IDM_UNDOCKCOMPUTER
:
2679 EXITWINDLG ExitWinDlg
;
2681 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2682 ExitWinDlg
= (EXITWINDLG
) GetProcAddress(hShell32
, (LPCSTR
) 60);
2692 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2696 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2702 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2704 if (wParam
== TIMER_ID_MOUSETRACK
)
2706 ProcessMouseTracking();
2708 else if (wParam
== TIMER_ID_AUTOHIDE
)
2717 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2720 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2726 ::GetWindowRect(m_hWnd
, &rc
);
2730 rc
.bottom
- rc
.top
};
2732 as
->rcTarget
.right
- as
->rcTarget
.left
,
2733 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2735 as
->rcActual
.right
- as
->rcActual
.left
,
2736 as
->rcActual
.bottom
- as
->rcActual
.top
};
2739 szWindow
.cx
- szTarget
.cx
,
2740 szWindow
.cy
- szTarget
.cx
,
2746 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2749 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2752 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2753 rc
.left
= rc
.right
- szWindow
.cy
;
2756 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2757 rc
.top
= rc
.bottom
- szWindow
.cy
;
2761 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2768 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2770 BEGIN_MSG_MAP(CTrayWindow
)
2771 if (StartMenuBand
!= NULL
)
2778 Msg
.wParam
= wParam
;
2779 Msg
.lParam
= lParam
;
2781 if (StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2786 wParam
= Msg
.wParam
;
2787 lParam
= Msg
.lParam
;
2789 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2790 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2791 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2792 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2793 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2794 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2795 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2796 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2797 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2798 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2799 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2800 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2801 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2802 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2803 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2804 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2805 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2806 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2807 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2808 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2809 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2810 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2811 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2812 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2813 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2814 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2815 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2819 /*****************************************************************************/
2821 VOID
TrayProcessMessages()
2825 /* FIXME: We should keep a reference here... */
2827 while (PeekMessage(&Msg
,
2833 if (Msg
.message
== WM_QUIT
)
2836 if (StartMenuBand
== NULL
||
2837 StartMenuBand
->IsMenuMessage(
2840 TranslateMessage(&Msg
);
2841 DispatchMessage(&Msg
);
2846 VOID
TrayMessageLoop()
2851 /* FIXME: We should keep a reference here... */
2855 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2857 if (!Ret
|| Ret
== -1)
2860 if (Msg
.message
== WM_HOTKEY
)
2864 case IDHK_RUN
: /* Win+R */
2865 DisplayRunFileDlg();
2870 if (StartMenuBand
== NULL
||
2871 StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2873 TranslateMessage(&Msg
);
2874 DispatchMessage(&Msg
);
2882 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2883 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2884 * The reason we implement it is because we have to use SHCreateDesktop() so
2885 * that the shell provides the desktop window and all the features that come
2886 * with it (especially positioning of desktop icons)
2889 virtual ULONG STDMETHODCALLTYPE
GetState()
2891 /* FIXME: Return ABS_ flags? */
2892 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2896 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2898 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2899 *phWndTray
= m_hWnd
;
2903 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2905 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2907 this->hWndDesktop
= hWndDesktop
;
2911 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2913 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2917 virtual HRESULT
RaiseStartButton()
2919 StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2925 Position
= (DWORD
) -1;
2928 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2930 DECLARE_PROTECT_FINAL_CONSTRUCT()
2931 BEGIN_COM_MAP(CTrayWindow
)
2932 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2933 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2937 class CTrayWindowCtxMenu
:
2938 public CComCoClass
<CTrayWindowCtxMenu
>,
2939 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2943 CComPtr
<CTrayWindow
> TrayWnd
;
2944 CComPtr
<IContextMenu
> pcm
;
2947 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2949 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2950 this->hWndOwner
= hWndOwner
;
2954 virtual HRESULT STDMETHODCALLTYPE
2955 QueryContextMenu(HMENU hPopup
,
2961 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
2965 int count
= ::GetMenuItemCount(menubase
);
2967 for (int i
= 0; i
< count
; i
++)
2971 MENUITEMINFOW mii
= { 0 };
2972 mii
.cbSize
= sizeof(mii
);
2973 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2974 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2975 mii
.dwTypeData
= label
;
2976 mii
.cch
= _countof(label
);
2977 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2979 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
2981 mii
.fType
|= MFT_RADIOCHECK
;
2983 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
2986 ::DestroyMenu(menubase
);
2988 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2995 CheckMenuItem(hPopup
,
2997 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
2999 if (TrayWnd
->TrayBandSite
!= NULL
)
3001 if (SUCCEEDED(TrayWnd
->TrayBandSite
->AddContextMenus(
3018 virtual HRESULT STDMETHODCALLTYPE
3019 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3021 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3024 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3026 CMINVOKECOMMANDINFO cmici
= { 0 };
3030 /* Setup and invoke the shell command */
3031 cmici
.cbSize
= sizeof(cmici
);
3032 cmici
.hwnd
= hWndOwner
;
3033 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3034 cmici
.nShow
= SW_NORMAL
;
3036 pcm
->InvokeCommand(&cmici
);
3041 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3048 virtual HRESULT STDMETHODCALLTYPE
3049 GetCommandString(UINT_PTR idCmd
,
3058 CTrayWindowCtxMenu()
3062 virtual ~CTrayWindowCtxMenu()
3066 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3067 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3071 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3073 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3074 mnu
->Initialize(TrayWnd
, hWndOwner
);
3079 CTrayWindow
* g_TrayWindow
;
3082 Tray_OnStartMenuDismissed()
3084 return g_TrayWindow
->RaiseStartButton();
3088 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3090 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3092 return E_OUTOFMEMORY
;
3096 g_TrayWindow
= Tray
;
3098 *ppTray
= (ITrayWindow
*) Tray
;
3103 VOID
TrayProcessMessages(ITrayWindow
*)
3105 g_TrayWindow
->TrayProcessMessages();
3108 VOID
TrayMessageLoop(ITrayWindow
*)
3110 g_TrayWindow
->TrayMessageLoop();