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
23 extern HRESULT
InitShellServices(HDPA
* phdpa
);
24 extern HRESULT
ShutdownShellServices(HDPA hdpa
);
26 static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu
;
28 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
30 #define TIMER_ID_AUTOHIDE 1
31 #define TIMER_ID_MOUSETRACK 2
32 #define MOUSETRACK_INTERVAL 100
33 #define AUTOHIDE_DELAY_HIDE 2000
34 #define AUTOHIDE_DELAY_SHOW 50
35 #define AUTOHIDE_INTERVAL_ANIMATING 10
37 #define AUTOHIDE_SPEED_SHOW 10
38 #define AUTOHIDE_SPEED_HIDE 1
40 #define AUTOHIDE_HIDDEN 0
41 #define AUTOHIDE_SHOWING 1
42 #define AUTOHIDE_SHOWN 2
43 #define AUTOHIDE_HIDING 3
45 static LONG TrayWndCount
= 0;
47 static const TCHAR szTrayWndClass
[] = TEXT("Shell_TrayWnd");
49 static const ITrayWindowVtbl ITrayWindowImpl_Vtbl
;
50 static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl
;
56 const GUID IID_IShellDesktopTray
= {0x213e2df9, 0x9a14, 0x4328, {0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9}};
60 const ITrayWindowVtbl
*lpVtbl
;
61 const IShellDesktopTrayVtbl
*lpVtblShellDesktopTray
;
69 HIMAGELIST himlStartBtn
;
74 ITrayBandSite
*TrayBandSite
;
81 HMONITOR PreviousMonitor
;
82 DWORD DraggingPosition
;
83 HMONITOR DraggingMonitor
;
94 DWORD AlwaysOnTop
: 1;
95 DWORD SmSmallIcons
: 1;
100 DWORD InSizeMove
: 1;
101 DWORD IsDragging
: 1;
102 DWORD NewPosSize
: 1;
106 NONCLIENTMETRICS ncm
;
109 IMenuBand
*StartMenuBand
;
110 IMenuPopup
*StartMenuPopup
;
111 HBITMAP hbmStartMenu
;
113 HWND hwndTrayPropertiesOwner
;
114 HWND hwndRunFileDlgOwner
;
118 TRACKMOUSEEVENT MouseTrackingInfo
;
120 HDPA hdpaShellServices
;
123 static ITrayWindowImpl
* g_TrayWindow
;
125 BOOL
LaunchCPanel(HWND hwnd
, LPCTSTR applet
)
127 TCHAR szParams
[MAX_PATH
];
129 StringCbCopy(szParams
, sizeof(szParams
),
130 TEXT("shell32.dll,Control_RunDLL "));
131 if (FAILED(StringCbCat(szParams
, sizeof(szParams
),
135 return (ShellExecute(hwnd
, TEXT("open"), TEXT("rundll32.exe"), szParams
, NULL
, SW_SHOWDEFAULT
) > (HINSTANCE
)32);
139 IUnknown_from_impl(ITrayWindowImpl
*This
)
141 return (IUnknown
*)&This
->lpVtbl
;
145 ITrayWindow_from_impl(ITrayWindowImpl
*This
)
147 return (ITrayWindow
*)&This
->lpVtbl
;
150 static IShellDesktopTray
*
151 IShellDesktopTray_from_impl(ITrayWindowImpl
*This
)
153 return (IShellDesktopTray
*)&This
->lpVtblShellDesktopTray
;
156 static ITrayWindowImpl
*
157 impl_from_ITrayWindow(ITrayWindow
*iface
)
159 return (ITrayWindowImpl
*)((ULONG_PTR
)iface
- FIELD_OFFSET(ITrayWindowImpl
,
163 static ITrayWindowImpl
*
164 impl_from_IShellDesktopTray(IShellDesktopTray
*iface
)
166 return (ITrayWindowImpl
*)((ULONG_PTR
)iface
- FIELD_OFFSET(ITrayWindowImpl
,
167 lpVtblShellDesktopTray
));
175 ITrayWindowImpl_UpdateNonClientMetrics(IN OUT ITrayWindowImpl
*This
)
177 This
->ncm
.cbSize
= sizeof(This
->ncm
);
178 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
183 if (This
->hFont
!= NULL
)
184 DeleteObject(This
->hFont
);
186 This
->hFont
= CreateFontIndirect(&This
->ncm
.lfMessageFont
);
194 ITrayWindowImpl_SetWindowsFont(IN OUT ITrayWindowImpl
*This
)
196 if (This
->hwndTrayNotify
!= NULL
)
198 SendMessage(This
->hwndTrayNotify
,
206 ITrayWindowImpl_GetScreenRectFromRect(IN OUT ITrayWindowImpl
*This
,
213 mi
.cbSize
= sizeof(mi
);
214 hMon
= MonitorFromRect(pRect
,
220 *pRect
= mi
.rcMonitor
;
226 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
227 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
236 ITrayWindowImpl_GetMonitorFromRect(IN OUT ITrayWindowImpl
*This
,
237 IN
const RECT
*pRect
)
241 /* In case the monitor sizes or saved sizes differ a bit (probably
242 not a lot, only so the tray window overlaps into another monitor
243 now), minimize the risk that we determine a wrong monitor by
244 using the center point of the tray window if we can't determine
245 it using the rectangle. */
246 hMon
= MonitorFromRect(pRect
,
247 MONITOR_DEFAULTTONULL
);
252 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
253 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
255 /* be less error-prone, find the nearest monitor */
256 hMon
= MonitorFromPoint(pt
,
257 MONITOR_DEFAULTTONEAREST
);
264 ITrayWindowImpl_GetScreenRect(IN OUT ITrayWindowImpl
*This
,
265 IN HMONITOR hMonitor
,
268 HMONITOR hMon
= NULL
;
270 if (hMonitor
!= NULL
)
274 mi
.cbSize
= sizeof(mi
);
275 if (!GetMonitorInfo(hMonitor
,
278 /* Hm, the monitor is gone? Try to find a monitor where it
279 could be located now */
280 hMon
= ITrayWindowImpl_GetMonitorFromRect(This
,
283 !GetMonitorInfo(hMon
,
291 *pRect
= mi
.rcMonitor
;
298 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
299 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
306 ITrayWindowImpl_MakeTrayRectWithSize(IN DWORD Position
,
307 IN
const SIZE
*pTraySize
,
313 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
317 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
321 pRect
->left
= pRect
->right
- pTraySize
->cx
;
326 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
332 ITrayWindowImpl_GetTrayRectFromScreenRect(IN OUT ITrayWindowImpl
*This
,
334 IN
const RECT
*pScreen
,
335 IN
const SIZE
*pTraySize OPTIONAL
,
338 if (pTraySize
== NULL
)
339 pTraySize
= &This
->TraySize
;
343 /* Move the border outside of the screen */
345 GetSystemMetrics(SM_CXEDGE
),
346 GetSystemMetrics(SM_CYEDGE
));
348 ITrayWindowImpl_MakeTrayRectWithSize(Position
,
354 ITrayWindowImpl_IsPosHorizontal(IN OUT ITrayWindowImpl
*This
)
356 return This
->Position
== ABE_TOP
|| This
->Position
== ABE_BOTTOM
;
360 ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl
*This
,
369 //Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
371 szWnd
.cx
= pRect
->right
- pRect
->left
;
372 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
375 hMon
= ITrayWindowImpl_GetScreenRectFromRect(This
,
377 MONITOR_DEFAULTTONEAREST
);
379 /* Calculate the maximum size of the tray window and limit the window
380 size to half of the screen's size. */
381 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
382 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
383 if (szWnd
.cx
> szMax
.cx
)
385 if (szWnd
.cy
> szMax
.cy
)
388 /* FIXME - calculate */
390 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
401 ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl
*This
,
406 AdjustWindowRectEx(&rcMin
,
407 GetWindowLong(This
->hWnd
,
410 GetWindowLong(This
->hWnd
,
419 ITrayWindowImpl_GetDraggingRectFromPt(IN OUT ITrayWindowImpl
*This
,
422 OUT HMONITOR
*phMonitor
)
424 HMONITOR hMon
, hMonNew
;
425 DWORD PosH
, PosV
, Pos
;
426 SIZE DeltaPt
, ScreenOffset
;
432 /* Determine the screen rectangle */
433 hMon
= MonitorFromPoint(pt
,
434 MONITOR_DEFAULTTONULL
);
440 mi
.cbSize
= sizeof(mi
);
441 if (!GetMonitorInfo(hMon
,
445 goto GetPrimaryScreenRect
;
448 /* make left top corner of the screen zero based to
449 make calculations easier */
450 pt
.x
-= mi
.rcMonitor
.left
;
451 pt
.y
-= mi
.rcMonitor
.top
;
453 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
454 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
455 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
456 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
460 GetPrimaryScreenRect
:
463 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
464 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
467 /* Calculate the nearest screen border */
468 if (pt
.x
< rcScreen
.right
/ 2)
475 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
479 if (pt
.y
< rcScreen
.bottom
/ 2)
486 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
490 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
492 /* Fix the screen origin to be relative to the primary monitor again */
493 OffsetRect(&rcScreen
,
497 hMonNew
= ITrayWindowImpl_GetMonitorFromRect(This
,
498 &This
->rcTrayWnd
[Pos
]);
503 /* Recalculate the rectangle, we're dragging to another monitor.
504 We don't need to recalculate the rect on single monitor systems. */
505 szTray
.cx
= This
->rcTrayWnd
[Pos
].right
- This
->rcTrayWnd
[Pos
].left
;
506 szTray
.cy
= This
->rcTrayWnd
[Pos
].bottom
- This
->rcTrayWnd
[Pos
].top
;
508 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
515 pRect
->left
+= This
->AutoHideOffset
.cx
;
516 pRect
->right
+= This
->AutoHideOffset
.cx
;
517 pRect
->top
+= This
->AutoHideOffset
.cy
;
518 pRect
->bottom
+= This
->AutoHideOffset
.cy
;
524 /* The user is dragging the tray window on the same monitor. We don't need
525 to recalculate the rectangle */
526 *pRect
= This
->rcTrayWnd
[Pos
];
529 pRect
->left
+= This
->AutoHideOffset
.cx
;
530 pRect
->right
+= This
->AutoHideOffset
.cx
;
531 pRect
->top
+= This
->AutoHideOffset
.cy
;
532 pRect
->bottom
+= This
->AutoHideOffset
.cy
;
542 ITrayWindowImpl_GetDraggingRectFromRect(IN OUT ITrayWindowImpl
*This
,
544 OUT HMONITOR
*phMonitor
)
548 /* Calculate the center of the rectangle. We call
549 ITrayWindowImpl_GetDraggingRectFromPt to calculate a valid
550 dragging rectangle */
551 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
552 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
554 return ITrayWindowImpl_GetDraggingRectFromPt(This
,
561 ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl
*This
,
562 IN OUT LPWINDOWPOS pwp
)
566 if (This
->IsDragging
)
568 rcTray
.left
= pwp
->x
;
570 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
571 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
574 rcTray
.left
-= This
->AutoHideOffset
.cx
;
575 rcTray
.right
-= This
->AutoHideOffset
.cx
;
576 rcTray
.top
-= This
->AutoHideOffset
.cy
;
577 rcTray
.bottom
-= This
->AutoHideOffset
.cy
;
580 if (!EqualRect(&rcTray
,
581 &This
->rcTrayWnd
[This
->DraggingPosition
]))
583 /* Recalculate the rectangle, the user dragged the tray
584 window to another monitor or the window was somehow else
586 This
->DraggingPosition
= ITrayWindowImpl_GetDraggingRectFromRect(This
,
588 &This
->DraggingMonitor
);
589 //This->rcTrayWnd[This->DraggingPosition] = rcTray;
592 //This->Monitor = ITrayWindowImpl_CalculateValidSize(This,
593 // This->DraggingPosition,
596 This
->Monitor
= This
->DraggingMonitor
;
597 This
->Position
= This
->DraggingPosition
;
598 This
->IsDragging
= FALSE
;
600 This
->rcTrayWnd
[This
->Position
] = rcTray
;
603 else if (GetWindowRect(This
->hWnd
,
606 if (This
->InSizeMove
)
608 if (!(pwp
->flags
& SWP_NOMOVE
))
610 rcTray
.left
= pwp
->x
;
614 if (!(pwp
->flags
& SWP_NOSIZE
))
616 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
617 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
620 This
->Position
= ITrayWindowImpl_GetDraggingRectFromRect(This
,
624 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
631 ITrayWindowImpl_MakeTrayRectWithSize(This
->Position
,
638 rcTray
.left
-= This
->AutoHideOffset
.cx
;
639 rcTray
.right
-= This
->AutoHideOffset
.cx
;
640 rcTray
.top
-= This
->AutoHideOffset
.cy
;
641 rcTray
.bottom
-= This
->AutoHideOffset
.cy
;
643 This
->rcTrayWnd
[This
->Position
] = rcTray
;
647 /* If the user isn't resizing the tray window we need to make sure the
648 new size or position is valid. This is to prevent changes to the window
649 without user interaction. */
650 rcTray
= This
->rcTrayWnd
[This
->Position
];
654 This
->TraySize
.cx
= rcTray
.right
- rcTray
.left
;
655 This
->TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
659 rcTray
.left
+= This
->AutoHideOffset
.cx
;
660 rcTray
.right
+= This
->AutoHideOffset
.cx
;
661 rcTray
.top
+= This
->AutoHideOffset
.cy
;
662 rcTray
.bottom
+= This
->AutoHideOffset
.cy
;
665 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
666 pwp
->x
= rcTray
.left
;
668 pwp
->cx
= This
->TraySize
.cx
;
669 pwp
->cy
= This
->TraySize
.cy
;
674 ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl
*This
,
677 RECT rcClip
, rcWindow
;
680 if (GetWindowRect(This
->hWnd
,
683 /* Disable clipping on systems with only one monitor */
684 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
691 ITrayWindowImpl_GetScreenRect(This
,
695 if (!IntersectRect(&rcClip
,
706 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
711 /* Set the clipping region or make sure the window isn't clipped
712 by disabling it explicitly. */
713 SetWindowRgn(This
->hWnd
,
720 ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl
*This
)
722 RECT rcTray
,rcWorkArea
;
724 /* If monitor has changed then fix the previous monitors work area */
725 if (This
->PreviousMonitor
!= This
->Monitor
)
727 ITrayWindowImpl_GetScreenRect(This
,
728 This
->PreviousMonitor
,
730 SystemParametersInfo(SPI_SETWORKAREA
,
736 rcTray
= This
->rcTrayWnd
[This
->Position
];
738 ITrayWindowImpl_GetScreenRect(This
,
741 This
->PreviousMonitor
= This
->Monitor
;
743 /* If AutoHide is false then change the workarea to exclude the area that
744 the taskbar covers. */
747 switch (This
->Position
)
750 rcWorkArea
.top
= rcTray
.bottom
;
753 rcWorkArea
.left
= rcTray
.right
;
756 rcWorkArea
.right
= rcTray
.left
;
759 rcWorkArea
.bottom
= rcTray
.top
;
764 SystemParametersInfo(SPI_SETWORKAREA
,
771 ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl
*This
)
775 rcTray
= This
->rcTrayWnd
[This
->Position
];
779 rcTray
.left
+= This
->AutoHideOffset
.cx
;
780 rcTray
.right
+= This
->AutoHideOffset
.cx
;
781 rcTray
.top
+= This
->AutoHideOffset
.cy
;
782 rcTray
.bottom
+= This
->AutoHideOffset
.cy
;
785 // TRACE("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
787 /* Move the tray window */
788 SetWindowPos(This
->hWnd
,
792 rcTray
.right
- rcTray
.left
,
793 rcTray
.bottom
- rcTray
.top
,
796 ITrayWindowImpl_ResizeWorkArea(This
);
798 ITrayWindowImpl_ApplyClipping(This
,
802 typedef struct _TW_STUCKRECTS2
810 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
813 ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl
*This
)
818 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
819 DWORD cbSize
= sizeof(sr
);
821 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
822 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
823 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
824 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
826 if (SHGetValue(hkExplorer
,
831 &cbSize
) == ERROR_SUCCESS
&&
832 sr
.cbSize
== sizeof(sr
))
834 This
->AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
835 This
->AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
836 This
->SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
837 This
->HideClock
= (sr
.dwFlags
& 0x8) != 0;
839 /* FIXME: Are there more flags? */
841 if (sr
.Position
> ABE_BOTTOM
)
842 This
->Position
= ABE_BOTTOM
;
844 This
->Position
= sr
.Position
;
846 /* Try to find out which monitor the tray window was located on last.
847 Here we're only interested in the monitor screen that we think
848 is the last one used. We're going to determine on which monitor
849 we really are after calculating the docked position. */
851 ITrayWindowImpl_GetScreenRectFromRect(This
,
853 MONITOR_DEFAULTTONEAREST
);
857 This
->Position
= ABE_BOTTOM
;
858 This
->AlwaysOnTop
= TRUE
;
860 /* Use the minimum size of the taskbar, we'll use the start
861 button as a minimum for now. Make sure we calculate the
862 entire window size, not just the client size. However, we
863 use a thinner border than a standard thick border, so that
864 the start button and bands are not stuck to the screen border. */
865 sr
.Size
.cx
= This
->StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
866 sr
.Size
.cy
= This
->StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
868 /* Use the primary screen by default */
871 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
872 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
873 ITrayWindowImpl_GetScreenRectFromRect(This
,
875 MONITOR_DEFAULTTOPRIMARY
);
878 if (This
->hWnd
!= NULL
)
879 SetWindowPos(This
->hWnd
,
880 This
->AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
885 SWP_NOMOVE
| SWP_NOSIZE
);
887 /* Determine a minimum tray window rectangle. The "client" height is
888 zero here since we cannot determine an optimal minimum width when
889 loaded as a vertical tray window. We just need to make sure the values
890 loaded from the registry are at least. The windows explorer behaves
891 the same way, it allows the user to save a zero width vertical tray
892 window, but not a zero height horizontal tray window. */
893 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
894 WndSize
.cy
= This
->StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
896 if (WndSize
.cx
< sr
.Size
.cx
)
897 WndSize
.cx
= sr
.Size
.cx
;
898 if (WndSize
.cy
< sr
.Size
.cy
)
899 WndSize
.cy
= sr
.Size
.cy
;
901 /* Save the calculated size */
902 This
->TraySize
= WndSize
;
904 /* Calculate all docking rectangles. We need to do this here so they're
905 initialized and dragging the tray window to another position gives
911 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
915 &This
->rcTrayWnd
[Pos
]);
916 // TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom);
919 /* Determine which monitor we are on. It shouldn't matter which docked
920 position rectangle we use */
921 This
->Monitor
= ITrayWindowImpl_GetMonitorFromRect(This
,
922 &This
->rcTrayWnd
[ABE_LEFT
]);
926 ITrayWindowImpl_TrackMenu(IN OUT ITrayWindowImpl
*This
,
928 IN POINT
*ppt OPTIONAL
,
929 IN HWND hwndExclude OPTIONAL
,
931 IN BOOL IsContextMenu
)
933 TPMPARAMS tmp
, *ptmp
= NULL
;
938 if (hwndExclude
!= NULL
)
940 /* Get the client rectangle and map it to screen coordinates */
941 if (GetClientRect(hwndExclude
,
943 MapWindowPoints(hwndExclude
,
945 (LPPOINT
)&tmp
.rcExclude
,
955 GetClientRect(This
->hWnd
,
957 MapWindowPoints(This
->hWnd
,
959 (LPPOINT
)&tmp
.rcExclude
,
967 /* NOTE: TrackPopupMenuEx will eventually align the track position
968 for us, no need to take care of it here as long as the
969 coordinates are somewhere within the exclusion rectangle */
970 pt
.x
= ptmp
->rcExclude
.left
;
971 pt
.y
= ptmp
->rcExclude
.top
;
979 tmp
.cbSize
= sizeof(tmp
);
981 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
982 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
984 fuFlags
|= TPM_RIGHTBUTTON
;
986 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
988 cmdId
= TrackPopupMenuEx(hMenu
,
999 ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl
*This
,
1000 IN
const TRAYWINDOW_CTXMENU
*pMenu
,
1001 IN POINT
*ppt OPTIONAL
,
1002 IN HWND hwndExclude OPTIONAL
,
1004 IN PVOID Context OPTIONAL
)
1008 PVOID pcmContext
= NULL
;
1010 hPopup
= pMenu
->CreateCtxMenu(This
->hWnd
,
1015 cmdId
= ITrayWindowImpl_TrackMenu(This
,
1022 pMenu
->CtxMenuCommand(This
->hWnd
,
1032 ITrayWindowImpl_Free(ITrayWindowImpl
*This
)
1034 HeapFree(hProcessHeap
,
1040 static ULONG STDMETHODCALLTYPE
1041 ITrayWindowImpl_Release(IN OUT ITrayWindow
*iface
)
1043 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1046 Ret
= InterlockedDecrement(&This
->Ref
);
1048 ITrayWindowImpl_Free(This
);
1054 ITrayWindowImpl_Destroy(ITrayWindowImpl
*This
)
1056 (void)InterlockedExchangePointer((PVOID
*)&This
->hWnd
,
1060 if (This
->hdpaShellServices
!= NULL
)
1062 ShutdownShellServices(This
->hdpaShellServices
);
1063 This
->hdpaShellServices
= NULL
;
1066 if (This
->himlStartBtn
!= NULL
)
1068 ImageList_Destroy(This
->himlStartBtn
);
1069 This
->himlStartBtn
= NULL
;
1072 if (This
->hCaptionFont
!= NULL
)
1074 DeleteObject(This
->hCaptionFont
);
1075 This
->hCaptionFont
= NULL
;
1078 if (This
->hStartBtnFont
!= NULL
)
1080 DeleteObject(This
->hStartBtnFont
);
1081 This
->hStartBtnFont
= NULL
;
1084 if (This
->hFont
!= NULL
)
1086 DeleteObject(This
->hFont
);
1090 if (This
->StartMenuPopup
!= NULL
)
1092 IMenuPopup_Release(This
->StartMenuPopup
);
1093 This
->StartMenuPopup
= NULL
;
1096 if (This
->hbmStartMenu
!= NULL
)
1098 DeleteObject(This
->hbmStartMenu
);
1099 This
->hbmStartMenu
= NULL
;
1102 if (This
->StartMenuBand
!= NULL
)
1104 IMenuBand_Release(This
->StartMenuBand
);
1105 This
->StartMenuBand
= NULL
;
1108 if (This
->TrayBandSite
!= NULL
)
1110 /* FIXME: Unload bands */
1111 ITrayBandSite_Release(This
->TrayBandSite
);
1112 This
->TrayBandSite
= NULL
;
1115 if (This
->TaskbarTheme
)
1117 CloseThemeData(This
->TaskbarTheme
);
1118 This
->TaskbarTheme
= NULL
;
1121 ITrayWindowImpl_Release(ITrayWindow_from_impl(This
));
1123 if (InterlockedDecrement(&TrayWndCount
) == 0)
1127 static ULONG STDMETHODCALLTYPE
1128 ITrayWindowImpl_AddRef(IN OUT ITrayWindow
*iface
)
1130 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1132 return InterlockedIncrement(&This
->Ref
);
1137 ITrayWindowImpl_NCCreate(IN OUT ITrayWindowImpl
*This
)
1139 ITrayWindowImpl_AddRef(ITrayWindow_from_impl(This
));
1145 ITrayWindowImpl_UpdateStartButton(IN OUT ITrayWindowImpl
*This
,
1146 IN HBITMAP hbmStart OPTIONAL
)
1148 SIZE Size
= { 0, 0 };
1150 if (This
->himlStartBtn
== NULL
||
1151 !SendMessage(This
->hwndStart
,
1156 Size
.cx
= GetSystemMetrics(SM_CXEDGE
);
1157 Size
.cy
= GetSystemMetrics(SM_CYEDGE
);
1159 if (hbmStart
== NULL
)
1161 hbmStart
= (HBITMAP
)SendMessage(This
->hwndStart
,
1167 if (hbmStart
!= NULL
)
1171 if (GetObject(hbmStart
,
1175 Size
.cx
+= bmp
.bmWidth
;
1176 Size
.cy
+= max(bmp
.bmHeight
,
1177 GetSystemMetrics(SM_CYCAPTION
));
1181 /* Huh?! Shouldn't happen... */
1188 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
1189 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
1193 /* Save the size of the start button */
1194 This
->StartBtnSize
= Size
;
1198 ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl
*This
,
1199 IN PRECT prcClient OPTIONAL
)
1202 SIZE TraySize
, StartSize
;
1203 POINT ptTrayNotify
= { 0, 0 };
1207 ITrayWindowImpl_UpdateStartButton(This
, NULL
);
1208 if (prcClient
!= NULL
)
1210 rcClient
= *prcClient
;
1214 if (!GetClientRect(This
->hWnd
,
1221 Horizontal
= ITrayWindowImpl_IsPosHorizontal(This
);
1223 /* We're about to resize/move the start button, the rebar control and
1224 the tray notification control */
1225 dwp
= BeginDeferWindowPos(3);
1229 /* Limit the Start button width to the client width, if neccessary */
1230 StartSize
= This
->StartBtnSize
;
1231 if (StartSize
.cx
> rcClient
.right
)
1232 StartSize
.cx
= rcClient
.right
;
1234 if (This
->hwndStart
!= NULL
)
1236 /* Resize and reposition the button */
1237 dwp
= DeferWindowPos(dwp
,
1244 SWP_NOZORDER
| SWP_NOACTIVATE
);
1249 /* Determine the size that the tray notification window needs */
1253 TraySize
.cy
= rcClient
.bottom
;
1257 TraySize
.cx
= rcClient
.right
;
1261 if (This
->hwndTrayNotify
!= NULL
&&
1262 SendMessage(This
->hwndTrayNotify
,
1263 TNWM_GETMINIMUMSIZE
,
1267 /* Move the tray notification window to the desired location */
1269 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1271 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1273 dwp
= DeferWindowPos(dwp
,
1274 This
->hwndTrayNotify
,
1280 SWP_NOZORDER
| SWP_NOACTIVATE
);
1285 /* Resize/Move the rebar control */
1286 if (This
->hwndRebar
!= NULL
)
1288 POINT ptRebar
= { 0, 0 };
1291 SetWindowStyle(This
->hwndRebar
,
1293 Horizontal
? 0 : CCS_VERT
);
1297 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1298 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1299 szRebar
.cy
= rcClient
.bottom
;
1303 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1304 szRebar
.cx
= rcClient
.right
;
1305 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1308 dwp
= DeferWindowPos(dwp
,
1315 SWP_NOZORDER
| SWP_NOACTIVATE
);
1319 EndDeferWindowPos(dwp
);
1321 if (This
->hwndTaskSwitch
!= NULL
)
1323 /* Update the task switch window configuration */
1324 SendMessage(This
->hwndTaskSwitch
,
1325 TSWM_UPDATETASKBARPOS
,
1332 ITrayWindowImpl_CreateStartBtnImageList(IN OUT ITrayWindowImpl
*This
)
1337 if (This
->himlStartBtn
!= NULL
)
1340 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
1341 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
1343 /* Load the start button icon and create a image list for it */
1344 hIconStart
= LoadImage(hExplorerInstance
,
1345 MAKEINTRESOURCE(IDI_START
),
1349 LR_SHARED
| LR_DEFAULTCOLOR
);
1351 if (hIconStart
!= NULL
)
1353 This
->himlStartBtn
= ImageList_Create(IconSize
.cx
,
1355 ILC_COLOR32
| ILC_MASK
,
1358 if (This
->himlStartBtn
!= NULL
)
1360 if (ImageList_AddIcon(This
->himlStartBtn
,
1366 /* Failed to add the icon! */
1367 ImageList_Destroy(This
->himlStartBtn
);
1368 This
->himlStartBtn
= NULL
;
1376 ITrayWindowImpl_CreateStartButtonBitmap(IN OUT ITrayWindowImpl
*This
)
1378 TCHAR szStartCaption
[32];
1381 HDC hDCScreen
= NULL
;
1382 SIZE Size
, SmallIcon
;
1383 HBITMAP hbmpOld
, hbmp
= NULL
;
1384 HBITMAP hBitmap
= NULL
;
1390 /* NOTE: This is the backwards compatibility code that is used if the
1391 Common Controls Version 6.0 are not available! */
1393 if (!LoadString(hExplorerInstance
,
1396 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1401 /* Load the start button icon */
1402 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
1403 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
1404 hIconStart
= LoadImage(hExplorerInstance
,
1405 MAKEINTRESOURCE(IDI_START
),
1409 LR_SHARED
| LR_DEFAULTCOLOR
);
1411 hDCScreen
= GetDC(NULL
);
1412 if (hDCScreen
== NULL
)
1415 hDC
= CreateCompatibleDC(hDCScreen
);
1419 hFontOld
= SelectObject(hDC
,
1420 This
->hStartBtnFont
);
1422 Ret
= GetTextExtentPoint32(hDC
,
1424 _tcslen(szStartCaption
),
1432 /* Make sure the height is at least the size of a caption icon. */
1433 if (hIconStart
!= NULL
)
1434 Size
.cx
+= SmallIcon
.cx
+ 4;
1435 Size
.cy
= max(Size
.cy
,
1438 /* Create the bitmap */
1439 hbmp
= CreateCompatibleBitmap(hDCScreen
,
1445 /* Caluclate the button rect */
1448 rcButton
.right
= Size
.cx
;
1449 rcButton
.bottom
= Size
.cy
;
1451 /* Draw the button */
1452 hbmpOld
= SelectObject(hDC
,
1455 Flags
= DC_TEXT
| DC_INBUTTON
;
1456 if (hIconStart
!= NULL
)
1459 if (DrawCapTemp
!= NULL
)
1461 Ret
= DrawCapTemp(NULL
,
1464 This
->hStartBtnFont
,
1476 /* We successfully created the bitmap! */
1481 if (hDCScreen
!= NULL
)
1497 ITrayWindowImpl_UpdateTheme(IN OUT ITrayWindowImpl
*This
)
1499 if (This
->TaskbarTheme
)
1500 CloseThemeData(This
->TaskbarTheme
);
1502 if (IsThemeActive())
1503 This
->TaskbarTheme
= OpenThemeData(This
->hWnd
, L
"Taskbar");
1505 This
->TaskbarTheme
= 0;
1509 ITrayWindowImpl_Create(IN OUT ITrayWindowImpl
*This
)
1511 TCHAR szStartCaption
[32];
1513 SetWindowTheme(This
->hWnd
, L
"TaskBar", NULL
);
1514 ITrayWindowImpl_UpdateTheme(This
);
1516 InterlockedIncrement(&TrayWndCount
);
1518 if (!LoadString(hExplorerInstance
,
1521 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1523 szStartCaption
[0] = TEXT('\0');
1526 if (This
->hStartBtnFont
== NULL
|| This
->hCaptionFont
== NULL
)
1528 NONCLIENTMETRICS ncm
;
1530 /* Get the system fonts, we use the caption font,
1531 always bold, though. */
1532 ncm
.cbSize
= sizeof(ncm
);
1533 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1538 if (This
->hCaptionFont
== NULL
)
1540 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1541 This
->hCaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1544 if (This
->hStartBtnFont
== NULL
)
1546 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
1547 This
->hStartBtnFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1552 /* Create the Start button */
1553 This
->hwndStart
= CreateWindowEx(0,
1556 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1557 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1563 (HMENU
)IDC_STARTBTN
,
1566 if (This
->hwndStart
)
1568 SetWindowTheme(This
->hwndStart
, L
"Start", NULL
);
1569 SendMessage(This
->hwndStart
,
1571 (WPARAM
)This
->hStartBtnFont
,
1574 if (ITrayWindowImpl_CreateStartBtnImageList(This
))
1576 BUTTON_IMAGELIST bil
;
1578 /* Try to set the start button image. This requires the Common
1579 Controls 6.0 to be present (XP and later) */
1580 bil
.himl
= This
->himlStartBtn
;
1581 bil
.margin
.left
= bil
.margin
.right
= 1;
1582 bil
.margin
.top
= bil
.margin
.bottom
= 1;
1583 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
1585 if (!SendMessage(This
->hwndStart
,
1590 /* Fall back to the deprecated method on older systems that don't
1591 support Common Controls 6.0 */
1592 ImageList_Destroy(This
->himlStartBtn
);
1593 This
->himlStartBtn
= NULL
;
1595 goto SetStartBtnImage
;
1598 /* We're using the image list, remove the BS_BITMAP style and
1599 don't center it horizontally */
1600 SetWindowStyle(This
->hwndStart
,
1601 BS_BITMAP
| BS_RIGHT
,
1604 ITrayWindowImpl_UpdateStartButton(This
,
1609 HBITMAP hbmStart
, hbmOld
;
1612 hbmStart
= ITrayWindowImpl_CreateStartButtonBitmap(This
);
1613 if (hbmStart
!= NULL
)
1615 ITrayWindowImpl_UpdateStartButton(This
,
1618 hbmOld
= (HBITMAP
)SendMessage(This
->hwndStart
,
1624 DeleteObject(hbmOld
);
1629 /* Load the saved tray window settings */
1630 ITrayWindowImpl_RegLoadSettings(This
);
1632 /* Create and initialize the start menu */
1633 This
->hbmStartMenu
= LoadBitmap(hExplorerInstance
,
1634 MAKEINTRESOURCE(IDB_STARTMENU
));
1635 This
->StartMenuPopup
= CreateStartMenu(ITrayWindow_from_impl(This
),
1636 &This
->StartMenuBand
,
1640 /* Load the tray band site */
1641 if (This
->TrayBandSite
!= NULL
)
1643 ITrayBandSite_Release(This
->TrayBandSite
);
1646 This
->TrayBandSite
= CreateTrayBandSite(ITrayWindow_from_impl(This
),
1648 &This
->hwndTaskSwitch
);
1649 SetWindowTheme(This
->hwndRebar
, L
"TaskBar", NULL
);
1651 /* Create the tray notification window */
1652 This
->hwndTrayNotify
= CreateTrayNotifyWnd(ITrayWindow_from_impl(This
),
1655 if (ITrayWindowImpl_UpdateNonClientMetrics(This
))
1657 ITrayWindowImpl_SetWindowsFont(This
);
1660 /* Move the tray window to the right position and resize it if neccessary */
1661 ITrayWindowImpl_CheckTrayWndPosition(This
);
1663 /* Align all controls on the tray window */
1664 ITrayWindowImpl_AlignControls(This
,
1667 InitShellServices(&(This
->hdpaShellServices
));
1671 This
->AutoHideState
= AUTOHIDE_HIDING
;
1672 SetTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1676 static HRESULT STDMETHODCALLTYPE
1677 ITrayWindowImpl_QueryInterface(IN OUT ITrayWindow
*iface
,
1681 ITrayWindowImpl
*This
;
1686 This
= impl_from_ITrayWindow(iface
);
1688 if (IsEqualIID(riid
,
1691 *ppvObj
= IUnknown_from_impl(This
);
1693 else if (IsEqualIID(riid
,
1694 &IID_IShellDesktopTray
))
1696 *ppvObj
= IShellDesktopTray_from_impl(This
);
1701 return E_NOINTERFACE
;
1704 ITrayWindowImpl_AddRef(iface
);
1708 static ITrayWindowImpl
*
1709 ITrayWindowImpl_Construct(VOID
)
1711 ITrayWindowImpl
*This
;
1713 This
= HeapAlloc(hProcessHeap
,
1719 This
->lpVtbl
= &ITrayWindowImpl_Vtbl
;
1720 This
->lpVtblShellDesktopTray
= &IShellDesktopTrayImpl_Vtbl
;
1722 This
->Position
= (DWORD
)-1;
1727 static HRESULT STDMETHODCALLTYPE
1728 ITrayWindowImpl_Open(IN OUT ITrayWindow
*iface
)
1730 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1735 /* Check if there's already a window created and try to show it.
1736 If it was somehow destroyed just create a new tray window. */
1737 if (This
->hWnd
!= NULL
)
1739 if (IsWindow(This
->hWnd
))
1741 if (!IsWindowVisible(This
->hWnd
))
1743 ITrayWindowImpl_CheckTrayWndPosition(This
);
1745 ShowWindow(This
->hWnd
,
1750 goto TryCreateTrayWnd
;
1757 dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1758 if (This
->AlwaysOnTop
)
1759 dwExStyle
|= WS_EX_TOPMOST
;
1761 if (This
->Position
!= (DWORD
)-1)
1762 rcWnd
= This
->rcTrayWnd
[This
->Position
];
1769 hWnd
= CreateWindowEx(dwExStyle
,
1772 WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1773 WS_BORDER
| WS_THICKFRAME
,
1776 rcWnd
.right
- rcWnd
.left
,
1777 rcWnd
.bottom
- rcWnd
.top
,
1789 static HRESULT STDMETHODCALLTYPE
1790 ITrayWindowImpl_Close(IN OUT ITrayWindow
*iface
)
1792 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1794 if (This
->hWnd
!= NULL
)
1796 SendMessage(This
->hWnd
,
1805 static HWND STDMETHODCALLTYPE
1806 ITrayWindowImpl_GetHWND(IN OUT ITrayWindow
*iface
)
1808 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1813 static BOOL STDMETHODCALLTYPE
1814 ITrayWindowImpl_IsSpecialHWND(IN OUT ITrayWindow
*iface
,
1817 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1819 return (hWnd
== This
->hWnd
||
1820 (This
->hWndDesktop
!= NULL
&& hWnd
== This
->hWndDesktop
));
1823 static BOOL STDMETHODCALLTYPE
1824 ITrayWindowImpl_IsHorizontal(IN OUT ITrayWindow
*iface
)
1826 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1827 return ITrayWindowImpl_IsPosHorizontal(This
);
1830 static HFONT STDMETHODCALLTYPE
1831 ITrayWIndowImpl_GetCaptionFonts(IN OUT ITrayWindow
*iface
,
1832 OUT HFONT
*phBoldCaption OPTIONAL
)
1834 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1836 if (phBoldCaption
!= NULL
)
1837 *phBoldCaption
= This
->hStartBtnFont
;
1839 return This
->hCaptionFont
;
1843 TrayPropertiesThread(IN OUT PVOID pParam
)
1845 ITrayWindowImpl
*This
= pParam
;
1849 GetWindowRect(This
->hwndStart
, &posRect
);
1850 hwnd
= CreateWindowEx(0,
1853 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1856 posRect
.right
- posRect
.left
,
1857 posRect
.bottom
- posRect
.top
,
1863 This
->hwndTrayPropertiesOwner
= hwnd
;
1865 DisplayTrayProperties(hwnd
);
1867 This
->hwndTrayPropertiesOwner
= NULL
;
1868 DestroyWindow(hwnd
);
1873 static HWND STDMETHODCALLTYPE
1874 ITrayWindowImpl_DisplayProperties(IN OUT ITrayWindow
*iface
)
1876 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1879 if (This
->hwndTrayPropertiesOwner
)
1881 hTrayProp
= GetLastActivePopup(This
->hwndTrayPropertiesOwner
);
1882 if (hTrayProp
!= NULL
&&
1883 hTrayProp
!= This
->hwndTrayPropertiesOwner
)
1885 SetForegroundWindow(hTrayProp
);
1890 CloseHandle(CreateThread(NULL
, 0, TrayPropertiesThread
, This
, 0, NULL
));
1895 OpenCommonStartMenuDirectory(IN HWND hWndOwner
,
1896 IN LPCTSTR lpOperation
)
1898 TCHAR szDir
[MAX_PATH
];
1900 if (SHGetSpecialFolderPath(hWndOwner
,
1902 CSIDL_COMMON_STARTMENU
,
1905 ShellExecute(hWndOwner
,
1915 OpenTaskManager(IN HWND hWndOwner
)
1917 ShellExecute(hWndOwner
,
1919 TEXT("taskmgr.exe"),
1925 static BOOL STDMETHODCALLTYPE
1926 ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow
*iface
,
1929 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1930 BOOL bHandled
= TRUE
;
1934 case ID_SHELL_CMD_PROPERTIES
:
1935 ITrayWindow_DisplayProperties(iface
);
1938 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1939 OpenCommonStartMenuDirectory(This
->hWnd
,
1943 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1944 OpenCommonStartMenuDirectory(This
->hWnd
,
1948 case ID_LOCKTASKBAR
:
1949 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1951 ITrayWindow_Lock(iface
,
1956 case ID_SHELL_CMD_OPEN_TASKMGR
:
1957 OpenTaskManager(This
->hWnd
);
1960 case ID_SHELL_CMD_UNDO_ACTION
:
1963 case ID_SHELL_CMD_SHOW_DESKTOP
:
1966 case ID_SHELL_CMD_TILE_WND_H
:
1967 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1970 case ID_SHELL_CMD_TILE_WND_V
:
1971 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1974 case ID_SHELL_CMD_CASCADE_WND
:
1975 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1978 case ID_SHELL_CMD_CUST_NOTIF
:
1981 case ID_SHELL_CMD_ADJUST_DAT
:
1982 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
1986 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1994 static BOOL STDMETHODCALLTYPE
1995 ITrayWindowImpl_Lock(IN OUT ITrayWindow
*iface
,
1999 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
2001 bPrevLock
= This
->Locked
;
2002 if (This
->Locked
!= bLock
)
2004 This
->Locked
= bLock
;
2006 if (This
->TrayBandSite
!= NULL
)
2008 if (!SUCCEEDED(ITrayBandSite_Lock(This
->TrayBandSite
,
2012 This
->Locked
= bPrevLock
;
2020 static const ITrayWindowVtbl ITrayWindowImpl_Vtbl
=
2023 ITrayWindowImpl_QueryInterface
,
2024 ITrayWindowImpl_AddRef
,
2025 ITrayWindowImpl_Release
,
2027 ITrayWindowImpl_Open
,
2028 ITrayWindowImpl_Close
,
2029 ITrayWindowImpl_GetHWND
,
2030 ITrayWindowImpl_IsSpecialHWND
,
2031 ITrayWindowImpl_IsHorizontal
,
2032 ITrayWIndowImpl_GetCaptionFonts
,
2033 ITrayWindowImpl_DisplayProperties
,
2034 ITrayWindowImpl_ExecContextMenuCmd
,
2035 ITrayWindowImpl_Lock
2039 ITrayWindowImpl_DrawBackground(IN ITrayWindowImpl
*This
,
2045 GetClientRect(This
->hWnd
, &rect
);
2046 switch (This
->Position
)
2049 backoundPart
= TBP_BACKGROUNDLEFT
;
2052 backoundPart
= TBP_BACKGROUNDTOP
;
2055 backoundPart
= TBP_BACKGROUNDRIGHT
;
2059 backoundPart
= TBP_BACKGROUNDBOTTOM
;
2062 DrawThemeBackground(This
->TaskbarTheme
, dc
, backoundPart
, 0, &rect
, 0);
2067 ITrayWindowImpl_DrawSizer(IN ITrayWindowImpl
*This
,
2074 GetWindowRect(This
->hWnd
, &rect
);
2075 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
2077 hdc
= GetDCEx(This
->hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
2079 switch (This
->Position
)
2082 backoundPart
= TBP_SIZINGBARLEFT
;
2083 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
2086 backoundPart
= TBP_SIZINGBARTOP
;
2087 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
2090 backoundPart
= TBP_SIZINGBARRIGHT
;
2091 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
2095 backoundPart
= TBP_SIZINGBARBOTTOM
;
2096 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
2100 DrawThemeBackground(This
->TaskbarTheme
, hdc
, backoundPart
, 0, &rect
, 0);
2102 ReleaseDC(This
->hWnd
, hdc
);
2107 RunFileDlgThread(IN OUT PVOID pParam
)
2109 ITrayWindowImpl
*This
= pParam
;
2111 RUNFILEDLG RunFileDlg
;
2115 GetWindowRect(This
->hwndStart
,&posRect
);
2117 hwnd
= CreateWindowEx(0,
2120 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
2123 posRect
.right
- posRect
.left
,
2124 posRect
.bottom
- posRect
.top
,
2130 This
->hwndRunFileDlgOwner
= hwnd
;
2132 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2133 RunFileDlg
= (RUNFILEDLG
)GetProcAddress(hShell32
, (LPCSTR
)61);
2135 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
2137 This
->hwndRunFileDlgOwner
= NULL
;
2138 DestroyWindow(hwnd
);
2144 ITrayWindowImpl_DisplayRunFileDlg(IN ITrayWindowImpl
*This
)
2147 if (This
->hwndRunFileDlgOwner
)
2149 hRunDlg
= GetLastActivePopup(This
->hwndRunFileDlgOwner
);
2150 if (hRunDlg
!= NULL
&&
2151 hRunDlg
!= This
->hwndRunFileDlgOwner
)
2153 SetForegroundWindow(hRunDlg
);
2158 CloseHandle(CreateThread(NULL
, 0, RunFileDlgThread
, This
, 0, NULL
));
2161 static void PopupStartMenu(IN ITrayWindowImpl
*This
)
2163 if (This
->StartMenuPopup
!= NULL
)
2169 if (GetWindowRect(This
->hwndStart
,
2170 (RECT
*) &rcExclude
))
2172 switch (This
->Position
)
2175 pt
.x
= rcExclude
.left
;
2176 pt
.y
= rcExclude
.top
;
2177 dwFlags
|= MPPF_BOTTOM
;
2181 pt
.x
= rcExclude
.left
;
2182 pt
.y
= rcExclude
.bottom
;
2183 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
2186 pt
.x
= rcExclude
.right
;
2187 pt
.y
= rcExclude
.bottom
;
2188 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
2192 IMenuPopup_Popup(This
->StartMenuPopup
,
2197 SendMessageW(This
->hwndStart
, BM_SETSTATE
, TRUE
, 0);
2203 ProcessMouseTracking(ITrayWindowImpl
* This
)
2208 UINT state
= This
->AutoHideState
;
2211 GetWindowRect(This
->hWnd
, &rcCurrent
);
2212 over
= PtInRect(&rcCurrent
, pt
);
2214 if (SendMessage(This
->hwndStart
, BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2221 if (state
== AUTOHIDE_HIDING
)
2223 TRACE("AutoHide cancelling hide.\n");
2224 This
->AutoHideState
= AUTOHIDE_SHOWING
;
2225 SetTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2227 else if (state
== AUTOHIDE_HIDDEN
)
2229 TRACE("AutoHide starting show.\n");
2230 This
->AutoHideState
= AUTOHIDE_SHOWING
;
2231 SetTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2236 if (state
== AUTOHIDE_SHOWING
)
2238 TRACE("AutoHide cancelling show.\n");
2239 This
->AutoHideState
= AUTOHIDE_HIDING
;
2240 SetTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2242 else if (state
== AUTOHIDE_SHOWN
)
2244 TRACE("AutoHide starting hide.\n");
2245 This
->AutoHideState
= AUTOHIDE_HIDING
;
2246 SetTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2249 KillTimer(This
->hWnd
, TIMER_ID_MOUSETRACK
);
2254 ProcessAutoHide(ITrayWindowImpl
* This
)
2256 RECT rc
= This
->rcTrayWnd
[This
->Position
];
2257 INT w
= This
->TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2258 INT h
= This
->TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2260 TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", This
->AutoHideState
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, w
, h
);
2262 switch (This
->AutoHideState
)
2264 case AUTOHIDE_HIDING
:
2265 switch (This
->Position
)
2268 This
->AutoHideOffset
.cy
= 0;
2269 This
->AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2270 if (This
->AutoHideOffset
.cx
< -w
)
2271 This
->AutoHideOffset
.cx
= -w
;
2274 This
->AutoHideOffset
.cx
= 0;
2275 This
->AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2276 if (This
->AutoHideOffset
.cy
< -h
)
2277 This
->AutoHideOffset
.cy
= -h
;
2280 This
->AutoHideOffset
.cy
= 0;
2281 This
->AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2282 if (This
->AutoHideOffset
.cx
> w
)
2283 This
->AutoHideOffset
.cx
= w
;
2286 This
->AutoHideOffset
.cx
= 0;
2287 This
->AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2288 if (This
->AutoHideOffset
.cy
> h
)
2289 This
->AutoHideOffset
.cy
= h
;
2293 if (This
->AutoHideOffset
.cx
!= w
&& This
->AutoHideOffset
.cy
!= h
)
2295 SetTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2300 case AUTOHIDE_HIDDEN
:
2302 switch (This
->Position
)
2305 This
->AutoHideOffset
.cx
= -w
;
2306 This
->AutoHideOffset
.cy
= 0;
2309 This
->AutoHideOffset
.cx
= 0;
2310 This
->AutoHideOffset
.cy
= -h
;
2313 This
->AutoHideOffset
.cx
= w
;
2314 This
->AutoHideOffset
.cy
= 0;
2317 This
->AutoHideOffset
.cx
= 0;
2318 This
->AutoHideOffset
.cy
= h
;
2322 KillTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
);
2323 This
->AutoHideState
= AUTOHIDE_HIDDEN
;
2326 case AUTOHIDE_SHOWING
:
2327 if (This
->AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2329 This
->AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2331 else if (This
->AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2333 This
->AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2337 This
->AutoHideOffset
.cx
= 0;
2340 if (This
->AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2342 This
->AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2344 else if (This
->AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2346 This
->AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2350 This
->AutoHideOffset
.cy
= 0;
2353 if (This
->AutoHideOffset
.cx
!= 0 || This
->AutoHideOffset
.cy
!= 0)
2355 SetTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2360 case AUTOHIDE_SHOWN
:
2362 KillTimer(This
->hWnd
, TIMER_ID_AUTOHIDE
);
2363 This
->AutoHideState
= AUTOHIDE_SHOWN
;
2367 rc
.left
+= This
->AutoHideOffset
.cx
;
2368 rc
.right
+= This
->AutoHideOffset
.cx
;
2369 rc
.top
+= This
->AutoHideOffset
.cy
;
2370 rc
.bottom
+= This
->AutoHideOffset
.cy
;
2372 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, This
->AutoHideState
);
2373 SetWindowPos(This
->hWnd
, NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2376 static LRESULT CALLBACK
2377 TrayWndProc(IN HWND hwnd
,
2382 ITrayWindowImpl
*This
= NULL
;
2383 LRESULT Ret
= FALSE
;
2385 if (uMsg
!= WM_NCCREATE
)
2387 This
= (ITrayWindowImpl
*)GetWindowLongPtr(hwnd
,
2391 if (This
!= NULL
|| uMsg
== WM_NCCREATE
)
2393 if (This
!= NULL
&& This
->StartMenuBand
!= NULL
)
2400 Msg
.wParam
= wParam
;
2401 Msg
.lParam
= lParam
;
2403 if (IMenuBand_TranslateMenuMessage(This
->StartMenuBand
,
2410 wParam
= Msg
.wParam
;
2411 lParam
= Msg
.lParam
;
2416 case WM_DISPLAYCHANGE
:
2418 /* Load the saved tray window settings */
2419 ITrayWindowImpl_RegLoadSettings(This
);
2421 /* Move the tray window to the right position and resize it if neccessary */
2422 ITrayWindowImpl_CheckTrayWndPosition(This
);
2424 /* Align all controls on the tray window */
2425 ITrayWindowImpl_AlignControls(This
, NULL
);
2431 if (This
->hwndTrayNotify
)
2433 TrayNotify_NotifyMsg(This
->hwndTrayNotify
,
2439 case WM_THEMECHANGED
:
2440 ITrayWindowImpl_UpdateTheme(This
);
2443 if (!This
->TaskbarTheme
)
2445 return ITrayWindowImpl_DrawSizer(This
,
2448 if (!This
->TaskbarTheme
)
2450 return ITrayWindowImpl_DrawBackground(This
,
2452 case WM_CTLCOLORBTN
:
2453 SetBkMode((HDC
)wParam
, TRANSPARENT
);
2454 return (LRESULT
)GetStockObject(HOLLOW_BRUSH
);
2462 /* The user may not be able to resize the tray window.
2463 Pretend like the window is not sizeable when the user
2464 clicks on the border. */
2468 SetLastError(ERROR_SUCCESS
);
2469 if (GetClientRect(hwnd
,
2471 (MapWindowPoints(hwnd
,
2474 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2476 pt
.x
= (SHORT
)LOWORD(lParam
);
2477 pt
.y
= (SHORT
)HIWORD(lParam
);
2479 if (PtInRect(&rcClient
,
2482 /* The user is trying to drag the tray window */
2486 /* Depending on the position of the tray window, allow only
2487 changing the border next to the monitor working area */
2488 switch (This
->Position
)
2491 if (pt
.y
> rcClient
.bottom
)
2495 if (pt
.x
> rcClient
.right
)
2499 if (pt
.x
< rcClient
.left
)
2504 if (pt
.y
< rcClient
.top
)
2514 PRECT pRect
= (PRECT
)lParam
;
2516 /* We need to ensure that an application can not accidently
2517 move the tray window (using SetWindowPos). However, we still
2518 need to be able to move the window in case the user wants to
2519 drag the tray window to another position or in case the user
2520 wants to resize the tray window. */
2521 if (!This
->Locked
&& GetCursorPos(&ptCursor
))
2523 This
->IsDragging
= TRUE
;
2524 This
->DraggingPosition
= ITrayWindowImpl_GetDraggingRectFromPt(This
,
2527 &This
->DraggingMonitor
);
2531 *pRect
= This
->rcTrayWnd
[This
->Position
];
2535 pRect
->left
+= This
->AutoHideOffset
.cx
;
2536 pRect
->right
+= This
->AutoHideOffset
.cx
;
2537 pRect
->top
+= This
->AutoHideOffset
.cy
;
2538 pRect
->bottom
+= This
->AutoHideOffset
.cy
;
2546 PRECT pRect
= (PRECT
)lParam
;
2550 ITrayWindowImpl_CalculateValidSize(This
,
2556 *pRect
= This
->rcTrayWnd
[This
->Position
];
2560 pRect
->left
+= This
->AutoHideOffset
.cx
;
2561 pRect
->right
+= This
->AutoHideOffset
.cx
;
2562 pRect
->top
+= This
->AutoHideOffset
.cy
;
2563 pRect
->bottom
+= This
->AutoHideOffset
.cy
;
2569 case WM_WINDOWPOSCHANGING
:
2571 ITrayWindowImpl_ChangingWinPos(This
,
2572 (LPWINDOWPOS
)lParam
);
2579 InvalidateRect(This
->hWnd
, NULL
, TRUE
);
2580 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2582 ITrayWindowImpl_ResizeWorkArea(This
);
2583 /* Clip the tray window on multi monitor systems so the edges can't
2584 overlap into another monitor */
2585 ITrayWindowImpl_ApplyClipping(This
,
2588 if (!GetClientRect(This
->hWnd
,
2596 rcClient
.left
= rcClient
.top
= 0;
2597 rcClient
.right
= LOWORD(lParam
);
2598 rcClient
.bottom
= HIWORD(lParam
);
2601 ITrayWindowImpl_AlignControls(This
,
2606 case WM_ENTERSIZEMOVE
:
2607 This
->InSizeMove
= TRUE
;
2608 This
->IsDragging
= FALSE
;
2611 /* Remove the clipping on multi monitor systems while dragging around */
2612 ITrayWindowImpl_ApplyClipping(This
,
2617 case WM_EXITSIZEMOVE
:
2618 This
->InSizeMove
= FALSE
;
2621 /* Apply clipping */
2622 PostMessage(This
->hWnd
,
2634 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2635 The tray window needs to handle this specially, since it normally doesn't have
2638 static const UINT uidDisableItem
[] = {
2649 /* temporarily enable the system menu */
2650 SetWindowStyle(hwnd
,
2654 hSysMenu
= GetSystemMenu(hwnd
,
2656 if (hSysMenu
!= NULL
)
2658 /* Disable all items that are not relevant */
2659 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2661 EnableMenuItem(hSysMenu
,
2663 MF_BYCOMMAND
| MF_GRAYED
);
2666 EnableMenuItem(hSysMenu
,
2669 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2671 /* Display the system menu */
2672 uId
= ITrayWindowImpl_TrackMenu(This
,
2676 This
->Position
!= ABE_TOP
,
2680 SendMessage(This
->hWnd
,
2687 /* revert the system menu window style */
2688 SetWindowStyle(hwnd
,
2699 case WM_NCRBUTTONUP
:
2700 /* We want the user to be able to get a context menu even on the nonclient
2701 area (including the sizing border)! */
2702 uMsg
= WM_CONTEXTMENU
;
2703 wParam
= (WPARAM
)hwnd
;
2706 case WM_CONTEXTMENU
:
2708 POINT pt
, *ppt
= NULL
;
2709 HWND hWndExclude
= NULL
;
2711 /* Check if the administrator has forbidden access to context menus */
2712 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2715 pt
.x
= (SHORT
)LOWORD(lParam
);
2716 pt
.y
= (SHORT
)HIWORD(lParam
);
2718 if (pt
.x
!= -1 || pt
.y
!= -1)
2721 hWndExclude
= This
->hwndStart
;
2723 if ((HWND
)wParam
== This
->hwndStart
)
2725 /* Make sure we can't track the context menu if the start
2726 menu is currently being shown */
2727 if (!(SendMessage(This
->hwndStart
,
2732 ITrayWindowImpl_TrackCtxMenu(This
,
2733 &StartMenuBtnCtxMenu
,
2736 This
->Position
== ABE_BOTTOM
,
2742 /* See if the context menu should be handled by the task band site */
2743 if (ppt
!= NULL
&& This
->TrayBandSite
!= NULL
)
2746 POINT ptClient
= *ppt
;
2748 /* Convert the coordinates to client-coordinates */
2749 MapWindowPoints(NULL
,
2754 hWndAtPt
= ChildWindowFromPoint(This
->hWnd
,
2756 if (hWndAtPt
!= NULL
&&
2757 (hWndAtPt
== This
->hwndRebar
|| IsChild(This
->hwndRebar
,
2760 /* Check if the user clicked on the task switch window */
2762 MapWindowPoints(NULL
,
2767 hWndAtPt
= ChildWindowFromPointEx(This
->hwndRebar
,
2769 CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2770 if (hWndAtPt
== This
->hwndTaskSwitch
)
2771 goto HandleTrayContextMenu
;
2773 /* Forward the message to the task band site */
2774 ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2782 goto HandleTrayContextMenu
;
2786 HandleTrayContextMenu
:
2787 /* Tray the default tray window context menu */
2788 ITrayWindowImpl_TrackCtxMenu(This
,
2801 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2802 the rebar control! But we shouldn't forward messages that the band
2803 site doesn't handle, such as other controls (start button, tray window */
2804 if (This
->TrayBandSite
== NULL
||
2805 !SUCCEEDED(ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2812 const NMHDR
*nmh
= (const NMHDR
*)lParam
;
2814 if (nmh
->hwndFrom
== This
->hwndTrayNotify
)
2819 /* Cause all controls to be aligned */
2820 PostMessage(This
->hWnd
,
2831 case WM_NCLBUTTONDBLCLK
:
2833 /* We "handle" this message so users can't cause a weird maximize/restore
2834 window animation when double-clicking the tray window! */
2836 /* We should forward mouse messages to child windows here.
2837 Right now, this is only clock double-click */
2839 if (TrayNotify_GetClockRect(This
->hwndTrayNotify
, &rcClock
))
2842 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2843 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2844 if (PtInRect(&rcClock
, ptClick
))
2845 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
2852 LPCREATESTRUCT CreateStruct
= (LPCREATESTRUCT
)lParam
;
2853 This
= (ITrayWindowImpl
*)CreateStruct
->lpCreateParams
;
2855 if (InterlockedCompareExchangePointer((PVOID
*)&This
->hWnd
,
2859 /* Somebody else was faster... */
2863 SetWindowLongPtr(hwnd
,
2867 return ITrayWindowImpl_NCCreate(This
);
2871 ITrayWindowImpl_Create(This
);
2875 ITrayWindowImpl_Destroy(This
);
2878 case WM_APP_TRAYDESTROY
:
2879 DestroyWindow(hwnd
);
2882 case TWM_OPENSTARTMENU
:
2885 HRESULT hr
= IUnknown_GetWindow((IUnknown
*)This
->StartMenuPopup
, &hwndStartMenu
);
2889 if (IsWindowVisible(hwndStartMenu
))
2890 SetWindowPos(hwndStartMenu
, 0,0,0,0,0, SWP_HIDEWINDOW
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
);
2892 SendMessage(This
->hWnd
, WM_COMMAND
, MAKEWPARAM(BN_CLICKED
, IDC_STARTBTN
), (LPARAM
)This
->hwndStart
);
2897 if ((HWND
)lParam
== This
->hwndStart
)
2899 PopupStartMenu(This
);
2903 if (This
->TrayBandSite
== NULL
||
2904 FAILED(ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2911 switch (LOWORD(wParam
))
2913 /* FIXME: Handle these commands as well */
2914 case IDM_TASKBARANDSTARTMENU
:
2916 ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This
));
2922 case IDM_HELPANDSUPPORT
:
2924 /* TODO: Implement properly */
2926 LPCWSTR strSite
= L
"http://www.reactos.org/";
2928 /* TODO: Make localizable */
2929 LPCWSTR strCaption
= L
"Sorry";
2930 LPCWSTR strMessage
= L
"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed.";
2931 WCHAR tmpMessage
[512];
2933 /* TODO: Read from the registry */
2934 LPCWSTR strVerb
= NULL
; /* default */
2935 LPCWSTR strPath
= strSite
;
2936 LPCWSTR strParams
= NULL
;
2938 /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */
2939 int result
= (int) ShellExecuteW(hwnd
, strVerb
, strPath
, strParams
, NULL
, SW_SHOWNORMAL
);
2942 StringCchPrintfW(tmpMessage
, 512, strMessage
, strSite
, result
);
2943 MessageBoxExW(hwnd
, tmpMessage
, strCaption
, MB_OK
, 0);
2950 ITrayWindowImpl_DisplayRunFileDlg(This
);
2954 /* FIXME: Handle these commands as well */
2955 case IDM_SYNCHRONIZE
:
2957 case IDM_DISCONNECT
:
2958 case IDM_UNDOCKCOMPUTER
:
2964 EXITWINDLG ExitWinDlg
;
2966 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2967 ExitWinDlg
= (EXITWINDLG
)GetProcAddress(hShell32
, (LPCSTR
)60);
2977 case WM_NCMOUSEMOVE
:
2981 SetTimer(This
->hWnd
, TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2986 if (wParam
== TIMER_ID_MOUSETRACK
)
2988 ProcessMouseTracking(This
);
2990 else if (wParam
== TIMER_ID_AUTOHIDE
)
2992 ProcessAutoHide(This
);
3004 Ret
= DefWindowProc(hwnd
,
3014 * Tray Window Context Menu
3018 CreateTrayWindowContextMenu(IN HWND hWndOwner
,
3019 IN PVOID
*ppcmContext
,
3020 IN PVOID Context OPTIONAL
)
3022 ITrayWindowImpl
*This
= (ITrayWindowImpl
*)Context
;
3023 IContextMenu
*pcm
= NULL
;
3026 hPopup
= LoadPopupMenu(hExplorerInstance
,
3027 MAKEINTRESOURCE(IDM_TRAYWND
));
3031 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3038 CheckMenuItem(hPopup
,
3040 MF_BYCOMMAND
| (This
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3042 if (This
->TrayBandSite
!= NULL
)
3044 if (SUCCEEDED(ITrayBandSite_AddContextMenus(This
->TrayBandSite
,
3052 TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
3053 *(IContextMenu
**)ppcmContext
= pcm
;
3062 OnTrayWindowContextMenuCommand(IN HWND hWndOwner
,
3064 IN PVOID pcmContext OPTIONAL
,
3065 IN PVOID Context OPTIONAL
)
3067 ITrayWindowImpl
*This
= (ITrayWindowImpl
*)Context
;
3068 IContextMenu
*pcm
= (IContextMenu
*)pcmContext
;
3072 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3074 CMINVOKECOMMANDINFO cmici
= {0};
3078 /* Setup and invoke the shell command */
3079 cmici
.cbSize
= sizeof(cmici
);
3080 cmici
.hwnd
= hWndOwner
;
3081 cmici
.lpVerb
= (LPCSTR
)MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3082 cmici
.nShow
= SW_NORMAL
;
3084 IContextMenu_InvokeCommand(pcm
,
3090 ITrayWindow_ExecContextMenuCmd(ITrayWindow_from_impl(This
),
3096 IContextMenu_Release(pcm
);
3099 static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu
= {
3100 CreateTrayWindowContextMenu
,
3101 OnTrayWindowContextMenuCommand
3104 /*****************************************************************************/
3107 RegisterTrayWindowClass(VOID
)
3112 if (!RegisterTrayNotifyWndClass())
3115 wcTrayWnd
.style
= CS_DBLCLKS
;
3116 wcTrayWnd
.lpfnWndProc
= TrayWndProc
;
3117 wcTrayWnd
.cbClsExtra
= 0;
3118 wcTrayWnd
.cbWndExtra
= sizeof(ITrayWindowImpl
*);
3119 wcTrayWnd
.hInstance
= hExplorerInstance
;
3120 wcTrayWnd
.hIcon
= NULL
;
3121 wcTrayWnd
.hCursor
= LoadCursor(NULL
,
3123 wcTrayWnd
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
3124 wcTrayWnd
.lpszMenuName
= NULL
;
3125 wcTrayWnd
.lpszClassName
= szTrayWndClass
;
3127 Ret
= RegisterClass(&wcTrayWnd
) != 0;
3130 UnregisterTrayNotifyWndClass();
3136 UnregisterTrayWindowClass(VOID
)
3138 UnregisterTrayNotifyWndClass();
3140 UnregisterClass(szTrayWndClass
,
3145 CreateTrayWindow(VOID
)
3147 ITrayWindowImpl
*This
;
3148 ITrayWindow
*TrayWindow
;
3150 This
= ITrayWindowImpl_Construct();
3153 TrayWindow
= ITrayWindow_from_impl(This
);
3155 ITrayWindowImpl_Open(TrayWindow
);
3157 g_TrayWindow
= This
;
3166 TrayProcessMessages(IN OUT ITrayWindow
*Tray
)
3168 ITrayWindowImpl
*This
;
3171 This
= impl_from_ITrayWindow(Tray
);
3173 /* FIXME: We should keep a reference here... */
3175 while (PeekMessage(&Msg
,
3181 if (Msg
.message
== WM_QUIT
)
3184 if (This
->StartMenuBand
== NULL
||
3185 IMenuBand_IsMenuMessage(This
->StartMenuBand
,
3188 TranslateMessage(&Msg
);
3189 DispatchMessage(&Msg
);
3195 TrayMessageLoop(IN OUT ITrayWindow
*Tray
)
3197 ITrayWindowImpl
*This
;
3201 This
= impl_from_ITrayWindow(Tray
);
3203 /* FIXME: We should keep a reference here... */
3207 Ret
= GetMessage(&Msg
,
3212 if (!Ret
|| Ret
== -1)
3215 if (Msg
.message
== WM_HOTKEY
)
3219 case IDHK_RUN
: /* Win+R */
3220 ITrayWindowImpl_DisplayRunFileDlg(This
);
3225 if (This
->StartMenuBand
== NULL
||
3226 IMenuBand_IsMenuMessage(This
->StartMenuBand
,
3229 TranslateMessage(&Msg
);
3230 DispatchMessage(&Msg
);
3238 * NOTE: This is a very windows-specific COM interface used by SHCreateDesktop()!
3239 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
3240 * The reason we implement it is because we have to use SHCreateDesktop() so
3241 * that the shell provides the desktop window and all the features that come
3242 * with it (especially positioning of desktop icons)
3245 static HRESULT STDMETHODCALLTYPE
3246 ITrayWindowImpl_IShellDesktopTray_QueryInterface(IN OUT IShellDesktopTray
*iface
,
3250 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
3251 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
3253 TRACE("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid
, ppvObj
);
3254 return ITrayWindowImpl_QueryInterface(tray
,
3259 static ULONG STDMETHODCALLTYPE
3260 ITrayWindowImpl_IShellDesktopTray_Release(IN OUT IShellDesktopTray
*iface
)
3262 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
3263 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
3265 TRACE("IShellDesktopTray::Release()\n");
3266 return ITrayWindowImpl_Release(tray
);
3269 static ULONG STDMETHODCALLTYPE
3270 ITrayWindowImpl_IShellDesktopTray_AddRef(IN OUT IShellDesktopTray
*iface
)
3272 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
3273 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
3275 TRACE("IShellDesktopTray::AddRef()\n");
3276 return ITrayWindowImpl_AddRef(tray
);
3279 static ULONG STDMETHODCALLTYPE
3280 ITrayWindowImpl_IShellDesktopTray_GetState(IN OUT IShellDesktopTray
*iface
)
3282 /* FIXME: Return ABS_ flags? */
3283 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3287 static HRESULT STDMETHODCALLTYPE
3288 ITrayWindowImpl_IShellDesktopTray_GetTrayWindow(IN OUT IShellDesktopTray
*iface
,
3289 OUT HWND
*phWndTray
)
3291 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
3292 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
3293 *phWndTray
= This
->hWnd
;
3297 static HRESULT STDMETHODCALLTYPE
3298 ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow(IN OUT IShellDesktopTray
*iface
,
3299 IN HWND hWndDesktop
)
3301 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
3302 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
3304 This
->hWndDesktop
= hWndDesktop
;
3308 static HRESULT STDMETHODCALLTYPE
3309 ITrayWindowImpl_IShellDesktopTray_Unknown(IN OUT IShellDesktopTray
*iface
,
3310 IN DWORD dwUnknown1
,
3311 IN DWORD dwUnknown2
)
3313 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
3317 static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl
=
3320 ITrayWindowImpl_IShellDesktopTray_QueryInterface
,
3321 ITrayWindowImpl_IShellDesktopTray_AddRef
,
3322 ITrayWindowImpl_IShellDesktopTray_Release
,
3323 /*** IShellDesktopTray ***/
3324 ITrayWindowImpl_IShellDesktopTray_GetState
,
3325 ITrayWindowImpl_IShellDesktopTray_GetTrayWindow
,
3326 ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow
,
3327 ITrayWindowImpl_IShellDesktopTray_Unknown
3331 ITrayWindowImpl_RaiseStartButton(ITrayWindowImpl
* This
)
3333 SendMessageW(This
->hwndStart
, BM_SETSTATE
, FALSE
, 0);
3338 Tray_OnStartMenuDismissed()
3340 return ITrayWindowImpl_RaiseStartButton(g_TrayWindow
);