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");
1440 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1444 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1450 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1452 return OnThemeChanged();
1455 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1457 WCHAR szStartCaption
[32];
1459 ((ITrayWindow
*)this)->AddRef();
1461 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1464 InterlockedIncrement(&TrayWndCount
);
1466 if (!LoadString(hExplorerInstance
,
1469 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1471 szStartCaption
[0] = TEXT('\0');
1474 if (m_CaptionFont
== NULL
)
1476 NONCLIENTMETRICS ncm
;
1478 /* Get the system fonts, we use the caption font,
1479 always bold, though. */
1480 ncm
.cbSize
= sizeof(ncm
);
1481 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
1483 if (m_CaptionFont
== NULL
)
1485 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1486 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1491 /* Create the Start button */
1492 m_StartButton
.SubclassWindow(CreateWindowEx(
1496 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1497 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1503 (HMENU
) IDC_STARTBTN
,
1507 if (m_StartButton
.m_hWnd
)
1509 m_StartButton
.Initialize();
1512 /* Load the saved tray window settings */
1515 /* Create and initialize the start menu */
1516 HBITMAP hbmBanner
= LoadBitmap(hExplorerInstance
, MAKEINTRESOURCE(IDB_STARTMENU
));
1517 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
1519 /* Load the tray band site */
1520 if (m_TrayBandSite
!= NULL
)
1522 m_TrayBandSite
.Release();
1525 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
1526 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
1528 /* Create the tray notification window */
1529 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
1531 if (UpdateNonClientMetrics())
1536 /* Move the tray window to the right position and resize it if neccessary */
1537 CheckTrayWndPosition();
1539 /* Align all controls on the tray window */
1540 AlignControls(NULL
);
1542 InitShellServices(&(m_ShellServices
));
1546 m_AutoHideState
= AUTOHIDE_HIDING
;
1547 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1550 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
1551 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
1552 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
1553 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
1554 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
1555 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
1556 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
1557 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
1558 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
1559 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
1560 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
1561 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
1566 HRESULT STDMETHODCALLTYPE
Open()
1570 /* Check if there's already a window created and try to show it.
1571 If it was somehow destroyed just create a new tray window. */
1572 if (m_hWnd
!= NULL
&& IsWindow())
1574 if (!IsWindowVisible(m_hWnd
))
1576 CheckTrayWndPosition();
1578 ShowWindow(SW_SHOW
);
1584 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1586 dwExStyle
|= WS_EX_TOPMOST
;
1588 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1589 WS_BORDER
| WS_THICKFRAME
;
1591 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1592 if (m_Position
!= (DWORD
) -1)
1593 rcWnd
= m_TrayRects
[m_Position
];
1595 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1601 HRESULT STDMETHODCALLTYPE
Close()
1614 HWND STDMETHODCALLTYPE
GetHWND()
1619 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1621 return (m_hWnd
== hWnd
||
1622 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1625 BOOL STDMETHODCALLTYPE
1628 return IsPosHorizontal();
1631 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1633 if (phBoldCaption
!= NULL
)
1634 *phBoldCaption
= m_StartButton
.GetFont();
1636 return m_CaptionFont
;
1639 DWORD WINAPI
TrayPropertiesThread()
1644 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1645 hwnd
= CreateWindowEx(0,
1648 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1651 posRect
.right
- posRect
.left
,
1652 posRect
.bottom
- posRect
.top
,
1658 m_TrayPropertiesOwner
= hwnd
;
1660 DisplayTrayProperties(hwnd
);
1662 m_TrayPropertiesOwner
= NULL
;
1668 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1670 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1672 return This
->TrayPropertiesThread();
1675 HWND STDMETHODCALLTYPE
DisplayProperties()
1679 if (m_TrayPropertiesOwner
)
1681 hTrayProp
= GetLastActivePopup(m_TrayPropertiesOwner
);
1682 if (hTrayProp
!= NULL
&&
1683 hTrayProp
!= m_TrayPropertiesOwner
)
1685 SetForegroundWindow(hTrayProp
);
1690 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1694 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1696 WCHAR szDir
[MAX_PATH
];
1698 if (SHGetSpecialFolderPath(hWndOwner
,
1700 CSIDL_COMMON_STARTMENU
,
1703 ShellExecute(hWndOwner
,
1712 VOID
OpenTaskManager(IN HWND hWndOwner
)
1714 ShellExecute(hWndOwner
,
1716 TEXT("taskmgr.exe"),
1722 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1724 BOOL bHandled
= TRUE
;
1728 case ID_SHELL_CMD_PROPERTIES
:
1729 DisplayProperties();
1732 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1733 OpenCommonStartMenuDirectory(m_hWnd
,
1737 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1738 OpenCommonStartMenuDirectory(m_hWnd
,
1742 case ID_LOCKTASKBAR
:
1743 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1749 case ID_SHELL_CMD_OPEN_TASKMGR
:
1750 OpenTaskManager(m_hWnd
);
1753 case ID_SHELL_CMD_UNDO_ACTION
:
1756 case ID_SHELL_CMD_SHOW_DESKTOP
:
1759 case ID_SHELL_CMD_TILE_WND_H
:
1760 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1763 case ID_SHELL_CMD_TILE_WND_V
:
1764 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1767 case ID_SHELL_CMD_CASCADE_WND
:
1768 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1771 case ID_SHELL_CMD_CUST_NOTIF
:
1774 case ID_SHELL_CMD_ADJUST_DAT
:
1775 //FIXME: Use SHRunControlPanel
1776 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
1780 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1788 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1793 if (Locked
!= bLock
)
1797 if (m_TrayBandSite
!= NULL
)
1799 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1811 LRESULT
DrawBackground(HDC hdc
)
1816 GetClientRect(&rect
);
1820 GetClientRect(&rect
);
1824 partId
= TBP_BACKGROUNDLEFT
;
1827 partId
= TBP_BACKGROUNDTOP
;
1830 partId
= TBP_BACKGROUNDRIGHT
;
1834 partId
= TBP_BACKGROUNDBOTTOM
;
1838 DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1844 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1846 HDC hdc
= (HDC
) wParam
;
1854 return DrawBackground(hdc
);
1857 int DrawSizer(IN HRGN hRgn
)
1863 GetWindowRect(m_hWnd
, &rect
);
1864 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1866 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1871 backoundPart
= TBP_SIZINGBARLEFT
;
1872 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1875 backoundPart
= TBP_SIZINGBARTOP
;
1876 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1879 backoundPart
= TBP_SIZINGBARRIGHT
;
1880 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1884 backoundPart
= TBP_SIZINGBARBOTTOM
;
1885 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1889 DrawThemeBackground(m_Theme
, hdc
, backoundPart
, 0, &rect
, 0);
1891 ReleaseDC(m_hWnd
, hdc
);
1895 DWORD WINAPI
RunFileDlgThread()
1900 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1902 hwnd
= CreateWindowEx(0,
1905 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1908 posRect
.right
- posRect
.left
,
1909 posRect
.bottom
- posRect
.top
,
1915 m_RunFileDlgOwner
= hwnd
;
1917 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1919 m_RunFileDlgOwner
= NULL
;
1920 ::DestroyWindow(hwnd
);
1925 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1927 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1928 return This
->RunFileDlgThread();
1931 void DisplayRunFileDlg()
1934 if (m_RunFileDlgOwner
)
1936 hRunDlg
= GetLastActivePopup(m_RunFileDlgOwner
);
1937 if (hRunDlg
!= NULL
&&
1938 hRunDlg
!= m_RunFileDlgOwner
)
1940 SetForegroundWindow(hRunDlg
);
1945 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1948 void PopupStartMenu()
1950 if (m_StartMenuPopup
!= NULL
)
1956 if (GetWindowRect(m_StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1961 pt
.x
= rcExclude
.left
;
1962 pt
.y
= rcExclude
.top
;
1963 dwFlags
|= MPPF_BOTTOM
;
1967 pt
.x
= rcExclude
.left
;
1968 pt
.y
= rcExclude
.bottom
;
1969 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
1972 pt
.x
= rcExclude
.right
;
1973 pt
.y
= rcExclude
.bottom
;
1974 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
1978 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1980 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1985 void ProcessMouseTracking()
1990 UINT state
= m_AutoHideState
;
1993 GetWindowRect(m_hWnd
, &rcCurrent
);
1994 over
= PtInRect(&rcCurrent
, pt
);
1996 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2003 if (state
== AUTOHIDE_HIDING
)
2005 TRACE("AutoHide cancelling hide.\n");
2006 m_AutoHideState
= AUTOHIDE_SHOWING
;
2007 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2009 else if (state
== AUTOHIDE_HIDDEN
)
2011 TRACE("AutoHide starting show.\n");
2012 m_AutoHideState
= AUTOHIDE_SHOWING
;
2013 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2018 if (state
== AUTOHIDE_SHOWING
)
2020 TRACE("AutoHide cancelling show.\n");
2021 m_AutoHideState
= AUTOHIDE_HIDING
;
2022 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2024 else if (state
== AUTOHIDE_SHOWN
)
2026 TRACE("AutoHide starting hide.\n");
2027 m_AutoHideState
= AUTOHIDE_HIDING
;
2028 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2031 KillTimer(TIMER_ID_MOUSETRACK
);
2035 void ProcessAutoHide()
2037 RECT rc
= m_TrayRects
[m_Position
];
2038 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2039 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2041 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
);
2043 switch (m_AutoHideState
)
2045 case AUTOHIDE_HIDING
:
2049 m_AutoHideOffset
.cy
= 0;
2050 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2051 if (m_AutoHideOffset
.cx
< -w
)
2052 m_AutoHideOffset
.cx
= -w
;
2055 m_AutoHideOffset
.cx
= 0;
2056 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2057 if (m_AutoHideOffset
.cy
< -h
)
2058 m_AutoHideOffset
.cy
= -h
;
2061 m_AutoHideOffset
.cy
= 0;
2062 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2063 if (m_AutoHideOffset
.cx
> w
)
2064 m_AutoHideOffset
.cx
= w
;
2067 m_AutoHideOffset
.cx
= 0;
2068 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2069 if (m_AutoHideOffset
.cy
> h
)
2070 m_AutoHideOffset
.cy
= h
;
2074 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
2076 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2081 case AUTOHIDE_HIDDEN
:
2086 m_AutoHideOffset
.cx
= -w
;
2087 m_AutoHideOffset
.cy
= 0;
2090 m_AutoHideOffset
.cx
= 0;
2091 m_AutoHideOffset
.cy
= -h
;
2094 m_AutoHideOffset
.cx
= w
;
2095 m_AutoHideOffset
.cy
= 0;
2098 m_AutoHideOffset
.cx
= 0;
2099 m_AutoHideOffset
.cy
= h
;
2103 KillTimer(TIMER_ID_AUTOHIDE
);
2104 m_AutoHideState
= AUTOHIDE_HIDDEN
;
2107 case AUTOHIDE_SHOWING
:
2108 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2110 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2112 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2114 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2118 m_AutoHideOffset
.cx
= 0;
2121 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2123 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2125 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2127 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2131 m_AutoHideOffset
.cy
= 0;
2134 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
2136 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2141 case AUTOHIDE_SHOWN
:
2143 KillTimer(TIMER_ID_AUTOHIDE
);
2144 m_AutoHideState
= AUTOHIDE_SHOWN
;
2148 rc
.left
+= m_AutoHideOffset
.cx
;
2149 rc
.right
+= m_AutoHideOffset
.cx
;
2150 rc
.top
+= m_AutoHideOffset
.cy
;
2151 rc
.bottom
+= m_AutoHideOffset
.cy
;
2153 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
2154 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2157 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2159 /* Load the saved tray window settings */
2162 /* Move the tray window to the right position and resize it if neccessary */
2163 CheckTrayWndPosition();
2165 /* Align all controls on the tray window */
2166 AlignControls(NULL
);
2171 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2175 TrayNotify_NotifyMsg(m_TrayNotifyInstance
, wParam
, lParam
);
2180 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2188 return DrawSizer((HRGN
) wParam
);
2191 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2193 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2194 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2197 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2204 /* The user may not be able to resize the tray window.
2205 Pretend like the window is not sizeable when the user
2206 clicks on the border. */
2210 SetLastError(ERROR_SUCCESS
);
2211 if (GetClientRect(&rcClient
) &&
2212 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2214 pt
.x
= (SHORT
) LOWORD(lParam
);
2215 pt
.y
= (SHORT
) HIWORD(lParam
);
2217 if (PtInRect(&rcClient
,
2220 /* The user is trying to drag the tray window */
2224 /* Depending on the position of the tray window, allow only
2225 changing the border next to the monitor working area */
2229 if (pt
.y
> rcClient
.bottom
)
2233 if (pt
.x
> rcClient
.right
)
2237 if (pt
.x
< rcClient
.left
)
2242 if (pt
.y
< rcClient
.top
)
2251 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2254 PRECT pRect
= (PRECT
) lParam
;
2256 /* We need to ensure that an application can not accidently
2257 move the tray window (using SetWindowPos). However, we still
2258 need to be able to move the window in case the user wants to
2259 drag the tray window to another position or in case the user
2260 wants to resize the tray window. */
2261 if (!Locked
&& GetCursorPos(&ptCursor
))
2264 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2268 *pRect
= m_TrayRects
[m_Position
];
2272 pRect
->left
+= m_AutoHideOffset
.cx
;
2273 pRect
->right
+= m_AutoHideOffset
.cx
;
2274 pRect
->top
+= m_AutoHideOffset
.cy
;
2275 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2281 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2283 PRECT pRect
= (PRECT
) lParam
;
2287 CalculateValidSize(m_Position
, pRect
);
2291 *pRect
= m_TrayRects
[m_Position
];
2295 pRect
->left
+= m_AutoHideOffset
.cx
;
2296 pRect
->right
+= m_AutoHideOffset
.cx
;
2297 pRect
->top
+= m_AutoHideOffset
.cy
;
2298 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2304 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2306 ChangingWinPos((LPWINDOWPOS
) lParam
);
2310 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2313 InvalidateRect(NULL
, TRUE
);
2314 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2317 /* Clip the tray window on multi monitor systems so the edges can't
2318 overlap into another monitor */
2319 ApplyClipping(TRUE
);
2321 if (!GetClientRect(&rcClient
))
2328 rcClient
.left
= rcClient
.top
= 0;
2329 rcClient
.right
= LOWORD(lParam
);
2330 rcClient
.bottom
= HIWORD(lParam
);
2333 AlignControls(&rcClient
);
2337 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2343 /* Remove the clipping on multi monitor systems while dragging around */
2344 ApplyClipping(FALSE
);
2349 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2354 /* Apply clipping */
2355 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2360 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2366 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2367 The tray window needs to handle this specially, since it normally doesn't have
2370 static const UINT uidDisableItem
[] = {
2381 /* temporarily enable the system menu */
2382 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2384 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2385 if (hSysMenu
!= NULL
)
2387 /* Disable all items that are not relevant */
2388 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2390 EnableMenuItem(hSysMenu
,
2392 MF_BYCOMMAND
| MF_GRAYED
);
2395 EnableMenuItem(hSysMenu
,
2398 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2400 /* Display the system menu */
2404 m_StartButton
.m_hWnd
,
2405 m_Position
!= ABE_TOP
,
2409 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2413 /* revert the system menu window style */
2414 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2424 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2426 /* We want the user to be able to get a context menu even on the nonclient
2427 area (including the sizing border)! */
2428 uMsg
= WM_CONTEXTMENU
;
2429 wParam
= (WPARAM
) m_hWnd
;
2431 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2434 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2436 LRESULT Ret
= FALSE
;
2437 POINT pt
, *ppt
= NULL
;
2438 HWND hWndExclude
= NULL
;
2440 /* Check if the administrator has forbidden access to context menus */
2441 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2444 pt
.x
= (SHORT
) LOWORD(lParam
);
2445 pt
.y
= (SHORT
) HIWORD(lParam
);
2447 if (pt
.x
!= -1 || pt
.y
!= -1)
2450 hWndExclude
= m_StartButton
.m_hWnd
;
2452 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2454 /* Make sure we can't track the context menu if the start
2455 menu is currently being shown */
2456 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2458 CComPtr
<IContextMenu
> ctxMenu
;
2459 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2460 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2465 /* See if the context menu should be handled by the task band site */
2466 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2469 POINT ptClient
= *ppt
;
2471 /* Convert the coordinates to client-coordinates */
2472 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2474 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2475 if (hWndAtPt
!= NULL
&&
2476 (hWndAtPt
== m_Rebar
|| IsChild(m_Rebar
, hWndAtPt
)))
2478 /* Check if the user clicked on the task switch window */
2480 MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2482 hWndAtPt
= ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2483 if (hWndAtPt
== m_TaskSwitch
)
2484 goto HandleTrayContextMenu
;
2486 /* Forward the message to the task band site */
2487 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2490 goto HandleTrayContextMenu
;
2494 HandleTrayContextMenu
:
2495 /* Tray the default tray window context menu */
2496 CComPtr
<IContextMenu
> ctxMenu
;
2497 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2498 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2504 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2506 LRESULT Ret
= FALSE
;
2507 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2508 the rebar control! But we shouldn't forward messages that the band
2509 site doesn't handle, such as other controls (start button, tray window */
2511 HRESULT hr
= E_FAIL
;
2515 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2520 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2522 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2524 if (nmh
->hwndFrom
== m_TrayNotify
)
2529 /* Cause all controls to be aligned */
2530 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2538 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2540 /* We "handle" this message so users can't cause a weird maximize/restore
2541 window animation when double-clicking the tray window! */
2543 /* We should forward mouse messages to child windows here.
2544 Right now, this is only clock double-click */
2546 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2549 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2550 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2551 if (PtInRect(&rcClock
, ptClick
))
2553 //FIXME: use SHRunControlPanel
2554 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2560 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2566 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2569 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2570 if (FAILED_UNEXPECTEDLY(hr
))
2573 if (IsWindowVisible(hwndStartMenu
))
2575 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2585 LRESULT
DoExitWindows()
2587 ExitWindowsDialog(m_hWnd
);
2591 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2594 * TWM_DOEXITWINDOWS is send by the CDesktopBrowserr to us to
2595 * show the shutdown dialog
2597 return DoExitWindows();
2600 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2602 if (wParam
== SC_CLOSE
)
2604 return DoExitWindows();
2611 HRESULT
ExecResourceCmd(int id
)
2613 WCHAR szCommand
[256];
2614 WCHAR
*pszParameters
;
2616 if (!LoadString(hExplorerInstance
,
2619 sizeof(szCommand
) / sizeof(szCommand
[0])))
2624 pszParameters
= wcschr(szCommand
, L
'>');
2631 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, 0);
2635 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2640 DisplayRunFileDlg();
2643 ExecResourceCmd(IDS_HELP_COMMAND
);
2646 ShellExecuteW(0, L
"explore", NULL
, NULL
, NULL
, 1);
2649 SHFindFiles(NULL
, NULL
);
2651 case IDHK_FIND_COMPUTER
:
2652 SHFindComputer(NULL
, NULL
);
2654 case IDHK_SYS_PROPERTIES
:
2655 //FIXME: Use SHRunControlPanel
2656 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
2658 case IDHK_NEXT_TASK
:
2660 case IDHK_PREV_TASK
:
2662 case IDHK_MINIMIZE_ALL
:
2664 case IDHK_RESTORE_ALL
:
2675 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2677 LRESULT Ret
= FALSE
;
2679 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2685 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2687 switch (LOWORD(wParam
))
2689 /* FIXME: Handle these commands as well */
2690 case IDM_TASKBARANDSTARTMENU
:
2691 DisplayProperties();
2695 SHFindFiles(NULL
, NULL
);
2698 case IDM_HELPANDSUPPORT
:
2699 ExecResourceCmd(IDS_HELP_COMMAND
);
2703 DisplayRunFileDlg();
2706 /* FIXME: Handle these commands as well */
2707 case IDM_SYNCHRONIZE
:
2709 case IDM_DISCONNECT
:
2710 case IDM_UNDOCKCOMPUTER
:
2721 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2725 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2731 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2733 if (wParam
== TIMER_ID_MOUSETRACK
)
2735 ProcessMouseTracking();
2737 else if (wParam
== TIMER_ID_AUTOHIDE
)
2746 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2749 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2755 ::GetWindowRect(m_hWnd
, &rc
);
2759 rc
.bottom
- rc
.top
};
2761 as
->rcTarget
.right
- as
->rcTarget
.left
,
2762 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2764 as
->rcActual
.right
- as
->rcActual
.left
,
2765 as
->rcActual
.bottom
- as
->rcActual
.top
};
2768 szWindow
.cx
- szTarget
.cx
,
2769 szWindow
.cy
- szTarget
.cx
,
2775 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2778 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2781 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2782 rc
.left
= rc
.right
- szWindow
.cy
;
2785 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2786 rc
.top
= rc
.bottom
- szWindow
.cy
;
2790 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2797 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2799 BEGIN_MSG_MAP(CTrayWindow
)
2800 if (m_StartMenuBand
!= NULL
)
2807 Msg
.wParam
= wParam
;
2808 Msg
.lParam
= lParam
;
2810 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2815 wParam
= Msg
.wParam
;
2816 lParam
= Msg
.lParam
;
2818 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2819 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2820 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2821 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2822 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2823 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2824 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2825 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2826 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2827 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2828 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2829 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2830 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2831 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2832 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2833 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2834 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2835 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2836 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2837 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2838 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2839 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2840 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2841 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2842 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2843 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2844 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2845 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2846 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2847 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2851 /*****************************************************************************/
2853 VOID
TrayProcessMessages()
2857 /* FIXME: We should keep a reference here... */
2859 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2861 if (Msg
.message
== WM_QUIT
)
2864 if (m_StartMenuBand
== NULL
||
2865 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2867 TranslateMessage(&Msg
);
2868 DispatchMessage(&Msg
);
2873 VOID
TrayMessageLoop()
2878 /* FIXME: We should keep a reference here... */
2882 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2884 if (!Ret
|| Ret
== -1)
2887 if (m_StartMenuBand
== NULL
||
2888 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2890 TranslateMessage(&Msg
);
2891 DispatchMessage(&Msg
);
2899 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2900 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2901 * The reason we implement it is because we have to use SHCreateDesktop() so
2902 * that the shell provides the desktop window and all the features that come
2903 * with it (especially positioning of desktop icons)
2906 virtual ULONG STDMETHODCALLTYPE
GetState()
2908 /* FIXME: Return ABS_ flags? */
2909 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2913 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2915 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2916 *phWndTray
= m_hWnd
;
2920 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2922 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2924 m_DesktopWnd
= hWndDesktop
;
2928 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2930 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2934 virtual HRESULT
RaiseStartButton()
2936 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2942 m_Position
= (DWORD
) -1;
2945 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2947 DECLARE_PROTECT_FINAL_CONSTRUCT()
2948 BEGIN_COM_MAP(CTrayWindow
)
2949 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2950 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2954 class CTrayWindowCtxMenu
:
2955 public CComCoClass
<CTrayWindowCtxMenu
>,
2956 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2960 CComPtr
<CTrayWindow
> TrayWnd
;
2961 CComPtr
<IContextMenu
> pcm
;
2964 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2966 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2967 this->hWndOwner
= hWndOwner
;
2971 virtual HRESULT STDMETHODCALLTYPE
2972 QueryContextMenu(HMENU hPopup
,
2978 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
2981 return HRESULT_FROM_WIN32(GetLastError());
2983 int count
= ::GetMenuItemCount(menubase
);
2985 for (int i
= 0; i
< count
; i
++)
2989 MENUITEMINFOW mii
= { 0 };
2990 mii
.cbSize
= sizeof(mii
);
2991 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2992 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2993 mii
.dwTypeData
= label
;
2994 mii
.cch
= _countof(label
);
2995 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2997 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
2999 mii
.fType
|= MFT_RADIOCHECK
;
3001 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3004 ::DestroyMenu(menubase
);
3006 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3013 CheckMenuItem(hPopup
,
3015 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3017 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3019 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3027 WARN("AddContextMenus failed.\n");
3035 virtual HRESULT STDMETHODCALLTYPE
3036 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3038 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3041 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3043 CMINVOKECOMMANDINFO cmici
= { 0 };
3047 /* Setup and invoke the shell command */
3048 cmici
.cbSize
= sizeof(cmici
);
3049 cmici
.hwnd
= hWndOwner
;
3050 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3051 cmici
.nShow
= SW_NORMAL
;
3053 pcm
->InvokeCommand(&cmici
);
3058 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3065 virtual HRESULT STDMETHODCALLTYPE
3066 GetCommandString(UINT_PTR idCmd
,
3075 CTrayWindowCtxMenu()
3079 virtual ~CTrayWindowCtxMenu()
3083 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3084 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3088 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3090 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3091 mnu
->Initialize(TrayWnd
, hWndOwner
);
3096 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3098 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3100 return E_OUTOFMEMORY
;
3105 *ppTray
= (ITrayWindow
*) Tray
;
3111 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3113 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3114 return TrayWindow
->RaiseStartButton();
3117 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3119 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3120 TrayWindow
->TrayProcessMessages();
3123 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3125 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3126 TrayWindow
->TrayMessageLoop();