4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
6 * this library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * this library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <commoncontrols.h>
24 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
);
26 #define WM_APP_TRAYDESTROY (WM_APP + 0x100)
28 #define TIMER_ID_AUTOHIDE 1
29 #define TIMER_ID_MOUSETRACK 2
30 #define MOUSETRACK_INTERVAL 100
31 #define AUTOHIDE_DELAY_HIDE 2000
32 #define AUTOHIDE_DELAY_SHOW 50
33 #define AUTOHIDE_INTERVAL_ANIMATING 10
35 #define AUTOHIDE_SPEED_SHOW 10
36 #define AUTOHIDE_SPEED_HIDE 1
38 #define AUTOHIDE_HIDDEN 0
39 #define AUTOHIDE_SHOWING 1
40 #define AUTOHIDE_SHOWN 2
41 #define AUTOHIDE_HIDING 3
43 #define IDHK_RUN 0x1f4
44 #define IDHK_MINIMIZE_ALL 0x1f5
45 #define IDHK_RESTORE_ALL 0x1f6
46 #define IDHK_HELP 0x1f7
47 #define IDHK_EXPLORE 0x1f8
48 #define IDHK_FIND 0x1f9
49 #define IDHK_FIND_COMPUTER 0x1fa
50 #define IDHK_NEXT_TASK 0x1fb
51 #define IDHK_PREV_TASK 0x1fc
52 #define IDHK_SYS_PROPERTIES 0x1fd
53 #define IDHK_DESKTOP 0x1fe
54 #define IDHK_PAGER 0x1ff
56 static LONG TrayWndCount
= 0;
58 static const WCHAR szTrayWndClass
[] = TEXT("Shell_TrayWnd");
64 const GUID IID_IShellDesktopTray
= { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
67 : public CContainedWindow
69 HIMAGELIST m_ImageList
;
74 CStartButton(CMessageMap
*pObject
, DWORD dwMsgMapID
)
75 : CContainedWindow(pObject
, dwMsgMapID
)
79 virtual ~CStartButton()
81 if (m_ImageList
!= NULL
)
82 ImageList_Destroy(m_ImageList
);
98 VOID
UpdateSize(IN HBITMAP hbmStart
= NULL
)
100 SIZE Size
= { 0, 0 };
102 if (m_ImageList
== NULL
||
103 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
105 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
);
106 Size
.cy
= 2 * GetSystemMetrics(SM_CYEDGE
);
108 if (hbmStart
== NULL
)
110 hbmStart
= (HBITMAP
) SendMessageW(BM_GETIMAGE
, IMAGE_BITMAP
, 0);
113 if (hbmStart
!= NULL
)
117 if (GetObject(hbmStart
, sizeof(bmp
), &bmp
) != 0)
119 Size
.cx
+= bmp
.bmWidth
;
120 Size
.cy
+= max(bmp
.bmHeight
, GetSystemMetrics(SM_CYCAPTION
));
124 /* Huh?! Shouldn't happen... */
131 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
132 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
136 /* Save the size of the start button */
140 BOOL
CreateImageList()
145 if (m_ImageList
!= NULL
)
148 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
149 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
151 /* Load the start button icon and create a image list for it */
152 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
153 MAKEINTRESOURCE(IDI_START
),
157 LR_SHARED
| LR_DEFAULTCOLOR
);
159 if (hIconStart
== NULL
)
162 m_ImageList
= ImageList_Create(IconSize
.cx
,
164 ILC_COLOR32
| ILC_MASK
,
166 if (m_ImageList
== NULL
)
169 int s
= ImageList_ReplaceIcon(m_ImageList
, -1, hIconStart
);
172 /* Failed to add the icon! */
173 ImageList_Destroy(m_ImageList
);
182 HBITMAP
CreateBitmap()
184 WCHAR szStartCaption
[32];
187 HDC hDCScreen
= NULL
;
188 SIZE Size
, SmallIcon
;
189 HBITMAP hbmpOld
, hbmp
= NULL
;
190 HBITMAP hBitmap
= NULL
;
196 /* NOTE: this is the backwards compatibility code that is used if the
197 Common Controls Version 6.0 are not available! */
199 if (!LoadString(hExplorerInstance
,
202 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
207 /* Load the start button icon */
208 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
209 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
210 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
211 MAKEINTRESOURCE(IDI_START
),
215 LR_SHARED
| LR_DEFAULTCOLOR
);
217 hDCScreen
= GetDC(NULL
);
218 if (hDCScreen
== NULL
)
221 hDC
= CreateCompatibleDC(hDCScreen
);
225 hFontOld
= (HFONT
) SelectObject(hDC
, m_Font
);
227 Ret
= GetTextExtentPoint32(hDC
,
229 _tcslen(szStartCaption
),
232 SelectObject(hDC
, hFontOld
);
236 /* Make sure the height is at least the size of a caption icon. */
237 if (hIconStart
!= NULL
)
238 Size
.cx
+= SmallIcon
.cx
+ 4;
239 Size
.cy
= max(Size
.cy
, SmallIcon
.cy
);
241 /* Create the bitmap */
242 hbmp
= CreateCompatibleBitmap(hDCScreen
,
248 /* Caluclate the button rect */
251 rcButton
.right
= Size
.cx
;
252 rcButton
.bottom
= Size
.cy
;
254 /* Draw the button */
255 hbmpOld
= (HBITMAP
) SelectObject(hDC
, hbmp
);
257 Flags
= DC_TEXT
| DC_INBUTTON
;
258 if (hIconStart
!= NULL
)
261 DrawCaptionTemp(NULL
,
269 SelectObject(hDC
, hbmpOld
);
274 /* We successfully created the bitmap! */
279 if (hDCScreen
!= NULL
)
281 ReleaseDC(NULL
, hDCScreen
);
295 NONCLIENTMETRICS ncm
;
297 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
301 /* Get the system fonts, we use the caption font, always bold, though. */
302 ncm
.cbSize
= sizeof(ncm
);
303 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
305 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
306 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
310 SendMessage(WM_SETFONT
, (WPARAM
) m_Font
, FALSE
);
312 if (CreateImageList())
314 BUTTON_IMAGELIST bil
;
316 /* Try to set the start button image. this requires the Common
317 Controls 6.0 to be present (XP and later) */
318 bil
.himl
= m_ImageList
;
319 bil
.margin
.left
= bil
.margin
.right
= 1;
320 bil
.margin
.top
= bil
.margin
.bottom
= 1;
321 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
323 if (SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
))
325 /* We're using the image list, remove the BS_BITMAP style and
326 don't center it horizontally */
327 SetWindowStyle(m_hWnd
, BS_BITMAP
| BS_RIGHT
, 0);
333 /* Fall back to the deprecated method on older systems that don't
334 support Common Controls 6.0 */
335 ImageList_Destroy(m_ImageList
);
339 HBITMAP hbmStart
= CreateBitmap();
340 if (hbmStart
!= NULL
)
342 UpdateSize(hbmStart
);
344 HBITMAP hbmOld
= (HBITMAP
) SendMessageW(BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbmStart
);
347 DeleteObject(hbmOld
);
353 public CComCoClass
<CTrayWindow
>,
354 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
355 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
357 public IShellDesktopTray
359 CStartButton m_StartButton
;
361 CComPtr
<IMenuBand
> m_StartMenuBand
;
362 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
374 CTrayNotifyWnd
* m_TrayNotifyInstance
;
378 HMONITOR m_PreviousMonitor
;
379 DWORD m_DraggingPosition
;
380 HMONITOR m_DraggingMonitor
;
385 HWND m_TrayPropertiesOwner
;
386 HWND m_RunFileDlgOwner
;
388 UINT m_AutoHideState
;
389 SIZE m_AutoHideOffset
;
390 TRACKMOUSEEVENT m_MouseTrackingInfo
;
392 HDPA m_ShellServices
;
395 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
403 DWORD AlwaysOnTop
: 1;
404 DWORD SmSmallIcons
: 1;
409 DWORD InSizeMove
: 1;
410 DWORD IsDragging
: 1;
411 DWORD NewPosSize
: 1;
417 m_StartButton(this, 1),
427 m_PreviousMonitor(NULL
),
428 m_DraggingPosition(0),
429 m_DraggingMonitor(NULL
),
430 m_TrayPropertiesOwner(NULL
),
431 m_RunFileDlgOwner(NULL
),
432 m_AutoHideState(NULL
),
433 m_ShellServices(NULL
),
436 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
437 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
438 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
439 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
442 virtual ~CTrayWindow()
444 if (m_ShellServices
!= NULL
)
446 ShutdownShellServices(m_ShellServices
);
447 m_ShellServices
= NULL
;
450 if (m_CaptionFont
!= NULL
)
452 DeleteObject(m_CaptionFont
);
453 m_CaptionFont
= NULL
;
458 DeleteObject(m_Font
);
464 CloseThemeData(m_Theme
);
468 if (InterlockedDecrement(&TrayWndCount
) == 0)
476 BOOL
UpdateNonClientMetrics()
478 NONCLIENTMETRICS ncm
;
479 ncm
.cbSize
= sizeof(ncm
);
480 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
483 DeleteObject(m_Font
);
485 m_Font
= CreateFontIndirect(&ncm
.lfMessageFont
);
492 VOID
SetWindowsFont()
494 if (m_TrayNotify
!= NULL
)
496 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
500 HMONITOR
GetScreenRectFromRect(
507 mi
.cbSize
= sizeof(mi
);
508 hMon
= MonitorFromRect(pRect
,
514 *pRect
= mi
.rcMonitor
;
520 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
521 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
529 HMONITOR
GetMonitorFromRect(
530 IN
const RECT
*pRect
)
534 /* In case the monitor sizes or saved sizes differ a bit (probably
535 not a lot, only so the tray window overlaps into another monitor
536 now), minimize the risk that we determine a wrong monitor by
537 using the center point of the tray window if we can't determine
538 it using the rectangle. */
539 hMon
= MonitorFromRect(pRect
,
540 MONITOR_DEFAULTTONULL
);
545 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
546 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
548 /* be less error-prone, find the nearest monitor */
549 hMon
= MonitorFromPoint(pt
,
550 MONITOR_DEFAULTTONEAREST
);
556 HMONITOR
GetScreenRect(
557 IN HMONITOR hMonitor
,
560 HMONITOR hMon
= NULL
;
562 if (hMonitor
!= NULL
)
566 mi
.cbSize
= sizeof(mi
);
567 if (!GetMonitorInfo(hMonitor
,
570 /* Hm, the monitor is gone? Try to find a monitor where it
571 could be located now */
572 hMon
= GetMonitorFromRect(
575 !GetMonitorInfo(hMon
,
583 *pRect
= mi
.rcMonitor
;
590 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
591 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
597 VOID
MakeTrayRectWithSize(IN DWORD Position
,
598 IN
const SIZE
*pTraySize
,
604 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
608 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
612 pRect
->left
= pRect
->right
- pTraySize
->cx
;
617 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
622 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
623 IN
const RECT
*pScreen
,
624 IN
const SIZE
*pTraySize OPTIONAL
,
627 if (pTraySize
== NULL
)
628 pTraySize
= &m_TraySize
;
632 /* Move the border outside of the screen */
634 GetSystemMetrics(SM_CXEDGE
),
635 GetSystemMetrics(SM_CYEDGE
));
637 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
640 BOOL
IsPosHorizontal()
642 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
645 HMONITOR
CalculateValidSize(
654 //Horizontal = IsPosHorizontal();
656 szWnd
.cx
= pRect
->right
- pRect
->left
;
657 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
660 hMon
= GetScreenRectFromRect(
662 MONITOR_DEFAULTTONEAREST
);
664 /* Calculate the maximum size of the tray window and limit the window
665 size to half of the screen's size. */
666 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
667 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
668 if (szWnd
.cx
> szMax
.cx
)
670 if (szWnd
.cy
> szMax
.cy
)
673 /* FIXME - calculate */
675 GetTrayRectFromScreenRect(
686 GetMinimumWindowSize(
691 AdjustWindowRectEx(&rcMin
,
692 GetWindowLong(m_hWnd
,
695 GetWindowLong(m_hWnd
,
703 DWORD
GetDraggingRectFromPt(
706 OUT HMONITOR
*phMonitor
)
708 HMONITOR hMon
, hMonNew
;
709 DWORD PosH
, PosV
, Pos
;
710 SIZE DeltaPt
, ScreenOffset
;
716 /* Determine the screen rectangle */
717 hMon
= MonitorFromPoint(pt
,
718 MONITOR_DEFAULTTONULL
);
724 mi
.cbSize
= sizeof(mi
);
725 if (!GetMonitorInfo(hMon
,
729 goto GetPrimaryScreenRect
;
732 /* make left top corner of the screen zero based to
733 make calculations easier */
734 pt
.x
-= mi
.rcMonitor
.left
;
735 pt
.y
-= mi
.rcMonitor
.top
;
737 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
738 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
739 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
740 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
744 GetPrimaryScreenRect
:
747 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
748 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
751 /* Calculate the nearest screen border */
752 if (pt
.x
< rcScreen
.right
/ 2)
759 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
763 if (pt
.y
< rcScreen
.bottom
/ 2)
770 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
774 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
776 /* Fix the screen origin to be relative to the primary monitor again */
777 OffsetRect(&rcScreen
,
781 RECT rcPos
= m_TrayRects
[Pos
];
783 hMonNew
= GetMonitorFromRect(&rcPos
);
788 /* Recalculate the rectangle, we're dragging to another monitor.
789 We don't need to recalculate the rect on single monitor systems. */
790 szTray
.cx
= rcPos
.right
- rcPos
.left
;
791 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
793 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
796 pRect
->left
+= m_AutoHideOffset
.cx
;
797 pRect
->right
+= m_AutoHideOffset
.cx
;
798 pRect
->top
+= m_AutoHideOffset
.cy
;
799 pRect
->bottom
+= m_AutoHideOffset
.cy
;
805 /* The user is dragging the tray window on the same monitor. We don't need
806 to recalculate the rectangle */
810 pRect
->left
+= m_AutoHideOffset
.cx
;
811 pRect
->right
+= m_AutoHideOffset
.cx
;
812 pRect
->top
+= m_AutoHideOffset
.cy
;
813 pRect
->bottom
+= m_AutoHideOffset
.cy
;
822 DWORD
GetDraggingRectFromRect(
824 OUT HMONITOR
*phMonitor
)
828 /* Calculate the center of the rectangle. We call
829 GetDraggingRectFromPt to calculate a valid
830 dragging rectangle */
831 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
832 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
834 return GetDraggingRectFromPt(
840 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
846 rcTray
.left
= pwp
->x
;
848 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
849 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
852 rcTray
.left
-= m_AutoHideOffset
.cx
;
853 rcTray
.right
-= m_AutoHideOffset
.cx
;
854 rcTray
.top
-= m_AutoHideOffset
.cy
;
855 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
858 if (!EqualRect(&rcTray
,
859 &m_TrayRects
[m_DraggingPosition
]))
861 /* Recalculate the rectangle, the user dragged the tray
862 window to another monitor or the window was somehow else
864 m_DraggingPosition
= GetDraggingRectFromRect(
867 //m_TrayRects[DraggingPosition] = rcTray;
870 //Monitor = CalculateValidSize(
874 m_Monitor
= m_DraggingMonitor
;
875 m_Position
= m_DraggingPosition
;
878 m_TrayRects
[m_Position
] = rcTray
;
881 else if (GetWindowRect(m_hWnd
, &rcTray
))
885 if (!(pwp
->flags
& SWP_NOMOVE
))
887 rcTray
.left
= pwp
->x
;
891 if (!(pwp
->flags
& SWP_NOSIZE
))
893 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
894 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
897 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
899 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
906 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
911 rcTray
.left
-= m_AutoHideOffset
.cx
;
912 rcTray
.right
-= m_AutoHideOffset
.cx
;
913 rcTray
.top
-= m_AutoHideOffset
.cy
;
914 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
916 m_TrayRects
[m_Position
] = rcTray
;
920 /* If the user isn't resizing the tray window we need to make sure the
921 new size or position is valid. this is to prevent changes to the window
922 without user interaction. */
923 rcTray
= m_TrayRects
[m_Position
];
927 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
928 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
932 rcTray
.left
+= m_AutoHideOffset
.cx
;
933 rcTray
.right
+= m_AutoHideOffset
.cx
;
934 rcTray
.top
+= m_AutoHideOffset
.cy
;
935 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
938 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
939 pwp
->x
= rcTray
.left
;
941 pwp
->cx
= m_TraySize
.cx
;
942 pwp
->cy
= m_TraySize
.cy
;
946 VOID
ApplyClipping(IN BOOL Clip
)
948 RECT rcClip
, rcWindow
;
951 if (GetWindowRect(m_hWnd
, &rcWindow
))
953 /* Disable clipping on systems with only one monitor */
954 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
961 GetScreenRect(m_Monitor
, &rcClip
);
963 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
972 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
977 /* Set the clipping region or make sure the window isn't clipped
978 by disabling it explicitly. */
979 SetWindowRgn(m_hWnd
, hClipRgn
, TRUE
);
983 VOID
ResizeWorkArea()
985 #if !WIN7_COMPAT_MODE
986 RECT rcTray
, rcWorkArea
;
988 /* If monitor has changed then fix the previous monitors work area */
989 if (m_PreviousMonitor
!= m_Monitor
)
991 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
992 SystemParametersInfo(SPI_SETWORKAREA
,
998 rcTray
= m_TrayRects
[m_Position
];
1000 GetScreenRect(m_Monitor
, &rcWorkArea
);
1001 m_PreviousMonitor
= m_Monitor
;
1003 /* If AutoHide is false then change the workarea to exclude the area that
1004 the taskbar covers. */
1010 rcWorkArea
.top
= rcTray
.bottom
;
1013 rcWorkArea
.left
= rcTray
.right
;
1016 rcWorkArea
.right
= rcTray
.left
;
1019 rcWorkArea
.bottom
= rcTray
.top
;
1024 SystemParametersInfo(SPI_SETWORKAREA
,
1031 VOID
CheckTrayWndPosition()
1035 rcTray
= m_TrayRects
[m_Position
];
1039 rcTray
.left
+= m_AutoHideOffset
.cx
;
1040 rcTray
.right
+= m_AutoHideOffset
.cx
;
1041 rcTray
.top
+= m_AutoHideOffset
.cy
;
1042 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1045 /* Move the tray window */
1049 rcTray
.right
- rcTray
.left
,
1050 rcTray
.bottom
- rcTray
.top
,
1055 ApplyClipping(TRUE
);
1058 typedef struct _TW_STUCKRECTS2
1066 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1068 VOID
RegLoadSettings()
1073 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1074 DWORD cbSize
= sizeof(sr
);
1075 SIZE StartBtnSize
= m_StartButton
.GetSize();
1077 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1078 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1079 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1080 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1082 if (SHGetValue(hkExplorer
,
1083 TEXT("StuckRects2"),
1087 &cbSize
) == ERROR_SUCCESS
&&
1088 sr
.cbSize
== sizeof(sr
))
1090 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1091 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1092 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1093 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1095 /* FIXME: Are there more flags? */
1097 #if WIN7_COMPAT_MODE
1098 m_Position
= ABE_LEFT
;
1100 if (sr
.Position
> ABE_BOTTOM
)
1101 m_Position
= ABE_BOTTOM
;
1103 m_Position
= sr
.Position
;
1106 /* Try to find out which monitor the tray window was located on last.
1107 Here we're only interested in the monitor screen that we think
1108 is the last one used. We're going to determine on which monitor
1109 we really are after calculating the docked position. */
1111 GetScreenRectFromRect(
1113 MONITOR_DEFAULTTONEAREST
);
1117 m_Position
= ABE_BOTTOM
;
1120 /* Use the minimum size of the taskbar, we'll use the start
1121 button as a minimum for now. Make sure we calculate the
1122 entire window size, not just the client size. However, we
1123 use a thinner border than a standard thick border, so that
1124 the start button and bands are not stuck to the screen border. */
1125 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1126 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1128 /* Use the primary screen by default */
1131 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1132 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1133 GetScreenRectFromRect(
1135 MONITOR_DEFAULTTOPRIMARY
);
1140 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1145 SWP_NOMOVE
| SWP_NOSIZE
);
1147 /* Determine a minimum tray window rectangle. The "client" height is
1148 zero here since we cannot determine an optimal minimum width when
1149 loaded as a vertical tray window. We just need to make sure the values
1150 loaded from the registry are at least. The windows explorer behaves
1151 the same way, it allows the user to save a zero width vertical tray
1152 window, but not a zero height horizontal tray window. */
1153 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1154 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1156 if (WndSize
.cx
< sr
.Size
.cx
)
1157 WndSize
.cx
= sr
.Size
.cx
;
1158 if (WndSize
.cy
< sr
.Size
.cy
)
1159 WndSize
.cy
= sr
.Size
.cy
;
1161 /* Save the calculated size */
1162 m_TraySize
= WndSize
;
1164 /* Calculate all docking rectangles. We need to do this here so they're
1165 initialized and dragging the tray window to another position gives
1167 for (Pos
= ABE_LEFT
;
1171 GetTrayRectFromScreenRect(
1176 // TRACE("m_TrayRects[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, m_TrayRects[Pos].left, m_TrayRects[Pos].top, m_TrayRects[Pos].right, m_TrayRects[Pos].bottom);
1179 /* Determine which monitor we are on. It shouldn't matter which docked
1180 position rectangle we use */
1181 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1186 IN POINT
*ppt OPTIONAL
,
1187 IN HWND hwndExclude OPTIONAL
,
1189 IN BOOL IsContextMenu
)
1191 TPMPARAMS tmp
, *ptmp
= NULL
;
1196 if (hwndExclude
!= NULL
)
1198 /* Get the client rectangle and map it to screen coordinates */
1199 if (::GetClientRect(hwndExclude
,
1201 MapWindowPoints(hwndExclude
,
1203 (LPPOINT
) &tmp
.rcExclude
,
1213 GetClientRect(&tmp
.rcExclude
) &&
1214 MapWindowPoints(m_hWnd
,
1216 (LPPOINT
) &tmp
.rcExclude
,
1224 /* NOTE: TrackPopupMenuEx will eventually align the track position
1225 for us, no need to take care of it here as long as the
1226 coordinates are somewhere within the exclusion rectangle */
1227 pt
.x
= ptmp
->rcExclude
.left
;
1228 pt
.y
= ptmp
->rcExclude
.top
;
1236 tmp
.cbSize
= sizeof(tmp
);
1238 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
1239 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
1241 fuFlags
|= TPM_RIGHTBUTTON
;
1243 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
1245 cmdId
= TrackPopupMenuEx(hMenu
,
1255 HRESULT
TrackCtxMenu(
1256 IN IContextMenu
* contextMenu
,
1257 IN POINT
*ppt OPTIONAL
,
1258 IN HWND hwndExclude OPTIONAL
,
1260 IN PVOID Context OPTIONAL
)
1266 HMENU popup
= CreatePopupMenu();
1271 TRACE("Before Query\n");
1272 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
1273 if (FAILED_UNEXPECTEDLY(hr
))
1275 TRACE("Query failed\n");
1280 TRACE("Before Tracking\n");
1281 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
1285 TRACE("Before InvokeCommand\n");
1286 CMINVOKECOMMANDINFO cmi
= { 0 };
1287 cmi
.cbSize
= sizeof(cmi
);
1288 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
1290 hr
= contextMenu
->InvokeCommand(&cmi
);
1294 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
1302 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1305 SIZE TraySize
, StartSize
;
1306 POINT ptTrayNotify
= { 0, 0 };
1310 m_StartButton
.UpdateSize();
1311 if (prcClient
!= NULL
)
1313 rcClient
= *prcClient
;
1317 if (!GetClientRect(&rcClient
))
1323 Horizontal
= IsPosHorizontal();
1325 /* We're about to resize/move the start button, the rebar control and
1326 the tray notification control */
1327 dwp
= BeginDeferWindowPos(3);
1331 /* Limit the Start button width to the client width, if neccessary */
1332 StartSize
= m_StartButton
.GetSize();
1333 if (StartSize
.cx
> rcClient
.right
)
1334 StartSize
.cx
= rcClient
.right
;
1336 if (m_StartButton
.m_hWnd
!= NULL
)
1338 /* Resize and reposition the button */
1339 dwp
= DeferWindowPos(dwp
,
1340 m_StartButton
.m_hWnd
,
1346 SWP_NOZORDER
| SWP_NOACTIVATE
);
1351 /* Determine the size that the tray notification window needs */
1355 TraySize
.cy
= rcClient
.bottom
;
1359 TraySize
.cx
= rcClient
.right
;
1363 if (m_TrayNotify
!= NULL
&&
1364 SendMessage(m_TrayNotify
,
1365 TNWM_GETMINIMUMSIZE
,
1366 (WPARAM
) Horizontal
,
1367 (LPARAM
) &TraySize
))
1369 /* Move the tray notification window to the desired location */
1371 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1373 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1375 dwp
= DeferWindowPos(dwp
,
1382 SWP_NOZORDER
| SWP_NOACTIVATE
);
1387 /* Resize/Move the rebar control */
1388 if (m_Rebar
!= NULL
)
1390 POINT ptRebar
= { 0, 0 };
1393 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1397 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1398 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1399 szRebar
.cy
= rcClient
.bottom
;
1403 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1404 szRebar
.cx
= rcClient
.right
;
1405 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1408 dwp
= DeferWindowPos(dwp
,
1415 SWP_NOZORDER
| SWP_NOACTIVATE
);
1419 EndDeferWindowPos(dwp
);
1421 if (m_TaskSwitch
!= NULL
)
1423 /* Update the task switch window configuration */
1424 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1428 LRESULT
OnThemeChanged()
1431 CloseThemeData(m_Theme
);
1433 if (IsThemeActive())
1434 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
1438 if (Locked
&& m_Theme
)
1440 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1444 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1446 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1451 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1453 return OnThemeChanged();
1456 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1458 WCHAR szStartCaption
[32];
1460 ((ITrayWindow
*)this)->AddRef();
1462 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1465 InterlockedIncrement(&TrayWndCount
);
1467 if (!LoadString(hExplorerInstance
,
1470 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1472 szStartCaption
[0] = TEXT('\0');
1475 if (m_CaptionFont
== NULL
)
1477 NONCLIENTMETRICS ncm
;
1479 /* Get the system fonts, we use the caption font,
1480 always bold, though. */
1481 ncm
.cbSize
= sizeof(ncm
);
1482 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
1484 if (m_CaptionFont
== NULL
)
1486 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1487 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1492 /* Create the Start button */
1493 m_StartButton
.SubclassWindow(CreateWindowEx(
1497 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1498 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1504 (HMENU
) IDC_STARTBTN
,
1508 if (m_StartButton
.m_hWnd
)
1510 m_StartButton
.Initialize();
1513 /* Load the saved tray window settings */
1516 /* Create and initialize the start menu */
1517 HBITMAP hbmBanner
= LoadBitmap(hExplorerInstance
, MAKEINTRESOURCE(IDB_STARTMENU
));
1518 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
1520 /* Load the tray band site */
1521 if (m_TrayBandSite
!= NULL
)
1523 m_TrayBandSite
.Release();
1526 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
1527 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
1529 /* Create the tray notification window */
1530 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
1532 if (UpdateNonClientMetrics())
1537 /* Move the tray window to the right position and resize it if neccessary */
1538 CheckTrayWndPosition();
1540 /* Align all controls on the tray window */
1541 AlignControls(NULL
);
1543 InitShellServices(&(m_ShellServices
));
1547 m_AutoHideState
= AUTOHIDE_HIDING
;
1548 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1551 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
1552 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
1553 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
1554 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
1555 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
1556 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
1557 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
1558 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
1559 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
1560 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
1561 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
1562 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
1567 HRESULT STDMETHODCALLTYPE
Open()
1571 /* Check if there's already a window created and try to show it.
1572 If it was somehow destroyed just create a new tray window. */
1573 if (m_hWnd
!= NULL
&& IsWindow())
1575 if (!IsWindowVisible(m_hWnd
))
1577 CheckTrayWndPosition();
1579 ShowWindow(SW_SHOW
);
1585 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1587 dwExStyle
|= WS_EX_TOPMOST
;
1589 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1590 WS_BORDER
| WS_THICKFRAME
;
1592 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1593 if (m_Position
!= (DWORD
) -1)
1594 rcWnd
= m_TrayRects
[m_Position
];
1596 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1602 HRESULT STDMETHODCALLTYPE
Close()
1615 HWND STDMETHODCALLTYPE
GetHWND()
1620 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1622 return (m_hWnd
== hWnd
||
1623 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1626 BOOL STDMETHODCALLTYPE
1629 return IsPosHorizontal();
1632 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1634 if (phBoldCaption
!= NULL
)
1635 *phBoldCaption
= m_StartButton
.GetFont();
1637 return m_CaptionFont
;
1640 DWORD WINAPI
TrayPropertiesThread()
1645 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1646 hwnd
= CreateWindowEx(0,
1649 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1652 posRect
.right
- posRect
.left
,
1653 posRect
.bottom
- posRect
.top
,
1659 m_TrayPropertiesOwner
= hwnd
;
1661 DisplayTrayProperties(hwnd
);
1663 m_TrayPropertiesOwner
= NULL
;
1669 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1671 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1673 return This
->TrayPropertiesThread();
1676 HWND STDMETHODCALLTYPE
DisplayProperties()
1680 if (m_TrayPropertiesOwner
)
1682 hTrayProp
= GetLastActivePopup(m_TrayPropertiesOwner
);
1683 if (hTrayProp
!= NULL
&&
1684 hTrayProp
!= m_TrayPropertiesOwner
)
1686 SetForegroundWindow(hTrayProp
);
1691 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1695 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1697 WCHAR szDir
[MAX_PATH
];
1699 if (SHGetSpecialFolderPath(hWndOwner
,
1701 CSIDL_COMMON_STARTMENU
,
1704 ShellExecute(hWndOwner
,
1713 VOID
OpenTaskManager(IN HWND hWndOwner
)
1715 ShellExecute(hWndOwner
,
1717 TEXT("taskmgr.exe"),
1723 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1725 BOOL bHandled
= TRUE
;
1729 case ID_SHELL_CMD_PROPERTIES
:
1730 DisplayProperties();
1733 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1734 OpenCommonStartMenuDirectory(m_hWnd
,
1738 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1739 OpenCommonStartMenuDirectory(m_hWnd
,
1743 case ID_LOCKTASKBAR
:
1744 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1750 case ID_SHELL_CMD_OPEN_TASKMGR
:
1751 OpenTaskManager(m_hWnd
);
1754 case ID_SHELL_CMD_UNDO_ACTION
:
1757 case ID_SHELL_CMD_SHOW_DESKTOP
:
1760 case ID_SHELL_CMD_TILE_WND_H
:
1761 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1764 case ID_SHELL_CMD_TILE_WND_V
:
1765 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1768 case ID_SHELL_CMD_CASCADE_WND
:
1769 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1772 case ID_SHELL_CMD_CUST_NOTIF
:
1775 case ID_SHELL_CMD_ADJUST_DAT
:
1776 //FIXME: Use SHRunControlPanel
1777 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
1781 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1789 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1791 BOOL bPrevLock
= Locked
;
1793 if (Locked
!= bLock
)
1797 if (m_TrayBandSite
!= NULL
)
1799 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1807 if (Locked
&& m_Theme
)
1809 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1813 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1815 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1823 LRESULT
DrawBackground(HDC hdc
)
1828 GetClientRect(&rect
);
1832 GetClientRect(&rect
);
1836 partId
= TBP_BACKGROUNDLEFT
;
1839 partId
= TBP_BACKGROUNDTOP
;
1842 partId
= TBP_BACKGROUNDRIGHT
;
1846 partId
= TBP_BACKGROUNDBOTTOM
;
1850 DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1856 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1858 HDC hdc
= (HDC
) wParam
;
1866 return DrawBackground(hdc
);
1869 int DrawSizer(IN HRGN hRgn
)
1875 GetWindowRect(m_hWnd
, &rect
);
1876 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1878 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1883 backoundPart
= TBP_SIZINGBARLEFT
;
1884 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1887 backoundPart
= TBP_SIZINGBARTOP
;
1888 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1891 backoundPart
= TBP_SIZINGBARRIGHT
;
1892 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1896 backoundPart
= TBP_SIZINGBARBOTTOM
;
1897 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1901 DrawThemeBackground(m_Theme
, hdc
, backoundPart
, 0, &rect
, 0);
1903 ReleaseDC(m_hWnd
, hdc
);
1907 DWORD WINAPI
RunFileDlgThread()
1912 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1914 hwnd
= CreateWindowEx(0,
1917 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1920 posRect
.right
- posRect
.left
,
1921 posRect
.bottom
- posRect
.top
,
1927 m_RunFileDlgOwner
= hwnd
;
1929 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1931 m_RunFileDlgOwner
= NULL
;
1932 ::DestroyWindow(hwnd
);
1937 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1939 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1940 return This
->RunFileDlgThread();
1943 void DisplayRunFileDlg()
1946 if (m_RunFileDlgOwner
)
1948 hRunDlg
= GetLastActivePopup(m_RunFileDlgOwner
);
1949 if (hRunDlg
!= NULL
&&
1950 hRunDlg
!= m_RunFileDlgOwner
)
1952 SetForegroundWindow(hRunDlg
);
1957 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1960 void PopupStartMenu()
1962 if (m_StartMenuPopup
!= NULL
)
1968 if (GetWindowRect(m_StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1973 pt
.x
= rcExclude
.left
;
1974 pt
.y
= rcExclude
.top
;
1975 dwFlags
|= MPPF_TOP
;
1978 pt
.x
= rcExclude
.left
;
1979 pt
.y
= rcExclude
.bottom
;
1980 dwFlags
|= MPPF_BOTTOM
;
1983 pt
.x
= rcExclude
.right
;
1984 pt
.y
= rcExclude
.top
;
1985 dwFlags
|= MPPF_RIGHT
;
1988 pt
.x
= rcExclude
.left
;
1989 pt
.y
= rcExclude
.top
;
1990 dwFlags
|= MPPF_LEFT
;
1994 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1996 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
2001 void ProcessMouseTracking()
2006 UINT state
= m_AutoHideState
;
2009 GetWindowRect(m_hWnd
, &rcCurrent
);
2010 over
= PtInRect(&rcCurrent
, pt
);
2012 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2019 if (state
== AUTOHIDE_HIDING
)
2021 TRACE("AutoHide cancelling hide.\n");
2022 m_AutoHideState
= AUTOHIDE_SHOWING
;
2023 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2025 else if (state
== AUTOHIDE_HIDDEN
)
2027 TRACE("AutoHide starting show.\n");
2028 m_AutoHideState
= AUTOHIDE_SHOWING
;
2029 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2034 if (state
== AUTOHIDE_SHOWING
)
2036 TRACE("AutoHide cancelling show.\n");
2037 m_AutoHideState
= AUTOHIDE_HIDING
;
2038 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2040 else if (state
== AUTOHIDE_SHOWN
)
2042 TRACE("AutoHide starting hide.\n");
2043 m_AutoHideState
= AUTOHIDE_HIDING
;
2044 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2047 KillTimer(TIMER_ID_MOUSETRACK
);
2051 void ProcessAutoHide()
2053 RECT rc
= m_TrayRects
[m_Position
];
2054 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2055 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2057 TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", m_AutoHideState
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, w
, h
);
2059 switch (m_AutoHideState
)
2061 case AUTOHIDE_HIDING
:
2065 m_AutoHideOffset
.cy
= 0;
2066 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2067 if (m_AutoHideOffset
.cx
< -w
)
2068 m_AutoHideOffset
.cx
= -w
;
2071 m_AutoHideOffset
.cx
= 0;
2072 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2073 if (m_AutoHideOffset
.cy
< -h
)
2074 m_AutoHideOffset
.cy
= -h
;
2077 m_AutoHideOffset
.cy
= 0;
2078 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2079 if (m_AutoHideOffset
.cx
> w
)
2080 m_AutoHideOffset
.cx
= w
;
2083 m_AutoHideOffset
.cx
= 0;
2084 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2085 if (m_AutoHideOffset
.cy
> h
)
2086 m_AutoHideOffset
.cy
= h
;
2090 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
2092 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2097 case AUTOHIDE_HIDDEN
:
2102 m_AutoHideOffset
.cx
= -w
;
2103 m_AutoHideOffset
.cy
= 0;
2106 m_AutoHideOffset
.cx
= 0;
2107 m_AutoHideOffset
.cy
= -h
;
2110 m_AutoHideOffset
.cx
= w
;
2111 m_AutoHideOffset
.cy
= 0;
2114 m_AutoHideOffset
.cx
= 0;
2115 m_AutoHideOffset
.cy
= h
;
2119 KillTimer(TIMER_ID_AUTOHIDE
);
2120 m_AutoHideState
= AUTOHIDE_HIDDEN
;
2123 case AUTOHIDE_SHOWING
:
2124 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2126 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2128 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2130 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2134 m_AutoHideOffset
.cx
= 0;
2137 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2139 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2141 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2143 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2147 m_AutoHideOffset
.cy
= 0;
2150 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
2152 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2157 case AUTOHIDE_SHOWN
:
2159 KillTimer(TIMER_ID_AUTOHIDE
);
2160 m_AutoHideState
= AUTOHIDE_SHOWN
;
2164 rc
.left
+= m_AutoHideOffset
.cx
;
2165 rc
.right
+= m_AutoHideOffset
.cx
;
2166 rc
.top
+= m_AutoHideOffset
.cy
;
2167 rc
.bottom
+= m_AutoHideOffset
.cy
;
2169 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
2170 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2173 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2175 /* Load the saved tray window settings */
2178 /* Move the tray window to the right position and resize it if neccessary */
2179 CheckTrayWndPosition();
2181 /* Align all controls on the tray window */
2182 AlignControls(NULL
);
2187 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2191 return TrayNotify_NotifyMsg(m_TrayNotifyInstance
, wParam
, lParam
);
2196 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2204 return DrawSizer((HRGN
) wParam
);
2207 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2209 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2210 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2213 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2220 /* The user may not be able to resize the tray window.
2221 Pretend like the window is not sizeable when the user
2222 clicks on the border. */
2226 SetLastError(ERROR_SUCCESS
);
2227 if (GetClientRect(&rcClient
) &&
2228 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2230 pt
.x
= (SHORT
) LOWORD(lParam
);
2231 pt
.y
= (SHORT
) HIWORD(lParam
);
2233 if (PtInRect(&rcClient
,
2236 /* The user is trying to drag the tray window */
2240 /* Depending on the position of the tray window, allow only
2241 changing the border next to the monitor working area */
2245 if (pt
.y
> rcClient
.bottom
)
2249 if (pt
.x
> rcClient
.right
)
2253 if (pt
.x
< rcClient
.left
)
2258 if (pt
.y
< rcClient
.top
)
2267 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2270 PRECT pRect
= (PRECT
) lParam
;
2272 /* We need to ensure that an application can not accidently
2273 move the tray window (using SetWindowPos). However, we still
2274 need to be able to move the window in case the user wants to
2275 drag the tray window to another position or in case the user
2276 wants to resize the tray window. */
2277 if (!Locked
&& GetCursorPos(&ptCursor
))
2280 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2284 *pRect
= m_TrayRects
[m_Position
];
2288 pRect
->left
+= m_AutoHideOffset
.cx
;
2289 pRect
->right
+= m_AutoHideOffset
.cx
;
2290 pRect
->top
+= m_AutoHideOffset
.cy
;
2291 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2297 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2299 PRECT pRect
= (PRECT
) lParam
;
2303 CalculateValidSize(m_Position
, pRect
);
2307 *pRect
= m_TrayRects
[m_Position
];
2311 pRect
->left
+= m_AutoHideOffset
.cx
;
2312 pRect
->right
+= m_AutoHideOffset
.cx
;
2313 pRect
->top
+= m_AutoHideOffset
.cy
;
2314 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2320 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2322 ChangingWinPos((LPWINDOWPOS
) lParam
);
2326 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2329 InvalidateRect(NULL
, TRUE
);
2330 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2333 /* Clip the tray window on multi monitor systems so the edges can't
2334 overlap into another monitor */
2335 ApplyClipping(TRUE
);
2337 if (!GetClientRect(&rcClient
))
2344 rcClient
.left
= rcClient
.top
= 0;
2345 rcClient
.right
= LOWORD(lParam
);
2346 rcClient
.bottom
= HIWORD(lParam
);
2349 AlignControls(&rcClient
);
2353 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2359 /* Remove the clipping on multi monitor systems while dragging around */
2360 ApplyClipping(FALSE
);
2365 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2370 /* Apply clipping */
2371 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2376 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2382 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2383 The tray window needs to handle this specially, since it normally doesn't have
2386 static const UINT uidDisableItem
[] = {
2397 /* temporarily enable the system menu */
2398 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2400 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2401 if (hSysMenu
!= NULL
)
2403 /* Disable all items that are not relevant */
2404 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2406 EnableMenuItem(hSysMenu
,
2408 MF_BYCOMMAND
| MF_GRAYED
);
2411 EnableMenuItem(hSysMenu
,
2414 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2416 /* Display the system menu */
2420 m_StartButton
.m_hWnd
,
2421 m_Position
!= ABE_TOP
,
2425 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2429 /* revert the system menu window style */
2430 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2440 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2442 /* We want the user to be able to get a context menu even on the nonclient
2443 area (including the sizing border)! */
2444 uMsg
= WM_CONTEXTMENU
;
2445 wParam
= (WPARAM
) m_hWnd
;
2447 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2450 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2452 LRESULT Ret
= FALSE
;
2453 POINT pt
, *ppt
= NULL
;
2454 HWND hWndExclude
= NULL
;
2456 /* Check if the administrator has forbidden access to context menus */
2457 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2460 pt
.x
= (SHORT
) LOWORD(lParam
);
2461 pt
.y
= (SHORT
) HIWORD(lParam
);
2463 if (pt
.x
!= -1 || pt
.y
!= -1)
2466 hWndExclude
= m_StartButton
.m_hWnd
;
2468 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2470 /* Make sure we can't track the context menu if the start
2471 menu is currently being shown */
2472 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2474 CComPtr
<IContextMenu
> ctxMenu
;
2475 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2476 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2481 /* See if the context menu should be handled by the task band site */
2482 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2485 POINT ptClient
= *ppt
;
2487 /* Convert the coordinates to client-coordinates */
2488 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2490 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2491 if (hWndAtPt
!= NULL
&&
2492 (hWndAtPt
== m_Rebar
|| IsChild(m_Rebar
, hWndAtPt
)))
2494 /* Check if the user clicked on the task switch window */
2496 MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2498 hWndAtPt
= ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2499 if (hWndAtPt
== m_TaskSwitch
)
2500 goto HandleTrayContextMenu
;
2502 /* Forward the message to the task band site */
2503 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2506 goto HandleTrayContextMenu
;
2510 HandleTrayContextMenu
:
2511 /* Tray the default tray window context menu */
2512 CComPtr
<IContextMenu
> ctxMenu
;
2513 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2514 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2520 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2522 LRESULT Ret
= FALSE
;
2523 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2524 the rebar control! But we shouldn't forward messages that the band
2525 site doesn't handle, such as other controls (start button, tray window */
2527 HRESULT hr
= E_FAIL
;
2531 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2536 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2538 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2540 if (nmh
->hwndFrom
== m_TrayNotify
)
2545 /* Cause all controls to be aligned */
2546 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2554 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2556 /* We "handle" this message so users can't cause a weird maximize/restore
2557 window animation when double-clicking the tray window! */
2559 /* We should forward mouse messages to child windows here.
2560 Right now, this is only clock double-click */
2562 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2565 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2566 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2567 if (PtInRect(&rcClock
, ptClick
))
2569 //FIXME: use SHRunControlPanel
2570 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2576 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2582 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2585 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2586 if (FAILED_UNEXPECTEDLY(hr
))
2589 if (IsWindowVisible(hwndStartMenu
))
2591 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2601 LRESULT
DoExitWindows()
2603 ExitWindowsDialog(m_hWnd
);
2607 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2610 * TWM_DOEXITWINDOWS is send by the CDesktopBrowserr to us to
2611 * show the shutdown dialog
2613 return DoExitWindows();
2616 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2618 if (wParam
== SC_CLOSE
)
2620 return DoExitWindows();
2627 HRESULT
ExecResourceCmd(int id
)
2629 WCHAR szCommand
[256];
2630 WCHAR
*pszParameters
;
2632 if (!LoadString(hExplorerInstance
,
2635 sizeof(szCommand
) / sizeof(szCommand
[0])))
2640 pszParameters
= wcschr(szCommand
, L
'>');
2647 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, 0);
2651 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2656 DisplayRunFileDlg();
2659 ExecResourceCmd(IDS_HELP_COMMAND
);
2662 ShellExecuteW(0, L
"explore", NULL
, NULL
, NULL
, 1);
2665 SHFindFiles(NULL
, NULL
);
2667 case IDHK_FIND_COMPUTER
:
2668 SHFindComputer(NULL
, NULL
);
2670 case IDHK_SYS_PROPERTIES
:
2671 //FIXME: Use SHRunControlPanel
2672 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
2674 case IDHK_NEXT_TASK
:
2676 case IDHK_PREV_TASK
:
2678 case IDHK_MINIMIZE_ALL
:
2680 case IDHK_RESTORE_ALL
:
2691 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2693 LRESULT Ret
= FALSE
;
2695 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2701 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2703 switch (LOWORD(wParam
))
2705 /* FIXME: Handle these commands as well */
2706 case IDM_TASKBARANDSTARTMENU
:
2707 DisplayProperties();
2711 SHFindFiles(NULL
, NULL
);
2714 case IDM_HELPANDSUPPORT
:
2715 ExecResourceCmd(IDS_HELP_COMMAND
);
2719 DisplayRunFileDlg();
2722 /* FIXME: Handle these commands as well */
2723 case IDM_SYNCHRONIZE
:
2725 case IDM_DISCONNECT
:
2726 case IDM_UNDOCKCOMPUTER
:
2737 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2741 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2747 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2749 if (wParam
== TIMER_ID_MOUSETRACK
)
2751 ProcessMouseTracking();
2753 else if (wParam
== TIMER_ID_AUTOHIDE
)
2762 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2765 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2771 ::GetWindowRect(m_hWnd
, &rc
);
2775 rc
.bottom
- rc
.top
};
2777 as
->rcTarget
.right
- as
->rcTarget
.left
,
2778 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2780 as
->rcActual
.right
- as
->rcActual
.left
,
2781 as
->rcActual
.bottom
- as
->rcActual
.top
};
2784 szWindow
.cx
- szTarget
.cx
,
2785 szWindow
.cy
- szTarget
.cx
,
2791 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2794 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2797 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2798 rc
.left
= rc
.right
- szWindow
.cy
;
2801 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2802 rc
.top
= rc
.bottom
- szWindow
.cy
;
2806 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2813 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2815 BEGIN_MSG_MAP(CTrayWindow
)
2816 if (m_StartMenuBand
!= NULL
)
2823 Msg
.wParam
= wParam
;
2824 Msg
.lParam
= lParam
;
2826 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2831 wParam
= Msg
.wParam
;
2832 lParam
= Msg
.lParam
;
2834 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2835 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2836 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2837 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2838 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2839 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2840 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2841 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2842 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2843 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2844 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2845 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2846 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2847 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2848 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2849 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2850 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2851 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2852 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2853 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2854 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2855 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2856 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2857 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2858 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2859 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2860 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2861 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2862 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2863 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2867 /*****************************************************************************/
2869 VOID
TrayProcessMessages()
2873 /* FIXME: We should keep a reference here... */
2875 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2877 if (Msg
.message
== WM_QUIT
)
2880 if (m_StartMenuBand
== NULL
||
2881 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2883 TranslateMessage(&Msg
);
2884 DispatchMessage(&Msg
);
2889 VOID
TrayMessageLoop()
2894 /* FIXME: We should keep a reference here... */
2898 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2900 if (!Ret
|| Ret
== -1)
2903 if (m_StartMenuBand
== NULL
||
2904 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2906 TranslateMessage(&Msg
);
2907 DispatchMessage(&Msg
);
2915 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2916 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2917 * The reason we implement it is because we have to use SHCreateDesktop() so
2918 * that the shell provides the desktop window and all the features that come
2919 * with it (especially positioning of desktop icons)
2922 virtual ULONG STDMETHODCALLTYPE
GetState()
2924 /* FIXME: Return ABS_ flags? */
2925 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2929 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2931 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2932 *phWndTray
= m_hWnd
;
2936 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2938 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2940 m_DesktopWnd
= hWndDesktop
;
2944 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2946 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2950 virtual HRESULT
RaiseStartButton()
2952 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2958 m_Position
= (DWORD
) -1;
2961 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2963 DECLARE_PROTECT_FINAL_CONSTRUCT()
2964 BEGIN_COM_MAP(CTrayWindow
)
2965 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2966 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2970 class CTrayWindowCtxMenu
:
2971 public CComCoClass
<CTrayWindowCtxMenu
>,
2972 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2976 CComPtr
<CTrayWindow
> TrayWnd
;
2977 CComPtr
<IContextMenu
> pcm
;
2980 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2982 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2983 this->hWndOwner
= hWndOwner
;
2987 virtual HRESULT STDMETHODCALLTYPE
2988 QueryContextMenu(HMENU hPopup
,
2994 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
2997 return HRESULT_FROM_WIN32(GetLastError());
2999 int count
= ::GetMenuItemCount(menubase
);
3001 for (int i
= 0; i
< count
; i
++)
3005 MENUITEMINFOW mii
= { 0 };
3006 mii
.cbSize
= sizeof(mii
);
3007 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3008 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3009 mii
.dwTypeData
= label
;
3010 mii
.cch
= _countof(label
);
3011 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3013 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3015 mii
.fType
|= MFT_RADIOCHECK
;
3017 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3020 ::DestroyMenu(menubase
);
3022 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3029 CheckMenuItem(hPopup
,
3031 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3033 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3035 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3043 WARN("AddContextMenus failed.\n");
3051 virtual HRESULT STDMETHODCALLTYPE
3052 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3054 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3057 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3059 CMINVOKECOMMANDINFO cmici
= { 0 };
3063 /* Setup and invoke the shell command */
3064 cmici
.cbSize
= sizeof(cmici
);
3065 cmici
.hwnd
= hWndOwner
;
3066 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3067 cmici
.nShow
= SW_NORMAL
;
3069 pcm
->InvokeCommand(&cmici
);
3074 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3081 virtual HRESULT STDMETHODCALLTYPE
3082 GetCommandString(UINT_PTR idCmd
,
3091 CTrayWindowCtxMenu()
3095 virtual ~CTrayWindowCtxMenu()
3099 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3100 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3104 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3106 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3107 mnu
->Initialize(TrayWnd
, hWndOwner
);
3112 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3114 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3116 return E_OUTOFMEMORY
;
3121 *ppTray
= (ITrayWindow
*) Tray
;
3127 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3129 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3130 return TrayWindow
->RaiseStartButton();
3133 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3135 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3136 TrayWindow
->TrayProcessMessages();
3139 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3141 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3142 TrayWindow
->TrayMessageLoop();