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 static LONG TrayWndCount
= 0;
32 static const TCHAR szTrayWndClass
[] = TEXT("Shell_TrayWnd");
34 static const ITrayWindowVtbl ITrayWindowImpl_Vtbl
;
35 static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl
;
41 const GUID IID_IShellDesktopTray
= {0x213e2df9, 0x9a14, 0x4328, {0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9}};
45 const ITrayWindowVtbl
*lpVtbl
;
46 const IShellDesktopTrayVtbl
*lpVtblShellDesktopTray
;
54 HIMAGELIST himlStartBtn
;
59 ITrayBandSite
*TrayBandSite
;
66 HMONITOR PreviousMonitor
;
67 DWORD DraggingPosition
;
68 HMONITOR DraggingMonitor
;
79 DWORD AlwaysOnTop
: 1;
80 DWORD SmSmallIcons
: 1;
94 IMenuBand
*StartMenuBand
;
95 IMenuPopup
*StartMenuPopup
;
98 HWND hwndTrayPropertiesOwner
;
99 HWND hwndRunFileDlgOwner
;
101 HDPA hdpaShellServices
;
104 static ITrayWindowImpl
* g_TrayWindow
;
106 BOOL
LaunchCPanel(HWND hwnd
, LPCTSTR applet
)
108 TCHAR szParams
[MAX_PATH
];
110 StringCbCopy(szParams
, sizeof(szParams
),
111 TEXT("shell32.dll,Control_RunDLL "));
112 if (FAILED(StringCbCat(szParams
, sizeof(szParams
),
116 return (ShellExecute(hwnd
, TEXT("open"), TEXT("rundll32.exe"), szParams
, NULL
, SW_SHOWDEFAULT
) > (HINSTANCE
)32);
120 IUnknown_from_impl(ITrayWindowImpl
*This
)
122 return (IUnknown
*)&This
->lpVtbl
;
126 ITrayWindow_from_impl(ITrayWindowImpl
*This
)
128 return (ITrayWindow
*)&This
->lpVtbl
;
131 static IShellDesktopTray
*
132 IShellDesktopTray_from_impl(ITrayWindowImpl
*This
)
134 return (IShellDesktopTray
*)&This
->lpVtblShellDesktopTray
;
137 static ITrayWindowImpl
*
138 impl_from_ITrayWindow(ITrayWindow
*iface
)
140 return (ITrayWindowImpl
*)((ULONG_PTR
)iface
- FIELD_OFFSET(ITrayWindowImpl
,
144 static ITrayWindowImpl
*
145 impl_from_IShellDesktopTray(IShellDesktopTray
*iface
)
147 return (ITrayWindowImpl
*)((ULONG_PTR
)iface
- FIELD_OFFSET(ITrayWindowImpl
,
148 lpVtblShellDesktopTray
));
156 ITrayWindowImpl_UpdateNonClientMetrics(IN OUT ITrayWindowImpl
*This
)
158 This
->ncm
.cbSize
= sizeof(This
->ncm
);
159 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
164 if (This
->hFont
!= NULL
)
165 DeleteObject(This
->hFont
);
167 This
->hFont
= CreateFontIndirect(&This
->ncm
.lfMessageFont
);
175 ITrayWindowImpl_SetWindowsFont(IN OUT ITrayWindowImpl
*This
)
177 if (This
->hwndTrayNotify
!= NULL
)
179 SendMessage(This
->hwndTrayNotify
,
187 ITrayWindowImpl_GetScreenRectFromRect(IN OUT ITrayWindowImpl
*This
,
194 mi
.cbSize
= sizeof(mi
);
195 hMon
= MonitorFromRect(pRect
,
201 *pRect
= mi
.rcMonitor
;
207 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
208 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
217 ITrayWindowImpl_GetMonitorFromRect(IN OUT ITrayWindowImpl
*This
,
218 IN
const RECT
*pRect
)
222 /* In case the monitor sizes or saved sizes differ a bit (probably
223 not a lot, only so the tray window overlaps into another monitor
224 now), minimize the risk that we determine a wrong monitor by
225 using the center point of the tray window if we can't determine
226 it using the rectangle. */
227 hMon
= MonitorFromRect(pRect
,
228 MONITOR_DEFAULTTONULL
);
233 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
234 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
236 /* be less error-prone, find the nearest monitor */
237 hMon
= MonitorFromPoint(pt
,
238 MONITOR_DEFAULTTONEAREST
);
245 ITrayWindowImpl_GetScreenRect(IN OUT ITrayWindowImpl
*This
,
246 IN HMONITOR hMonitor
,
249 HMONITOR hMon
= NULL
;
251 if (hMonitor
!= NULL
)
255 mi
.cbSize
= sizeof(mi
);
256 if (!GetMonitorInfo(hMonitor
,
259 /* Hm, the monitor is gone? Try to find a monitor where it
260 could be located now */
261 hMon
= ITrayWindowImpl_GetMonitorFromRect(This
,
264 !GetMonitorInfo(hMon
,
272 *pRect
= mi
.rcMonitor
;
279 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
280 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
287 ITrayWindowImpl_MakeTrayRectWithSize(IN DWORD Position
,
288 IN
const SIZE
*pTraySize
,
294 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
298 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
302 pRect
->left
= pRect
->right
- pTraySize
->cx
;
307 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
313 ITrayWindowImpl_GetTrayRectFromScreenRect(IN OUT ITrayWindowImpl
*This
,
315 IN
const RECT
*pScreen
,
316 IN
const SIZE
*pTraySize OPTIONAL
,
319 if (pTraySize
== NULL
)
320 pTraySize
= &This
->TraySize
;
324 /* Move the border outside of the screen */
326 GetSystemMetrics(SM_CXEDGE
),
327 GetSystemMetrics(SM_CYEDGE
));
329 ITrayWindowImpl_MakeTrayRectWithSize(Position
,
335 ITrayWindowImpl_IsPosHorizontal(IN OUT ITrayWindowImpl
*This
)
337 return This
->Position
== ABE_TOP
|| This
->Position
== ABE_BOTTOM
;
341 ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl
*This
,
350 //Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
352 szWnd
.cx
= pRect
->right
- pRect
->left
;
353 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
356 hMon
= ITrayWindowImpl_GetScreenRectFromRect(This
,
358 MONITOR_DEFAULTTONEAREST
);
360 /* Calculate the maximum size of the tray window and limit the window
361 size to half of the screen's size. */
362 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
363 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
364 if (szWnd
.cx
> szMax
.cx
)
366 if (szWnd
.cy
> szMax
.cy
)
369 /* FIXME - calculate */
371 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
382 ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl
*This
,
387 AdjustWindowRectEx(&rcMin
,
388 GetWindowLong(This
->hWnd
,
391 GetWindowLong(This
->hWnd
,
400 ITrayWindowImpl_GetDraggingRectFromPt(IN OUT ITrayWindowImpl
*This
,
403 OUT HMONITOR
*phMonitor
)
405 HMONITOR hMon
, hMonNew
;
406 DWORD PosH
, PosV
, Pos
;
407 SIZE DeltaPt
, ScreenOffset
;
413 /* Determine the screen rectangle */
414 hMon
= MonitorFromPoint(pt
,
415 MONITOR_DEFAULTTONULL
);
421 mi
.cbSize
= sizeof(mi
);
422 if (!GetMonitorInfo(hMon
,
426 goto GetPrimaryScreenRect
;
429 /* make left top corner of the screen zero based to
430 make calculations easier */
431 pt
.x
-= mi
.rcMonitor
.left
;
432 pt
.y
-= mi
.rcMonitor
.top
;
434 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
435 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
436 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
437 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
441 GetPrimaryScreenRect
:
444 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
445 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
448 /* Calculate the nearest screen border */
449 if (pt
.x
< rcScreen
.right
/ 2)
456 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
460 if (pt
.y
< rcScreen
.bottom
/ 2)
467 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
471 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
473 /* Fix the screen origin to be relative to the primary monitor again */
474 OffsetRect(&rcScreen
,
478 hMonNew
= ITrayWindowImpl_GetMonitorFromRect(This
,
479 &This
->rcTrayWnd
[Pos
]);
484 /* Recalculate the rectangle, we're dragging to another monitor.
485 We don't need to recalculate the rect on single monitor systems. */
486 szTray
.cx
= This
->rcTrayWnd
[Pos
].right
- This
->rcTrayWnd
[Pos
].left
;
487 szTray
.cy
= This
->rcTrayWnd
[Pos
].bottom
- This
->rcTrayWnd
[Pos
].top
;
489 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
499 /* The user is dragging the tray window on the same monitor. We don't need
500 to recalculate the rectangle */
501 *pRect
= This
->rcTrayWnd
[Pos
];
510 ITrayWindowImpl_GetDraggingRectFromRect(IN OUT ITrayWindowImpl
*This
,
512 OUT HMONITOR
*phMonitor
)
516 /* Calculate the center of the rectangle. We call
517 ITrayWindowImpl_GetDraggingRectFromPt to calculate a valid
518 dragging rectangle */
519 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
520 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
522 return ITrayWindowImpl_GetDraggingRectFromPt(This
,
529 ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl
*This
,
530 IN OUT LPWINDOWPOS pwp
)
534 if (This
->IsDragging
)
536 rcTray
.left
= pwp
->x
;
538 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
539 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
541 if (!EqualRect(&rcTray
,
542 &This
->rcTrayWnd
[This
->DraggingPosition
]))
544 /* Recalculate the rectangle, the user dragged the tray
545 window to another monitor or the window was somehow else
547 This
->DraggingPosition
= ITrayWindowImpl_GetDraggingRectFromRect(This
,
549 &This
->DraggingMonitor
);
550 //This->rcTrayWnd[This->DraggingPosition] = rcTray;
553 //This->Monitor = ITrayWindowImpl_CalculateValidSize(This,
554 // This->DraggingPosition,
557 This
->Monitor
= This
->DraggingMonitor
;
558 This
->Position
= This
->DraggingPosition
;
559 This
->IsDragging
= FALSE
;
561 This
->rcTrayWnd
[This
->Position
] = rcTray
;
564 else if (GetWindowRect(This
->hWnd
,
567 if (This
->InSizeMove
)
569 if (!(pwp
->flags
& SWP_NOMOVE
))
571 rcTray
.left
= pwp
->x
;
575 if (!(pwp
->flags
& SWP_NOSIZE
))
577 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
578 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
581 This
->Position
= ITrayWindowImpl_GetDraggingRectFromRect(This
,
585 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
592 ITrayWindowImpl_MakeTrayRectWithSize(This
->Position
,
597 This
->rcTrayWnd
[This
->Position
] = rcTray
;
601 /* If the user isn't resizing the tray window we need to make sure the
602 new size or position is valid. This is to prevent changes to the window
603 without user interaction. */
604 rcTray
= This
->rcTrayWnd
[This
->Position
];
608 This
->TraySize
.cx
= rcTray
.right
- rcTray
.left
;
609 This
->TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
611 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
612 pwp
->x
= rcTray
.left
;
614 pwp
->cx
= This
->TraySize
.cx
;
615 pwp
->cy
= This
->TraySize
.cy
;
620 ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl
*This
,
623 RECT rcClip
, rcWindow
;
626 if (GetWindowRect(This
->hWnd
,
629 /* Disable clipping on systems with only one monitor */
630 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
637 ITrayWindowImpl_GetScreenRect(This
,
641 if (!IntersectRect(&rcClip
,
652 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
657 /* Set the clipping region or make sure the window isn't clipped
658 by disabling it explicitly. */
659 SetWindowRgn(This
->hWnd
,
666 ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl
*This
)
668 RECT rcTray
,rcWorkArea
;
670 /* If monitor has changed then fix the previous monitors work area */
671 if (This
->PreviousMonitor
!= This
->Monitor
)
673 ITrayWindowImpl_GetScreenRect(This
,
674 This
->PreviousMonitor
,
676 SystemParametersInfo(SPI_SETWORKAREA
,
682 rcTray
= This
->rcTrayWnd
[This
->Position
];
684 ITrayWindowImpl_GetScreenRect(This
,
687 This
->PreviousMonitor
= This
->Monitor
;
689 /* If AutoHide is false then change the workarea to exclude the area that
690 the taskbar covers. */
693 switch (This
->Position
)
696 rcWorkArea
.top
= rcTray
.bottom
;
699 rcWorkArea
.left
= rcTray
.right
;
702 rcWorkArea
.right
= rcTray
.left
;
705 rcWorkArea
.bottom
= rcTray
.top
;
710 SystemParametersInfo(SPI_SETWORKAREA
,
717 ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl
*This
)
721 rcTray
= This
->rcTrayWnd
[This
->Position
];
722 // TRACE("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
724 /* Move the tray window */
725 SetWindowPos(This
->hWnd
,
729 rcTray
.right
- rcTray
.left
,
730 rcTray
.bottom
- rcTray
.top
,
733 ITrayWindowImpl_ResizeWorkArea(This
);
735 ITrayWindowImpl_ApplyClipping(This
,
739 typedef struct _TW_STUCKRECTS2
747 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
750 ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl
*This
)
755 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
756 DWORD cbSize
= sizeof(sr
);
758 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
759 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
760 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
761 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
763 if (SHGetValue(hkExplorer
,
768 &cbSize
) == ERROR_SUCCESS
&&
769 sr
.cbSize
== sizeof(sr
))
771 This
->AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
772 This
->AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
773 This
->SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
774 This
->HideClock
= (sr
.dwFlags
& 0x8) != 0;
776 /* FIXME: Are there more flags? */
778 if (sr
.Position
> ABE_BOTTOM
)
779 This
->Position
= ABE_BOTTOM
;
781 This
->Position
= sr
.Position
;
783 /* Try to find out which monitor the tray window was located on last.
784 Here we're only interested in the monitor screen that we think
785 is the last one used. We're going to determine on which monitor
786 we really are after calculating the docked position. */
788 ITrayWindowImpl_GetScreenRectFromRect(This
,
790 MONITOR_DEFAULTTONEAREST
);
794 This
->Position
= ABE_BOTTOM
;
795 This
->AlwaysOnTop
= TRUE
;
797 /* Use the minimum size of the taskbar, we'll use the start
798 button as a minimum for now. Make sure we calculate the
799 entire window size, not just the client size. However, we
800 use a thinner border than a standard thick border, so that
801 the start button and bands are not stuck to the screen border. */
802 sr
.Size
.cx
= This
->StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
803 sr
.Size
.cy
= This
->StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
805 /* Use the primary screen by default */
808 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
809 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
810 ITrayWindowImpl_GetScreenRectFromRect(This
,
812 MONITOR_DEFAULTTOPRIMARY
);
815 if (This
->hWnd
!= NULL
)
816 SetWindowPos(This
->hWnd
,
817 This
->AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
822 SWP_NOMOVE
| SWP_NOSIZE
);
824 /* Determine a minimum tray window rectangle. The "client" height is
825 zero here since we cannot determine an optimal minimum width when
826 loaded as a vertical tray window. We just need to make sure the values
827 loaded from the registry are at least. The windows explorer behaves
828 the same way, it allows the user to save a zero width vertical tray
829 window, but not a zero height horizontal tray window. */
830 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
831 WndSize
.cy
= This
->StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
833 if (WndSize
.cx
< sr
.Size
.cx
)
834 WndSize
.cx
= sr
.Size
.cx
;
835 if (WndSize
.cy
< sr
.Size
.cy
)
836 WndSize
.cy
= sr
.Size
.cy
;
838 /* Save the calculated size */
839 This
->TraySize
= WndSize
;
841 /* Calculate all docking rectangles. We need to do this here so they're
842 initialized and dragging the tray window to another position gives
848 ITrayWindowImpl_GetTrayRectFromScreenRect(This
,
852 &This
->rcTrayWnd
[Pos
]);
853 // 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);
856 /* Determine which monitor we are on. It shouldn't matter which docked
857 position rectangle we use */
858 This
->Monitor
= ITrayWindowImpl_GetMonitorFromRect(This
,
859 &This
->rcTrayWnd
[ABE_LEFT
]);
863 ITrayWindowImpl_TrackMenu(IN OUT ITrayWindowImpl
*This
,
865 IN POINT
*ppt OPTIONAL
,
866 IN HWND hwndExclude OPTIONAL
,
868 IN BOOL IsContextMenu
)
870 TPMPARAMS tmp
, *ptmp
= NULL
;
875 if (hwndExclude
!= NULL
)
877 /* Get the client rectangle and map it to screen coordinates */
878 if (GetClientRect(hwndExclude
,
880 MapWindowPoints(hwndExclude
,
882 (LPPOINT
)&tmp
.rcExclude
,
892 GetClientRect(This
->hWnd
,
894 MapWindowPoints(This
->hWnd
,
896 (LPPOINT
)&tmp
.rcExclude
,
904 /* NOTE: TrackPopupMenuEx will eventually align the track position
905 for us, no need to take care of it here as long as the
906 coordinates are somewhere within the exclusion rectangle */
907 pt
.x
= ptmp
->rcExclude
.left
;
908 pt
.y
= ptmp
->rcExclude
.top
;
916 tmp
.cbSize
= sizeof(tmp
);
918 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
919 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
921 fuFlags
|= TPM_RIGHTBUTTON
;
923 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
925 cmdId
= TrackPopupMenuEx(hMenu
,
936 ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl
*This
,
937 IN
const TRAYWINDOW_CTXMENU
*pMenu
,
938 IN POINT
*ppt OPTIONAL
,
939 IN HWND hwndExclude OPTIONAL
,
941 IN PVOID Context OPTIONAL
)
945 PVOID pcmContext
= NULL
;
947 hPopup
= pMenu
->CreateCtxMenu(This
->hWnd
,
952 cmdId
= ITrayWindowImpl_TrackMenu(This
,
959 pMenu
->CtxMenuCommand(This
->hWnd
,
969 ITrayWindowImpl_Free(ITrayWindowImpl
*This
)
971 HeapFree(hProcessHeap
,
977 static ULONG STDMETHODCALLTYPE
978 ITrayWindowImpl_Release(IN OUT ITrayWindow
*iface
)
980 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
983 Ret
= InterlockedDecrement(&This
->Ref
);
985 ITrayWindowImpl_Free(This
);
991 ITrayWindowImpl_Destroy(ITrayWindowImpl
*This
)
993 (void)InterlockedExchangePointer((PVOID
*)&This
->hWnd
,
997 if (This
->hdpaShellServices
!= NULL
)
999 ShutdownShellServices(This
->hdpaShellServices
);
1000 This
->hdpaShellServices
= NULL
;
1003 if (This
->himlStartBtn
!= NULL
)
1005 ImageList_Destroy(This
->himlStartBtn
);
1006 This
->himlStartBtn
= NULL
;
1009 if (This
->hCaptionFont
!= NULL
)
1011 DeleteObject(This
->hCaptionFont
);
1012 This
->hCaptionFont
= NULL
;
1015 if (This
->hStartBtnFont
!= NULL
)
1017 DeleteObject(This
->hStartBtnFont
);
1018 This
->hStartBtnFont
= NULL
;
1021 if (This
->hFont
!= NULL
)
1023 DeleteObject(This
->hFont
);
1027 if (This
->StartMenuPopup
!= NULL
)
1029 IMenuPopup_Release(This
->StartMenuPopup
);
1030 This
->StartMenuPopup
= NULL
;
1033 if (This
->hbmStartMenu
!= NULL
)
1035 DeleteObject(This
->hbmStartMenu
);
1036 This
->hbmStartMenu
= NULL
;
1039 if (This
->StartMenuBand
!= NULL
)
1041 IMenuBand_Release(This
->StartMenuBand
);
1042 This
->StartMenuBand
= NULL
;
1045 if (This
->TrayBandSite
!= NULL
)
1047 /* FIXME: Unload bands */
1048 ITrayBandSite_Release(This
->TrayBandSite
);
1049 This
->TrayBandSite
= NULL
;
1052 if (This
->TaskbarTheme
)
1054 CloseThemeData(This
->TaskbarTheme
);
1055 This
->TaskbarTheme
= NULL
;
1058 ITrayWindowImpl_Release(ITrayWindow_from_impl(This
));
1060 if (InterlockedDecrement(&TrayWndCount
) == 0)
1064 static ULONG STDMETHODCALLTYPE
1065 ITrayWindowImpl_AddRef(IN OUT ITrayWindow
*iface
)
1067 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1069 return InterlockedIncrement(&This
->Ref
);
1074 ITrayWindowImpl_NCCreate(IN OUT ITrayWindowImpl
*This
)
1076 ITrayWindowImpl_AddRef(ITrayWindow_from_impl(This
));
1082 ITrayWindowImpl_UpdateStartButton(IN OUT ITrayWindowImpl
*This
,
1083 IN HBITMAP hbmStart OPTIONAL
)
1085 SIZE Size
= { 0, 0 };
1087 if (This
->himlStartBtn
== NULL
||
1088 !SendMessage(This
->hwndStart
,
1093 Size
.cx
= GetSystemMetrics(SM_CXEDGE
);
1094 Size
.cy
= GetSystemMetrics(SM_CYEDGE
);
1096 if (hbmStart
== NULL
)
1098 hbmStart
= (HBITMAP
)SendMessage(This
->hwndStart
,
1104 if (hbmStart
!= NULL
)
1108 if (GetObject(hbmStart
,
1112 Size
.cx
+= bmp
.bmWidth
;
1113 Size
.cy
+= max(bmp
.bmHeight
,
1114 GetSystemMetrics(SM_CYCAPTION
));
1118 /* Huh?! Shouldn't happen... */
1125 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
1126 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
1130 /* Save the size of the start button */
1131 This
->StartBtnSize
= Size
;
1135 ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl
*This
,
1136 IN PRECT prcClient OPTIONAL
)
1139 SIZE TraySize
, StartSize
;
1140 POINT ptTrayNotify
= { 0, 0 };
1144 ITrayWindowImpl_UpdateStartButton(This
, NULL
);
1145 if (prcClient
!= NULL
)
1147 rcClient
= *prcClient
;
1151 if (!GetClientRect(This
->hWnd
,
1158 Horizontal
= ITrayWindowImpl_IsPosHorizontal(This
);
1160 /* We're about to resize/move the start button, the rebar control and
1161 the tray notification control */
1162 dwp
= BeginDeferWindowPos(3);
1166 /* Limit the Start button width to the client width, if neccessary */
1167 StartSize
= This
->StartBtnSize
;
1168 if (StartSize
.cx
> rcClient
.right
)
1169 StartSize
.cx
= rcClient
.right
;
1171 if (This
->hwndStart
!= NULL
)
1173 /* Resize and reposition the button */
1174 dwp
= DeferWindowPos(dwp
,
1181 SWP_NOZORDER
| SWP_NOACTIVATE
);
1186 /* Determine the size that the tray notification window needs */
1190 TraySize
.cy
= rcClient
.bottom
;
1194 TraySize
.cx
= rcClient
.right
;
1198 if (This
->hwndTrayNotify
!= NULL
&&
1199 SendMessage(This
->hwndTrayNotify
,
1200 TNWM_GETMINIMUMSIZE
,
1204 /* Move the tray notification window to the desired location */
1206 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1208 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1210 dwp
= DeferWindowPos(dwp
,
1211 This
->hwndTrayNotify
,
1217 SWP_NOZORDER
| SWP_NOACTIVATE
);
1222 /* Resize/Move the rebar control */
1223 if (This
->hwndRebar
!= NULL
)
1225 POINT ptRebar
= { 0, 0 };
1228 SetWindowStyle(This
->hwndRebar
,
1230 Horizontal
? 0 : CCS_VERT
);
1234 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1235 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1236 szRebar
.cy
= rcClient
.bottom
;
1240 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1241 szRebar
.cx
= rcClient
.right
;
1242 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1245 dwp
= DeferWindowPos(dwp
,
1252 SWP_NOZORDER
| SWP_NOACTIVATE
);
1256 EndDeferWindowPos(dwp
);
1258 if (This
->hwndTaskSwitch
!= NULL
)
1260 /* Update the task switch window configuration */
1261 SendMessage(This
->hwndTaskSwitch
,
1262 TSWM_UPDATETASKBARPOS
,
1269 ITrayWindowImpl_CreateStartBtnImageList(IN OUT ITrayWindowImpl
*This
)
1274 if (This
->himlStartBtn
!= NULL
)
1277 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
1278 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
1280 /* Load the start button icon and create a image list for it */
1281 hIconStart
= LoadImage(hExplorerInstance
,
1282 MAKEINTRESOURCE(IDI_START
),
1286 LR_SHARED
| LR_DEFAULTCOLOR
);
1288 if (hIconStart
!= NULL
)
1290 This
->himlStartBtn
= ImageList_Create(IconSize
.cx
,
1292 ILC_COLOR32
| ILC_MASK
,
1295 if (This
->himlStartBtn
!= NULL
)
1297 if (ImageList_AddIcon(This
->himlStartBtn
,
1303 /* Failed to add the icon! */
1304 ImageList_Destroy(This
->himlStartBtn
);
1305 This
->himlStartBtn
= NULL
;
1313 ITrayWindowImpl_CreateStartButtonBitmap(IN OUT ITrayWindowImpl
*This
)
1315 TCHAR szStartCaption
[32];
1318 HDC hDCScreen
= NULL
;
1319 SIZE Size
, SmallIcon
;
1320 HBITMAP hbmpOld
, hbmp
= NULL
;
1321 HBITMAP hBitmap
= NULL
;
1327 /* NOTE: This is the backwards compatibility code that is used if the
1328 Common Controls Version 6.0 are not available! */
1330 if (!LoadString(hExplorerInstance
,
1333 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1338 /* Load the start button icon */
1339 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
1340 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
1341 hIconStart
= LoadImage(hExplorerInstance
,
1342 MAKEINTRESOURCE(IDI_START
),
1346 LR_SHARED
| LR_DEFAULTCOLOR
);
1348 hDCScreen
= GetDC(NULL
);
1349 if (hDCScreen
== NULL
)
1352 hDC
= CreateCompatibleDC(hDCScreen
);
1356 hFontOld
= SelectObject(hDC
,
1357 This
->hStartBtnFont
);
1359 Ret
= GetTextExtentPoint32(hDC
,
1361 _tcslen(szStartCaption
),
1369 /* Make sure the height is at least the size of a caption icon. */
1370 if (hIconStart
!= NULL
)
1371 Size
.cx
+= SmallIcon
.cx
+ 4;
1372 Size
.cy
= max(Size
.cy
,
1375 /* Create the bitmap */
1376 hbmp
= CreateCompatibleBitmap(hDCScreen
,
1382 /* Caluclate the button rect */
1385 rcButton
.right
= Size
.cx
;
1386 rcButton
.bottom
= Size
.cy
;
1388 /* Draw the button */
1389 hbmpOld
= SelectObject(hDC
,
1392 Flags
= DC_TEXT
| DC_INBUTTON
;
1393 if (hIconStart
!= NULL
)
1396 if (DrawCapTemp
!= NULL
)
1398 Ret
= DrawCapTemp(NULL
,
1401 This
->hStartBtnFont
,
1413 /* We successfully created the bitmap! */
1418 if (hDCScreen
!= NULL
)
1434 ITrayWindowImpl_UpdateTheme(IN OUT ITrayWindowImpl
*This
)
1436 if (This
->TaskbarTheme
)
1437 CloseThemeData(This
->TaskbarTheme
);
1439 if (IsThemeActive())
1440 This
->TaskbarTheme
= OpenThemeData(This
->hWnd
, L
"Taskbar");
1442 This
->TaskbarTheme
= 0;
1446 ITrayWindowImpl_Create(IN OUT ITrayWindowImpl
*This
)
1448 TCHAR szStartCaption
[32];
1450 SetWindowTheme(This
->hWnd
, L
"TaskBar", NULL
);
1451 ITrayWindowImpl_UpdateTheme(This
);
1453 InterlockedIncrement(&TrayWndCount
);
1455 if (!LoadString(hExplorerInstance
,
1458 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1460 szStartCaption
[0] = TEXT('\0');
1463 if (This
->hStartBtnFont
== NULL
|| This
->hCaptionFont
== NULL
)
1465 NONCLIENTMETRICS ncm
;
1467 /* Get the system fonts, we use the caption font,
1468 always bold, though. */
1469 ncm
.cbSize
= sizeof(ncm
);
1470 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1475 if (This
->hCaptionFont
== NULL
)
1477 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1478 This
->hCaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1481 if (This
->hStartBtnFont
== NULL
)
1483 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
1484 This
->hStartBtnFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1489 /* Create the Start button */
1490 This
->hwndStart
= CreateWindowEx(0,
1493 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1494 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1500 (HMENU
)IDC_STARTBTN
,
1503 if (This
->hwndStart
)
1505 SetWindowTheme(This
->hwndStart
, L
"Start", NULL
);
1506 SendMessage(This
->hwndStart
,
1508 (WPARAM
)This
->hStartBtnFont
,
1511 if (ITrayWindowImpl_CreateStartBtnImageList(This
))
1513 BUTTON_IMAGELIST bil
;
1515 /* Try to set the start button image. This requires the Common
1516 Controls 6.0 to be present (XP and later) */
1517 bil
.himl
= This
->himlStartBtn
;
1518 bil
.margin
.left
= bil
.margin
.right
= 1;
1519 bil
.margin
.top
= bil
.margin
.bottom
= 1;
1520 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
1522 if (!SendMessage(This
->hwndStart
,
1527 /* Fall back to the deprecated method on older systems that don't
1528 support Common Controls 6.0 */
1529 ImageList_Destroy(This
->himlStartBtn
);
1530 This
->himlStartBtn
= NULL
;
1532 goto SetStartBtnImage
;
1535 /* We're using the image list, remove the BS_BITMAP style and
1536 don't center it horizontally */
1537 SetWindowStyle(This
->hwndStart
,
1538 BS_BITMAP
| BS_RIGHT
,
1541 ITrayWindowImpl_UpdateStartButton(This
,
1546 HBITMAP hbmStart
, hbmOld
;
1549 hbmStart
= ITrayWindowImpl_CreateStartButtonBitmap(This
);
1550 if (hbmStart
!= NULL
)
1552 ITrayWindowImpl_UpdateStartButton(This
,
1555 hbmOld
= (HBITMAP
)SendMessage(This
->hwndStart
,
1561 DeleteObject(hbmOld
);
1566 /* Load the saved tray window settings */
1567 ITrayWindowImpl_RegLoadSettings(This
);
1569 /* Create and initialize the start menu */
1570 This
->hbmStartMenu
= LoadBitmap(hExplorerInstance
,
1571 MAKEINTRESOURCE(IDB_STARTMENU
));
1572 This
->StartMenuPopup
= CreateStartMenu(ITrayWindow_from_impl(This
),
1573 &This
->StartMenuBand
,
1577 /* Load the tray band site */
1578 if (This
->TrayBandSite
!= NULL
)
1580 ITrayBandSite_Release(This
->TrayBandSite
);
1583 This
->TrayBandSite
= CreateTrayBandSite(ITrayWindow_from_impl(This
),
1585 &This
->hwndTaskSwitch
);
1586 SetWindowTheme(This
->hwndRebar
, L
"TaskBar", NULL
);
1588 /* Create the tray notification window */
1589 This
->hwndTrayNotify
= CreateTrayNotifyWnd(ITrayWindow_from_impl(This
),
1592 if (ITrayWindowImpl_UpdateNonClientMetrics(This
))
1594 ITrayWindowImpl_SetWindowsFont(This
);
1597 /* Move the tray window to the right position and resize it if neccessary */
1598 ITrayWindowImpl_CheckTrayWndPosition(This
);
1600 /* Align all controls on the tray window */
1601 ITrayWindowImpl_AlignControls(This
,
1604 InitShellServices(&(This
->hdpaShellServices
));
1607 static HRESULT STDMETHODCALLTYPE
1608 ITrayWindowImpl_QueryInterface(IN OUT ITrayWindow
*iface
,
1612 ITrayWindowImpl
*This
;
1617 This
= impl_from_ITrayWindow(iface
);
1619 if (IsEqualIID(riid
,
1622 *ppvObj
= IUnknown_from_impl(This
);
1624 else if (IsEqualIID(riid
,
1625 &IID_IShellDesktopTray
))
1627 *ppvObj
= IShellDesktopTray_from_impl(This
);
1632 return E_NOINTERFACE
;
1635 ITrayWindowImpl_AddRef(iface
);
1639 static ITrayWindowImpl
*
1640 ITrayWindowImpl_Construct(VOID
)
1642 ITrayWindowImpl
*This
;
1644 This
= HeapAlloc(hProcessHeap
,
1650 This
->lpVtbl
= &ITrayWindowImpl_Vtbl
;
1651 This
->lpVtblShellDesktopTray
= &IShellDesktopTrayImpl_Vtbl
;
1653 This
->Position
= (DWORD
)-1;
1658 static HRESULT STDMETHODCALLTYPE
1659 ITrayWindowImpl_Open(IN OUT ITrayWindow
*iface
)
1661 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1666 /* Check if there's already a window created and try to show it.
1667 If it was somehow destroyed just create a new tray window. */
1668 if (This
->hWnd
!= NULL
)
1670 if (IsWindow(This
->hWnd
))
1672 if (!IsWindowVisible(This
->hWnd
))
1674 ITrayWindowImpl_CheckTrayWndPosition(This
);
1676 ShowWindow(This
->hWnd
,
1681 goto TryCreateTrayWnd
;
1688 dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1689 if (This
->AlwaysOnTop
)
1690 dwExStyle
|= WS_EX_TOPMOST
;
1692 if (This
->Position
!= (DWORD
)-1)
1693 rcWnd
= This
->rcTrayWnd
[This
->Position
];
1700 hWnd
= CreateWindowEx(dwExStyle
,
1703 WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1704 WS_BORDER
| WS_THICKFRAME
,
1707 rcWnd
.right
- rcWnd
.left
,
1708 rcWnd
.bottom
- rcWnd
.top
,
1720 static HRESULT STDMETHODCALLTYPE
1721 ITrayWindowImpl_Close(IN OUT ITrayWindow
*iface
)
1723 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1725 if (This
->hWnd
!= NULL
)
1727 SendMessage(This
->hWnd
,
1736 static HWND STDMETHODCALLTYPE
1737 ITrayWindowImpl_GetHWND(IN OUT ITrayWindow
*iface
)
1739 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1744 static BOOL STDMETHODCALLTYPE
1745 ITrayWindowImpl_IsSpecialHWND(IN OUT ITrayWindow
*iface
,
1748 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1750 return (hWnd
== This
->hWnd
||
1751 (This
->hWndDesktop
!= NULL
&& hWnd
== This
->hWndDesktop
));
1754 static BOOL STDMETHODCALLTYPE
1755 ITrayWindowImpl_IsHorizontal(IN OUT ITrayWindow
*iface
)
1757 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1758 return ITrayWindowImpl_IsPosHorizontal(This
);
1761 static HFONT STDMETHODCALLTYPE
1762 ITrayWIndowImpl_GetCaptionFonts(IN OUT ITrayWindow
*iface
,
1763 OUT HFONT
*phBoldCaption OPTIONAL
)
1765 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1767 if (phBoldCaption
!= NULL
)
1768 *phBoldCaption
= This
->hStartBtnFont
;
1770 return This
->hCaptionFont
;
1774 TrayPropertiesThread(IN OUT PVOID pParam
)
1776 ITrayWindowImpl
*This
= pParam
;
1780 GetWindowRect(This
->hwndStart
, &posRect
);
1781 hwnd
= CreateWindowEx(0,
1784 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1787 posRect
.right
- posRect
.left
,
1788 posRect
.bottom
- posRect
.top
,
1794 This
->hwndTrayPropertiesOwner
= hwnd
;
1796 DisplayTrayProperties(hwnd
);
1798 This
->hwndTrayPropertiesOwner
= NULL
;
1799 DestroyWindow(hwnd
);
1804 static HWND STDMETHODCALLTYPE
1805 ITrayWindowImpl_DisplayProperties(IN OUT ITrayWindow
*iface
)
1807 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1810 if (This
->hwndTrayPropertiesOwner
)
1812 hTrayProp
= GetLastActivePopup(This
->hwndTrayPropertiesOwner
);
1813 if (hTrayProp
!= NULL
&&
1814 hTrayProp
!= This
->hwndTrayPropertiesOwner
)
1816 SetForegroundWindow(hTrayProp
);
1821 CloseHandle(CreateThread(NULL
, 0, TrayPropertiesThread
, This
, 0, NULL
));
1826 OpenCommonStartMenuDirectory(IN HWND hWndOwner
,
1827 IN LPCTSTR lpOperation
)
1829 TCHAR szDir
[MAX_PATH
];
1831 if (SHGetSpecialFolderPath(hWndOwner
,
1833 CSIDL_COMMON_STARTMENU
,
1836 ShellExecute(hWndOwner
,
1846 OpenTaskManager(IN HWND hWndOwner
)
1848 ShellExecute(hWndOwner
,
1850 TEXT("taskmgr.exe"),
1856 static BOOL STDMETHODCALLTYPE
1857 ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow
*iface
,
1860 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1861 BOOL bHandled
= TRUE
;
1865 case ID_SHELL_CMD_PROPERTIES
:
1866 ITrayWindow_DisplayProperties(iface
);
1869 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1870 OpenCommonStartMenuDirectory(This
->hWnd
,
1874 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1875 OpenCommonStartMenuDirectory(This
->hWnd
,
1879 case ID_LOCKTASKBAR
:
1880 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1882 ITrayWindow_Lock(iface
,
1887 case ID_SHELL_CMD_OPEN_TASKMGR
:
1888 OpenTaskManager(This
->hWnd
);
1891 case ID_SHELL_CMD_UNDO_ACTION
:
1894 case ID_SHELL_CMD_SHOW_DESKTOP
:
1897 case ID_SHELL_CMD_TILE_WND_H
:
1898 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1901 case ID_SHELL_CMD_TILE_WND_V
:
1902 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1905 case ID_SHELL_CMD_CASCADE_WND
:
1906 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1909 case ID_SHELL_CMD_CUST_NOTIF
:
1912 case ID_SHELL_CMD_ADJUST_DAT
:
1913 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
1917 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1925 static BOOL STDMETHODCALLTYPE
1926 ITrayWindowImpl_Lock(IN OUT ITrayWindow
*iface
,
1930 ITrayWindowImpl
*This
= impl_from_ITrayWindow(iface
);
1932 bPrevLock
= This
->Locked
;
1933 if (This
->Locked
!= bLock
)
1935 This
->Locked
= bLock
;
1937 if (This
->TrayBandSite
!= NULL
)
1939 if (!SUCCEEDED(ITrayBandSite_Lock(This
->TrayBandSite
,
1943 This
->Locked
= bPrevLock
;
1951 static const ITrayWindowVtbl ITrayWindowImpl_Vtbl
=
1954 ITrayWindowImpl_QueryInterface
,
1955 ITrayWindowImpl_AddRef
,
1956 ITrayWindowImpl_Release
,
1958 ITrayWindowImpl_Open
,
1959 ITrayWindowImpl_Close
,
1960 ITrayWindowImpl_GetHWND
,
1961 ITrayWindowImpl_IsSpecialHWND
,
1962 ITrayWindowImpl_IsHorizontal
,
1963 ITrayWIndowImpl_GetCaptionFonts
,
1964 ITrayWindowImpl_DisplayProperties
,
1965 ITrayWindowImpl_ExecContextMenuCmd
,
1966 ITrayWindowImpl_Lock
1970 ITrayWindowImpl_DrawBackground(IN ITrayWindowImpl
*This
,
1976 GetClientRect(This
->hWnd
, &rect
);
1977 switch (This
->Position
)
1980 backoundPart
= TBP_BACKGROUNDLEFT
;
1983 backoundPart
= TBP_BACKGROUNDTOP
;
1986 backoundPart
= TBP_BACKGROUNDRIGHT
;
1990 backoundPart
= TBP_BACKGROUNDBOTTOM
;
1993 DrawThemeBackground(This
->TaskbarTheme
, dc
, backoundPart
, 0, &rect
, 0);
1998 ITrayWindowImpl_DrawSizer(IN ITrayWindowImpl
*This
,
2005 GetWindowRect(This
->hWnd
, &rect
);
2006 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
2008 hdc
= GetDCEx(This
->hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
2010 switch (This
->Position
)
2013 backoundPart
= TBP_SIZINGBARLEFT
;
2014 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
2017 backoundPart
= TBP_SIZINGBARTOP
;
2018 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
2021 backoundPart
= TBP_SIZINGBARRIGHT
;
2022 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
2026 backoundPart
= TBP_SIZINGBARBOTTOM
;
2027 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
2031 DrawThemeBackground(This
->TaskbarTheme
, hdc
, backoundPart
, 0, &rect
, 0);
2033 ReleaseDC(This
->hWnd
, hdc
);
2038 RunFileDlgThread(IN OUT PVOID pParam
)
2040 ITrayWindowImpl
*This
= pParam
;
2042 RUNFILEDLG RunFileDlg
;
2046 GetWindowRect(This
->hwndStart
,&posRect
);
2048 hwnd
= CreateWindowEx(0,
2051 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
2054 posRect
.right
- posRect
.left
,
2055 posRect
.bottom
- posRect
.top
,
2061 This
->hwndRunFileDlgOwner
= hwnd
;
2063 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2064 RunFileDlg
= (RUNFILEDLG
)GetProcAddress(hShell32
, (LPCSTR
)61);
2066 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
2068 This
->hwndRunFileDlgOwner
= NULL
;
2069 DestroyWindow(hwnd
);
2075 ITrayWindowImpl_DisplayRunFileDlg(IN ITrayWindowImpl
*This
)
2078 if (This
->hwndRunFileDlgOwner
)
2080 hRunDlg
= GetLastActivePopup(This
->hwndRunFileDlgOwner
);
2081 if (hRunDlg
!= NULL
&&
2082 hRunDlg
!= This
->hwndRunFileDlgOwner
)
2084 SetForegroundWindow(hRunDlg
);
2089 CloseHandle(CreateThread(NULL
, 0, RunFileDlgThread
, This
, 0, NULL
));
2092 static void PopupStartMenu(IN ITrayWindowImpl
*This
)
2094 if (This
->StartMenuPopup
!= NULL
)
2100 if (GetWindowRect(This
->hwndStart
,
2101 (RECT
*) &rcExclude
))
2103 switch (This
->Position
)
2106 pt
.x
= rcExclude
.left
;
2107 pt
.y
= rcExclude
.top
;
2108 dwFlags
|= MPPF_BOTTOM
;
2112 pt
.x
= rcExclude
.left
;
2113 pt
.y
= rcExclude
.bottom
;
2114 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
2117 pt
.x
= rcExclude
.right
;
2118 pt
.y
= rcExclude
.bottom
;
2119 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
2123 IMenuPopup_Popup(This
->StartMenuPopup
,
2128 SendMessageW(This
->hwndStart
, BM_SETSTATE
, TRUE
, 0);
2133 static LRESULT CALLBACK
2134 TrayWndProc(IN HWND hwnd
,
2139 ITrayWindowImpl
*This
= NULL
;
2140 LRESULT Ret
= FALSE
;
2142 if (uMsg
!= WM_NCCREATE
)
2144 This
= (ITrayWindowImpl
*)GetWindowLongPtr(hwnd
,
2148 if (This
!= NULL
|| uMsg
== WM_NCCREATE
)
2150 if (This
!= NULL
&& This
->StartMenuBand
!= NULL
)
2157 Msg
.wParam
= wParam
;
2158 Msg
.lParam
= lParam
;
2160 if (IMenuBand_TranslateMenuMessage(This
->StartMenuBand
,
2167 wParam
= Msg
.wParam
;
2168 lParam
= Msg
.lParam
;
2173 case WM_DISPLAYCHANGE
:
2175 /* Load the saved tray window settings */
2176 ITrayWindowImpl_RegLoadSettings(This
);
2178 /* Move the tray window to the right position and resize it if neccessary */
2179 ITrayWindowImpl_CheckTrayWndPosition(This
);
2181 /* Align all controls on the tray window */
2182 ITrayWindowImpl_AlignControls(This
, NULL
);
2188 if (This
->hwndTrayNotify
)
2190 TrayNotify_NotifyMsg(This
->hwndTrayNotify
,
2196 case WM_THEMECHANGED
:
2197 ITrayWindowImpl_UpdateTheme(This
);
2200 if (!This
->TaskbarTheme
)
2202 return ITrayWindowImpl_DrawSizer(This
,
2205 if (!This
->TaskbarTheme
)
2207 return ITrayWindowImpl_DrawBackground(This
,
2209 case WM_CTLCOLORBTN
:
2210 SetBkMode((HDC
)wParam
, TRANSPARENT
);
2211 return (LRESULT
)GetStockObject(HOLLOW_BRUSH
);
2219 /* The user may not be able to resize the tray window.
2220 Pretend like the window is not sizeable when the user
2221 clicks on the border. */
2225 SetLastError(ERROR_SUCCESS
);
2226 if (GetClientRect(hwnd
,
2228 (MapWindowPoints(hwnd
,
2231 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2233 pt
.x
= (SHORT
)LOWORD(lParam
);
2234 pt
.y
= (SHORT
)HIWORD(lParam
);
2236 if (PtInRect(&rcClient
,
2239 /* The user is trying to drag the tray window */
2243 /* Depending on the position of the tray window, allow only
2244 changing the border next to the monitor working area */
2245 switch (This
->Position
)
2248 if (pt
.y
> rcClient
.bottom
)
2252 if (pt
.x
> rcClient
.right
)
2256 if (pt
.x
< rcClient
.left
)
2261 if (pt
.y
< rcClient
.top
)
2271 PRECT pRect
= (PRECT
)lParam
;
2273 /* We need to ensure that an application can not accidently
2274 move the tray window (using SetWindowPos). However, we still
2275 need to be able to move the window in case the user wants to
2276 drag the tray window to another position or in case the user
2277 wants to resize the tray window. */
2278 if (!This
->Locked
&& GetCursorPos(&ptCursor
))
2280 This
->IsDragging
= TRUE
;
2281 This
->DraggingPosition
= ITrayWindowImpl_GetDraggingRectFromPt(This
,
2284 &This
->DraggingMonitor
);
2288 *pRect
= This
->rcTrayWnd
[This
->Position
];
2295 PRECT pRect
= (PRECT
)lParam
;
2299 ITrayWindowImpl_CalculateValidSize(This
,
2305 *pRect
= This
->rcTrayWnd
[This
->Position
];
2310 case WM_WINDOWPOSCHANGING
:
2312 ITrayWindowImpl_ChangingWinPos(This
,
2313 (LPWINDOWPOS
)lParam
);
2320 InvalidateRect(This
->hWnd
, NULL
, TRUE
);
2321 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2323 ITrayWindowImpl_ResizeWorkArea(This
);
2324 /* Clip the tray window on multi monitor systems so the edges can't
2325 overlap into another monitor */
2326 ITrayWindowImpl_ApplyClipping(This
,
2329 if (!GetClientRect(This
->hWnd
,
2337 rcClient
.left
= rcClient
.top
= 0;
2338 rcClient
.right
= LOWORD(lParam
);
2339 rcClient
.bottom
= HIWORD(lParam
);
2342 ITrayWindowImpl_AlignControls(This
,
2347 case WM_ENTERSIZEMOVE
:
2348 This
->InSizeMove
= TRUE
;
2349 This
->IsDragging
= FALSE
;
2352 /* Remove the clipping on multi monitor systems while dragging around */
2353 ITrayWindowImpl_ApplyClipping(This
,
2358 case WM_EXITSIZEMOVE
:
2359 This
->InSizeMove
= FALSE
;
2362 /* Apply clipping */
2363 PostMessage(This
->hWnd
,
2375 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2376 The tray window needs to handle this specially, since it normally doesn't have
2379 static const UINT uidDisableItem
[] = {
2390 /* temporarily enable the system menu */
2391 SetWindowStyle(hwnd
,
2395 hSysMenu
= GetSystemMenu(hwnd
,
2397 if (hSysMenu
!= NULL
)
2399 /* Disable all items that are not relevant */
2400 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2402 EnableMenuItem(hSysMenu
,
2404 MF_BYCOMMAND
| MF_GRAYED
);
2407 EnableMenuItem(hSysMenu
,
2410 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2412 /* Display the system menu */
2413 uId
= ITrayWindowImpl_TrackMenu(This
,
2417 This
->Position
!= ABE_TOP
,
2421 SendMessage(This
->hWnd
,
2428 /* revert the system menu window style */
2429 SetWindowStyle(hwnd
,
2440 case WM_NCRBUTTONUP
:
2441 /* We want the user to be able to get a context menu even on the nonclient
2442 area (including the sizing border)! */
2443 uMsg
= WM_CONTEXTMENU
;
2444 wParam
= (WPARAM
)hwnd
;
2447 case WM_CONTEXTMENU
:
2449 POINT pt
, *ppt
= NULL
;
2450 HWND hWndExclude
= NULL
;
2452 /* Check if the administrator has forbidden access to context menus */
2453 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2456 pt
.x
= (SHORT
)LOWORD(lParam
);
2457 pt
.y
= (SHORT
)HIWORD(lParam
);
2459 if (pt
.x
!= -1 || pt
.y
!= -1)
2462 hWndExclude
= This
->hwndStart
;
2464 if ((HWND
)wParam
== This
->hwndStart
)
2466 /* Make sure we can't track the context menu if the start
2467 menu is currently being shown */
2468 if (!(SendMessage(This
->hwndStart
,
2473 ITrayWindowImpl_TrackCtxMenu(This
,
2474 &StartMenuBtnCtxMenu
,
2477 This
->Position
== ABE_BOTTOM
,
2483 /* See if the context menu should be handled by the task band site */
2484 if (ppt
!= NULL
&& This
->TrayBandSite
!= NULL
)
2487 POINT ptClient
= *ppt
;
2489 /* Convert the coordinates to client-coordinates */
2490 MapWindowPoints(NULL
,
2495 hWndAtPt
= ChildWindowFromPoint(This
->hWnd
,
2497 if (hWndAtPt
!= NULL
&&
2498 (hWndAtPt
== This
->hwndRebar
|| IsChild(This
->hwndRebar
,
2501 /* Check if the user clicked on the task switch window */
2503 MapWindowPoints(NULL
,
2508 hWndAtPt
= ChildWindowFromPointEx(This
->hwndRebar
,
2510 CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2511 if (hWndAtPt
== This
->hwndTaskSwitch
)
2512 goto HandleTrayContextMenu
;
2514 /* Forward the message to the task band site */
2515 ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2523 goto HandleTrayContextMenu
;
2527 HandleTrayContextMenu
:
2528 /* Tray the default tray window context menu */
2529 ITrayWindowImpl_TrackCtxMenu(This
,
2542 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2543 the rebar control! But we shouldn't forward messages that the band
2544 site doesn't handle, such as other controls (start button, tray window */
2545 if (This
->TrayBandSite
== NULL
||
2546 !SUCCEEDED(ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2553 const NMHDR
*nmh
= (const NMHDR
*)lParam
;
2555 if (nmh
->hwndFrom
== This
->hwndTrayNotify
)
2560 /* Cause all controls to be aligned */
2561 PostMessage(This
->hWnd
,
2572 case WM_NCLBUTTONDBLCLK
:
2574 /* We "handle" this message so users can't cause a weird maximize/restore
2575 window animation when double-clicking the tray window! */
2577 /* We should forward mouse messages to child windows here.
2578 Right now, this is only clock double-click */
2580 if (TrayNotify_GetClockRect(This
->hwndTrayNotify
, &rcClock
))
2583 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2584 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2585 if (PtInRect(&rcClock
, ptClick
))
2586 LaunchCPanel(NULL
, TEXT("timedate.cpl"));
2593 LPCREATESTRUCT CreateStruct
= (LPCREATESTRUCT
)lParam
;
2594 This
= (ITrayWindowImpl
*)CreateStruct
->lpCreateParams
;
2596 if (InterlockedCompareExchangePointer((PVOID
*)&This
->hWnd
,
2600 /* Somebody else was faster... */
2604 SetWindowLongPtr(hwnd
,
2608 return ITrayWindowImpl_NCCreate(This
);
2612 ITrayWindowImpl_Create(This
);
2616 ITrayWindowImpl_Destroy(This
);
2619 case WM_APP_TRAYDESTROY
:
2620 DestroyWindow(hwnd
);
2623 case TWM_OPENSTARTMENU
:
2626 HRESULT hr
= IUnknown_GetWindow((IUnknown
*)This
->StartMenuPopup
, &hwndStartMenu
);
2630 if (IsWindowVisible(hwndStartMenu
))
2631 SetWindowPos(hwndStartMenu
, 0,0,0,0,0, SWP_HIDEWINDOW
| SWP_NOACTIVATE
| SWP_NOMOVE
| SWP_NOZORDER
);
2633 SendMessage(This
->hWnd
, WM_COMMAND
, MAKEWPARAM(BN_CLICKED
, IDC_STARTBTN
), (LPARAM
)This
->hwndStart
);
2638 if ((HWND
)lParam
== This
->hwndStart
)
2640 PopupStartMenu(This
);
2644 if (This
->TrayBandSite
== NULL
||
2645 FAILED(ITrayBandSite_ProcessMessage(This
->TrayBandSite
,
2652 switch (LOWORD(wParam
))
2654 /* FIXME: Handle these commands as well */
2655 case IDM_TASKBARANDSTARTMENU
:
2657 ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This
));
2663 case IDM_HELPANDSUPPORT
:
2665 /* TODO: Implement properly */
2667 LPCWSTR strSite
= L
"http://www.reactos.org/";
2669 /* TODO: Make localizable */
2670 LPCWSTR strCaption
= L
"Sorry";
2671 LPCWSTR strMessage
= L
"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed.";
2672 WCHAR tmpMessage
[512];
2674 /* TODO: Read from the registry */
2675 LPCWSTR strVerb
= NULL
; /* default */
2676 LPCWSTR strPath
= strSite
;
2677 LPCWSTR strParams
= NULL
;
2679 /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */
2680 int result
= (int) ShellExecuteW(hwnd
, strVerb
, strPath
, strParams
, NULL
, SW_SHOWNORMAL
);
2683 StringCchPrintfW(tmpMessage
, 512, strMessage
, strSite
, result
);
2684 MessageBoxExW(hwnd
, tmpMessage
, strCaption
, MB_OK
, 0);
2691 ITrayWindowImpl_DisplayRunFileDlg(This
);
2695 /* FIXME: Handle these commands as well */
2696 case IDM_SYNCHRONIZE
:
2698 case IDM_DISCONNECT
:
2699 case IDM_UNDOCKCOMPUTER
:
2705 EXITWINDLG ExitWinDlg
;
2707 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
2708 ExitWinDlg
= (EXITWINDLG
)GetProcAddress(hShell32
, (LPCSTR
)60);
2724 Ret
= DefWindowProc(hwnd
,
2734 * Tray Window Context Menu
2738 CreateTrayWindowContextMenu(IN HWND hWndOwner
,
2739 IN PVOID
*ppcmContext
,
2740 IN PVOID Context OPTIONAL
)
2742 ITrayWindowImpl
*This
= (ITrayWindowImpl
*)Context
;
2743 IContextMenu
*pcm
= NULL
;
2746 hPopup
= LoadPopupMenu(hExplorerInstance
,
2747 MAKEINTRESOURCE(IDM_TRAYWND
));
2751 if (SHRestricted(REST_CLASSICSHELL
) != 0)
2758 CheckMenuItem(hPopup
,
2760 MF_BYCOMMAND
| (This
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
2762 if (This
->TrayBandSite
!= NULL
)
2764 if (SUCCEEDED(ITrayBandSite_AddContextMenus(This
->TrayBandSite
,
2772 TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
2773 *(IContextMenu
**)ppcmContext
= pcm
;
2782 OnTrayWindowContextMenuCommand(IN HWND hWndOwner
,
2784 IN PVOID pcmContext OPTIONAL
,
2785 IN PVOID Context OPTIONAL
)
2787 ITrayWindowImpl
*This
= (ITrayWindowImpl
*)Context
;
2788 IContextMenu
*pcm
= (IContextMenu
*)pcmContext
;
2792 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
2794 CMINVOKECOMMANDINFO cmici
= {0};
2798 /* Setup and invoke the shell command */
2799 cmici
.cbSize
= sizeof(cmici
);
2800 cmici
.hwnd
= hWndOwner
;
2801 cmici
.lpVerb
= (LPCSTR
)MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
2802 cmici
.nShow
= SW_NORMAL
;
2804 IContextMenu_InvokeCommand(pcm
,
2810 ITrayWindow_ExecContextMenuCmd(ITrayWindow_from_impl(This
),
2816 IContextMenu_Release(pcm
);
2819 static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu
= {
2820 CreateTrayWindowContextMenu
,
2821 OnTrayWindowContextMenuCommand
2824 /*****************************************************************************/
2827 RegisterTrayWindowClass(VOID
)
2832 if (!RegisterTrayNotifyWndClass())
2835 wcTrayWnd
.style
= CS_DBLCLKS
;
2836 wcTrayWnd
.lpfnWndProc
= TrayWndProc
;
2837 wcTrayWnd
.cbClsExtra
= 0;
2838 wcTrayWnd
.cbWndExtra
= sizeof(ITrayWindowImpl
*);
2839 wcTrayWnd
.hInstance
= hExplorerInstance
;
2840 wcTrayWnd
.hIcon
= NULL
;
2841 wcTrayWnd
.hCursor
= LoadCursor(NULL
,
2843 wcTrayWnd
.hbrBackground
= (HBRUSH
)(COLOR_3DFACE
+ 1);
2844 wcTrayWnd
.lpszMenuName
= NULL
;
2845 wcTrayWnd
.lpszClassName
= szTrayWndClass
;
2847 Ret
= RegisterClass(&wcTrayWnd
) != 0;
2850 UnregisterTrayNotifyWndClass();
2856 UnregisterTrayWindowClass(VOID
)
2858 UnregisterTrayNotifyWndClass();
2860 UnregisterClass(szTrayWndClass
,
2865 CreateTrayWindow(VOID
)
2867 ITrayWindowImpl
*This
;
2868 ITrayWindow
*TrayWindow
;
2870 This
= ITrayWindowImpl_Construct();
2873 TrayWindow
= ITrayWindow_from_impl(This
);
2875 ITrayWindowImpl_Open(TrayWindow
);
2877 g_TrayWindow
= This
;
2886 TrayProcessMessages(IN OUT ITrayWindow
*Tray
)
2888 ITrayWindowImpl
*This
;
2891 This
= impl_from_ITrayWindow(Tray
);
2893 /* FIXME: We should keep a reference here... */
2895 while (PeekMessage(&Msg
,
2901 if (Msg
.message
== WM_QUIT
)
2904 if (This
->StartMenuBand
== NULL
||
2905 IMenuBand_IsMenuMessage(This
->StartMenuBand
,
2908 TranslateMessage(&Msg
);
2909 DispatchMessage(&Msg
);
2915 TrayMessageLoop(IN OUT ITrayWindow
*Tray
)
2917 ITrayWindowImpl
*This
;
2921 This
= impl_from_ITrayWindow(Tray
);
2923 /* FIXME: We should keep a reference here... */
2927 Ret
= GetMessage(&Msg
,
2932 if (!Ret
|| Ret
== -1)
2935 if (Msg
.message
== WM_HOTKEY
)
2939 case IDHK_RUN
: /* Win+R */
2940 ITrayWindowImpl_DisplayRunFileDlg(This
);
2945 if (This
->StartMenuBand
== NULL
||
2946 IMenuBand_IsMenuMessage(This
->StartMenuBand
,
2949 TranslateMessage(&Msg
);
2950 DispatchMessage(&Msg
);
2958 * NOTE: This is a very windows-specific COM interface used by SHCreateDesktop()!
2959 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2960 * The reason we implement it is because we have to use SHCreateDesktop() so
2961 * that the shell provides the desktop window and all the features that come
2962 * with it (especially positioning of desktop icons)
2965 static HRESULT STDMETHODCALLTYPE
2966 ITrayWindowImpl_IShellDesktopTray_QueryInterface(IN OUT IShellDesktopTray
*iface
,
2970 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2971 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
2973 TRACE("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid
, ppvObj
);
2974 return ITrayWindowImpl_QueryInterface(tray
,
2979 static ULONG STDMETHODCALLTYPE
2980 ITrayWindowImpl_IShellDesktopTray_Release(IN OUT IShellDesktopTray
*iface
)
2982 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2983 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
2985 TRACE("IShellDesktopTray::Release()\n");
2986 return ITrayWindowImpl_Release(tray
);
2989 static ULONG STDMETHODCALLTYPE
2990 ITrayWindowImpl_IShellDesktopTray_AddRef(IN OUT IShellDesktopTray
*iface
)
2992 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
2993 ITrayWindow
*tray
= ITrayWindow_from_impl(This
);
2995 TRACE("IShellDesktopTray::AddRef()\n");
2996 return ITrayWindowImpl_AddRef(tray
);
2999 static ULONG STDMETHODCALLTYPE
3000 ITrayWindowImpl_IShellDesktopTray_GetState(IN OUT IShellDesktopTray
*iface
)
3002 /* FIXME: Return ABS_ flags? */
3003 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3007 static HRESULT STDMETHODCALLTYPE
3008 ITrayWindowImpl_IShellDesktopTray_GetTrayWindow(IN OUT IShellDesktopTray
*iface
,
3009 OUT HWND
*phWndTray
)
3011 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
3012 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
3013 *phWndTray
= This
->hWnd
;
3017 static HRESULT STDMETHODCALLTYPE
3018 ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow(IN OUT IShellDesktopTray
*iface
,
3019 IN HWND hWndDesktop
)
3021 ITrayWindowImpl
*This
= impl_from_IShellDesktopTray(iface
);
3022 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
3024 This
->hWndDesktop
= hWndDesktop
;
3028 static HRESULT STDMETHODCALLTYPE
3029 ITrayWindowImpl_IShellDesktopTray_Unknown(IN OUT IShellDesktopTray
*iface
,
3030 IN DWORD dwUnknown1
,
3031 IN DWORD dwUnknown2
)
3033 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
3037 static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl
=
3040 ITrayWindowImpl_IShellDesktopTray_QueryInterface
,
3041 ITrayWindowImpl_IShellDesktopTray_AddRef
,
3042 ITrayWindowImpl_IShellDesktopTray_Release
,
3043 /*** IShellDesktopTray ***/
3044 ITrayWindowImpl_IShellDesktopTray_GetState
,
3045 ITrayWindowImpl_IShellDesktopTray_GetTrayWindow
,
3046 ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow
,
3047 ITrayWindowImpl_IShellDesktopTray_Unknown
3051 ITrayWindowImpl_RaiseStartButton(ITrayWindowImpl
* This
)
3053 SendMessageW(This
->hwndStart
, BM_SETSTATE
, FALSE
, 0);
3058 Tray_OnStartMenuDismissed()
3060 return ITrayWindowImpl_RaiseStartButton(g_TrayWindow
);