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
))
1319 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1324 Horizontal
= IsPosHorizontal();
1326 /* We're about to resize/move the start button, the rebar control and
1327 the tray notification control */
1328 dwp
= BeginDeferWindowPos(3);
1331 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1335 /* Limit the Start button width to the client width, if neccessary */
1336 StartSize
= m_StartButton
.GetSize();
1337 if (StartSize
.cx
> rcClient
.right
)
1338 StartSize
.cx
= rcClient
.right
;
1340 if (m_StartButton
.m_hWnd
!= NULL
)
1342 /* Resize and reposition the button */
1343 dwp
= DeferWindowPos(dwp
,
1344 m_StartButton
.m_hWnd
,
1350 SWP_NOZORDER
| SWP_NOACTIVATE
);
1353 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1358 /* Determine the size that the tray notification window needs */
1362 TraySize
.cy
= rcClient
.bottom
;
1366 TraySize
.cx
= rcClient
.right
;
1370 if (m_TrayNotify
!= NULL
&&
1371 SendMessage(m_TrayNotify
,
1372 TNWM_GETMINIMUMSIZE
,
1373 (WPARAM
) Horizontal
,
1374 (LPARAM
) &TraySize
))
1376 /* Move the tray notification window to the desired location */
1378 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1380 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1382 dwp
= DeferWindowPos(dwp
,
1389 SWP_NOZORDER
| SWP_NOACTIVATE
);
1392 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1397 /* Resize/Move the rebar control */
1398 if (m_Rebar
!= NULL
)
1400 POINT ptRebar
= { 0, 0 };
1403 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1407 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1408 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1409 szRebar
.cy
= rcClient
.bottom
;
1413 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1414 szRebar
.cx
= rcClient
.right
;
1415 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1418 dwp
= DeferWindowPos(dwp
,
1425 SWP_NOZORDER
| SWP_NOACTIVATE
);
1429 EndDeferWindowPos(dwp
);
1431 if (m_TaskSwitch
!= NULL
)
1433 /* Update the task switch window configuration */
1434 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1438 LRESULT
OnThemeChanged()
1441 CloseThemeData(m_Theme
);
1443 if (IsThemeActive())
1444 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
1448 if (Locked
&& m_Theme
)
1450 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1454 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1456 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1461 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1463 return OnThemeChanged();
1466 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1468 WCHAR szStartCaption
[32];
1470 ((ITrayWindow
*)this)->AddRef();
1472 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1475 InterlockedIncrement(&TrayWndCount
);
1477 if (!LoadString(hExplorerInstance
,
1480 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1482 szStartCaption
[0] = TEXT('\0');
1485 if (m_CaptionFont
== NULL
)
1487 NONCLIENTMETRICS ncm
;
1489 /* Get the system fonts, we use the caption font,
1490 always bold, though. */
1491 ncm
.cbSize
= sizeof(ncm
);
1492 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
1494 if (m_CaptionFont
== NULL
)
1496 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1497 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1502 /* Create the Start button */
1503 m_StartButton
.SubclassWindow(CreateWindowEx(
1507 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1508 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1514 (HMENU
) IDC_STARTBTN
,
1518 if (m_StartButton
.m_hWnd
)
1520 m_StartButton
.Initialize();
1523 /* Load the saved tray window settings */
1526 /* Create and initialize the start menu */
1527 HBITMAP hbmBanner
= LoadBitmap(hExplorerInstance
, MAKEINTRESOURCE(IDB_STARTMENU
));
1528 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
1530 /* Load the tray band site */
1531 if (m_TrayBandSite
!= NULL
)
1533 m_TrayBandSite
.Release();
1536 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
1537 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
1539 /* Create the tray notification window */
1540 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
1542 if (UpdateNonClientMetrics())
1547 /* Move the tray window to the right position and resize it if neccessary */
1548 CheckTrayWndPosition();
1550 /* Align all controls on the tray window */
1551 AlignControls(NULL
);
1553 InitShellServices(&(m_ShellServices
));
1557 m_AutoHideState
= AUTOHIDE_HIDING
;
1558 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1561 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
1562 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
1563 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
1564 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
1565 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
1566 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
1567 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
1568 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
1569 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
1570 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
1571 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
1572 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
1577 HRESULT STDMETHODCALLTYPE
Open()
1581 /* Check if there's already a window created and try to show it.
1582 If it was somehow destroyed just create a new tray window. */
1583 if (m_hWnd
!= NULL
&& IsWindow())
1585 if (!IsWindowVisible(m_hWnd
))
1587 CheckTrayWndPosition();
1589 ShowWindow(SW_SHOW
);
1595 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1597 dwExStyle
|= WS_EX_TOPMOST
;
1599 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1600 WS_BORDER
| WS_THICKFRAME
;
1602 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1603 if (m_Position
!= (DWORD
) -1)
1604 rcWnd
= m_TrayRects
[m_Position
];
1606 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1612 HRESULT STDMETHODCALLTYPE
Close()
1625 HWND STDMETHODCALLTYPE
GetHWND()
1630 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1632 return (m_hWnd
== hWnd
||
1633 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1636 BOOL STDMETHODCALLTYPE
1639 return IsPosHorizontal();
1642 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1644 if (phBoldCaption
!= NULL
)
1645 *phBoldCaption
= m_StartButton
.GetFont();
1647 return m_CaptionFont
;
1650 DWORD WINAPI
TrayPropertiesThread()
1655 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1656 hwnd
= CreateWindowEx(0,
1659 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1662 posRect
.right
- posRect
.left
,
1663 posRect
.bottom
- posRect
.top
,
1669 m_TrayPropertiesOwner
= hwnd
;
1671 DisplayTrayProperties(hwnd
);
1673 m_TrayPropertiesOwner
= NULL
;
1674 ::DestroyWindow(hwnd
);
1679 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1681 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1683 return This
->TrayPropertiesThread();
1686 HWND STDMETHODCALLTYPE
DisplayProperties()
1690 if (m_TrayPropertiesOwner
)
1692 hTrayProp
= GetLastActivePopup(m_TrayPropertiesOwner
);
1693 if (hTrayProp
!= NULL
&&
1694 hTrayProp
!= m_TrayPropertiesOwner
)
1696 SetForegroundWindow(hTrayProp
);
1701 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1705 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1707 WCHAR szDir
[MAX_PATH
];
1709 if (SHGetSpecialFolderPath(hWndOwner
,
1711 CSIDL_COMMON_STARTMENU
,
1714 ShellExecute(hWndOwner
,
1723 VOID
OpenTaskManager(IN HWND hWndOwner
)
1725 ShellExecute(hWndOwner
,
1727 TEXT("taskmgr.exe"),
1733 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1735 BOOL bHandled
= TRUE
;
1739 case ID_SHELL_CMD_PROPERTIES
:
1740 DisplayProperties();
1743 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1744 OpenCommonStartMenuDirectory(m_hWnd
,
1748 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1749 OpenCommonStartMenuDirectory(m_hWnd
,
1753 case ID_LOCKTASKBAR
:
1754 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1760 case ID_SHELL_CMD_OPEN_TASKMGR
:
1761 OpenTaskManager(m_hWnd
);
1764 case ID_SHELL_CMD_UNDO_ACTION
:
1767 case ID_SHELL_CMD_SHOW_DESKTOP
:
1770 case ID_SHELL_CMD_TILE_WND_H
:
1771 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1774 case ID_SHELL_CMD_TILE_WND_V
:
1775 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1778 case ID_SHELL_CMD_CASCADE_WND
:
1779 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1782 case ID_SHELL_CMD_CUST_NOTIF
:
1785 case ID_SHELL_CMD_ADJUST_DAT
:
1786 //FIXME: Use SHRunControlPanel
1787 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
1791 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1799 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1801 BOOL bPrevLock
= Locked
;
1803 if (Locked
!= bLock
)
1807 if (m_TrayBandSite
!= NULL
)
1809 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1817 if (Locked
&& m_Theme
)
1819 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1823 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1825 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1833 LRESULT
DrawBackground(HDC hdc
)
1838 GetClientRect(&rect
);
1842 GetClientRect(&rect
);
1846 partId
= TBP_BACKGROUNDLEFT
;
1849 partId
= TBP_BACKGROUNDTOP
;
1852 partId
= TBP_BACKGROUNDRIGHT
;
1856 partId
= TBP_BACKGROUNDBOTTOM
;
1860 DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1866 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1868 HDC hdc
= (HDC
) wParam
;
1876 return DrawBackground(hdc
);
1879 int DrawSizer(IN HRGN hRgn
)
1885 GetWindowRect(m_hWnd
, &rect
);
1886 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1888 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1893 backoundPart
= TBP_SIZINGBARLEFT
;
1894 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1897 backoundPart
= TBP_SIZINGBARTOP
;
1898 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1901 backoundPart
= TBP_SIZINGBARRIGHT
;
1902 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1906 backoundPart
= TBP_SIZINGBARBOTTOM
;
1907 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1911 DrawThemeBackground(m_Theme
, hdc
, backoundPart
, 0, &rect
, 0);
1913 ReleaseDC(m_hWnd
, hdc
);
1917 DWORD WINAPI
RunFileDlgThread()
1922 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1924 hwnd
= CreateWindowEx(0,
1927 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1930 posRect
.right
- posRect
.left
,
1931 posRect
.bottom
- posRect
.top
,
1937 m_RunFileDlgOwner
= hwnd
;
1939 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1941 m_RunFileDlgOwner
= NULL
;
1942 ::DestroyWindow(hwnd
);
1947 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1949 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1950 return This
->RunFileDlgThread();
1953 void DisplayRunFileDlg()
1956 if (m_RunFileDlgOwner
)
1958 hRunDlg
= GetLastActivePopup(m_RunFileDlgOwner
);
1959 if (hRunDlg
!= NULL
&&
1960 hRunDlg
!= m_RunFileDlgOwner
)
1962 SetForegroundWindow(hRunDlg
);
1967 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1970 void PopupStartMenu()
1972 if (m_StartMenuPopup
!= NULL
)
1978 if (GetWindowRect(m_StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1983 pt
.x
= rcExclude
.left
;
1984 pt
.y
= rcExclude
.top
;
1985 dwFlags
|= MPPF_TOP
;
1988 pt
.x
= rcExclude
.left
;
1989 pt
.y
= rcExclude
.bottom
;
1990 dwFlags
|= MPPF_BOTTOM
;
1993 pt
.x
= rcExclude
.right
;
1994 pt
.y
= rcExclude
.top
;
1995 dwFlags
|= MPPF_RIGHT
;
1998 pt
.x
= rcExclude
.left
;
1999 pt
.y
= rcExclude
.top
;
2000 dwFlags
|= MPPF_LEFT
;
2004 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
2006 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
2011 void ProcessMouseTracking()
2016 UINT state
= m_AutoHideState
;
2019 GetWindowRect(m_hWnd
, &rcCurrent
);
2020 over
= PtInRect(&rcCurrent
, pt
);
2022 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2029 if (state
== AUTOHIDE_HIDING
)
2031 TRACE("AutoHide cancelling hide.\n");
2032 m_AutoHideState
= AUTOHIDE_SHOWING
;
2033 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2035 else if (state
== AUTOHIDE_HIDDEN
)
2037 TRACE("AutoHide starting show.\n");
2038 m_AutoHideState
= AUTOHIDE_SHOWING
;
2039 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2044 if (state
== AUTOHIDE_SHOWING
)
2046 TRACE("AutoHide cancelling show.\n");
2047 m_AutoHideState
= AUTOHIDE_HIDING
;
2048 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2050 else if (state
== AUTOHIDE_SHOWN
)
2052 TRACE("AutoHide starting hide.\n");
2053 m_AutoHideState
= AUTOHIDE_HIDING
;
2054 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2057 KillTimer(TIMER_ID_MOUSETRACK
);
2061 void ProcessAutoHide()
2063 RECT rc
= m_TrayRects
[m_Position
];
2064 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2065 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2067 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
);
2069 switch (m_AutoHideState
)
2071 case AUTOHIDE_HIDING
:
2075 m_AutoHideOffset
.cy
= 0;
2076 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2077 if (m_AutoHideOffset
.cx
< -w
)
2078 m_AutoHideOffset
.cx
= -w
;
2081 m_AutoHideOffset
.cx
= 0;
2082 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2083 if (m_AutoHideOffset
.cy
< -h
)
2084 m_AutoHideOffset
.cy
= -h
;
2087 m_AutoHideOffset
.cy
= 0;
2088 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2089 if (m_AutoHideOffset
.cx
> w
)
2090 m_AutoHideOffset
.cx
= w
;
2093 m_AutoHideOffset
.cx
= 0;
2094 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2095 if (m_AutoHideOffset
.cy
> h
)
2096 m_AutoHideOffset
.cy
= h
;
2100 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
2102 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2107 case AUTOHIDE_HIDDEN
:
2112 m_AutoHideOffset
.cx
= -w
;
2113 m_AutoHideOffset
.cy
= 0;
2116 m_AutoHideOffset
.cx
= 0;
2117 m_AutoHideOffset
.cy
= -h
;
2120 m_AutoHideOffset
.cx
= w
;
2121 m_AutoHideOffset
.cy
= 0;
2124 m_AutoHideOffset
.cx
= 0;
2125 m_AutoHideOffset
.cy
= h
;
2129 KillTimer(TIMER_ID_AUTOHIDE
);
2130 m_AutoHideState
= AUTOHIDE_HIDDEN
;
2133 case AUTOHIDE_SHOWING
:
2134 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2136 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2138 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2140 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2144 m_AutoHideOffset
.cx
= 0;
2147 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2149 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2151 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2153 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2157 m_AutoHideOffset
.cy
= 0;
2160 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
2162 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2167 case AUTOHIDE_SHOWN
:
2169 KillTimer(TIMER_ID_AUTOHIDE
);
2170 m_AutoHideState
= AUTOHIDE_SHOWN
;
2174 rc
.left
+= m_AutoHideOffset
.cx
;
2175 rc
.right
+= m_AutoHideOffset
.cx
;
2176 rc
.top
+= m_AutoHideOffset
.cy
;
2177 rc
.bottom
+= m_AutoHideOffset
.cy
;
2179 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
2180 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2183 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2185 /* Load the saved tray window settings */
2188 /* Move the tray window to the right position and resize it if neccessary */
2189 CheckTrayWndPosition();
2191 /* Align all controls on the tray window */
2192 AlignControls(NULL
);
2197 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2201 TRACE("WM_COPYDATA notify message received. Handling...\n");
2202 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2207 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2215 return DrawSizer((HRGN
) wParam
);
2218 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2220 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2221 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2224 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2231 /* The user may not be able to resize the tray window.
2232 Pretend like the window is not sizeable when the user
2233 clicks on the border. */
2237 SetLastError(ERROR_SUCCESS
);
2238 if (GetClientRect(&rcClient
) &&
2239 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2241 pt
.x
= (SHORT
) LOWORD(lParam
);
2242 pt
.y
= (SHORT
) HIWORD(lParam
);
2244 if (PtInRect(&rcClient
,
2247 /* The user is trying to drag the tray window */
2251 /* Depending on the position of the tray window, allow only
2252 changing the border next to the monitor working area */
2256 if (pt
.y
> rcClient
.bottom
)
2260 if (pt
.x
> rcClient
.right
)
2264 if (pt
.x
< rcClient
.left
)
2269 if (pt
.y
< rcClient
.top
)
2278 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2281 PRECT pRect
= (PRECT
) lParam
;
2283 /* We need to ensure that an application can not accidently
2284 move the tray window (using SetWindowPos). However, we still
2285 need to be able to move the window in case the user wants to
2286 drag the tray window to another position or in case the user
2287 wants to resize the tray window. */
2288 if (!Locked
&& GetCursorPos(&ptCursor
))
2291 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2295 *pRect
= m_TrayRects
[m_Position
];
2299 pRect
->left
+= m_AutoHideOffset
.cx
;
2300 pRect
->right
+= m_AutoHideOffset
.cx
;
2301 pRect
->top
+= m_AutoHideOffset
.cy
;
2302 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2308 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2310 PRECT pRect
= (PRECT
) lParam
;
2314 CalculateValidSize(m_Position
, pRect
);
2318 *pRect
= m_TrayRects
[m_Position
];
2322 pRect
->left
+= m_AutoHideOffset
.cx
;
2323 pRect
->right
+= m_AutoHideOffset
.cx
;
2324 pRect
->top
+= m_AutoHideOffset
.cy
;
2325 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2331 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2333 ChangingWinPos((LPWINDOWPOS
) lParam
);
2337 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2340 InvalidateRect(NULL
, TRUE
);
2341 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2344 /* Clip the tray window on multi monitor systems so the edges can't
2345 overlap into another monitor */
2346 ApplyClipping(TRUE
);
2348 if (!GetClientRect(&rcClient
))
2355 rcClient
.left
= rcClient
.top
= 0;
2356 rcClient
.right
= LOWORD(lParam
);
2357 rcClient
.bottom
= HIWORD(lParam
);
2360 AlignControls(&rcClient
);
2364 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2370 /* Remove the clipping on multi monitor systems while dragging around */
2371 ApplyClipping(FALSE
);
2376 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2381 /* Apply clipping */
2382 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2387 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2393 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2394 The tray window needs to handle this specially, since it normally doesn't have
2397 static const UINT uidDisableItem
[] = {
2408 /* temporarily enable the system menu */
2409 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2411 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2412 if (hSysMenu
!= NULL
)
2414 /* Disable all items that are not relevant */
2415 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2417 EnableMenuItem(hSysMenu
,
2419 MF_BYCOMMAND
| MF_GRAYED
);
2422 EnableMenuItem(hSysMenu
,
2425 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2427 /* Display the system menu */
2431 m_StartButton
.m_hWnd
,
2432 m_Position
!= ABE_TOP
,
2436 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2440 /* revert the system menu window style */
2441 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2451 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2453 /* We want the user to be able to get a context menu even on the nonclient
2454 area (including the sizing border)! */
2455 uMsg
= WM_CONTEXTMENU
;
2456 wParam
= (WPARAM
) m_hWnd
;
2458 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2461 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2463 LRESULT Ret
= FALSE
;
2464 POINT pt
, *ppt
= NULL
;
2465 HWND hWndExclude
= NULL
;
2467 /* Check if the administrator has forbidden access to context menus */
2468 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2471 pt
.x
= (SHORT
) LOWORD(lParam
);
2472 pt
.y
= (SHORT
) HIWORD(lParam
);
2474 if (pt
.x
!= -1 || pt
.y
!= -1)
2477 hWndExclude
= m_StartButton
.m_hWnd
;
2479 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2481 /* Make sure we can't track the context menu if the start
2482 menu is currently being shown */
2483 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2485 CComPtr
<IContextMenu
> ctxMenu
;
2486 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2487 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2492 /* See if the context menu should be handled by the task band site */
2493 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2496 POINT ptClient
= *ppt
;
2498 /* Convert the coordinates to client-coordinates */
2499 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2501 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2502 if (hWndAtPt
!= NULL
&&
2503 (hWndAtPt
== m_Rebar
|| IsChild(m_Rebar
, hWndAtPt
)))
2505 /* Check if the user clicked on the task switch window */
2507 MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2509 hWndAtPt
= ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2510 if (hWndAtPt
== m_TaskSwitch
)
2511 goto HandleTrayContextMenu
;
2513 /* Forward the message to the task band site */
2514 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2517 goto HandleTrayContextMenu
;
2521 HandleTrayContextMenu
:
2522 /* Tray the default tray window context menu */
2523 CComPtr
<IContextMenu
> ctxMenu
;
2524 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2525 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2531 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2533 LRESULT Ret
= FALSE
;
2534 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2535 the rebar control! But we shouldn't forward messages that the band
2536 site doesn't handle, such as other controls (start button, tray window */
2538 HRESULT hr
= E_FAIL
;
2542 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2547 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2549 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2551 if (nmh
->hwndFrom
== m_TrayNotify
)
2556 /* Cause all controls to be aligned */
2557 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2565 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2567 /* We "handle" this message so users can't cause a weird maximize/restore
2568 window animation when double-clicking the tray window! */
2570 /* We should forward mouse messages to child windows here.
2571 Right now, this is only clock double-click */
2573 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2576 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2577 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2578 if (PtInRect(&rcClock
, ptClick
))
2580 //FIXME: use SHRunControlPanel
2581 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2587 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2593 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2596 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2597 if (FAILED_UNEXPECTEDLY(hr
))
2600 if (IsWindowVisible(hwndStartMenu
))
2602 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2612 LRESULT
DoExitWindows()
2614 ExitWindowsDialog(m_hWnd
);
2618 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2621 * TWM_DOEXITWINDOWS is send by the CDesktopBrowserr to us to
2622 * show the shutdown dialog
2624 return DoExitWindows();
2627 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2629 if (wParam
== SC_CLOSE
)
2631 return DoExitWindows();
2638 HRESULT
ExecResourceCmd(int id
)
2640 WCHAR szCommand
[256];
2641 WCHAR
*pszParameters
;
2643 if (!LoadString(hExplorerInstance
,
2646 sizeof(szCommand
) / sizeof(szCommand
[0])))
2651 pszParameters
= wcschr(szCommand
, L
'>');
2658 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, 0);
2662 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2667 DisplayRunFileDlg();
2670 ExecResourceCmd(IDS_HELP_COMMAND
);
2673 ShellExecuteW(0, L
"explore", NULL
, NULL
, NULL
, 1);
2676 SHFindFiles(NULL
, NULL
);
2678 case IDHK_FIND_COMPUTER
:
2679 SHFindComputer(NULL
, NULL
);
2681 case IDHK_SYS_PROPERTIES
:
2682 //FIXME: Use SHRunControlPanel
2683 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
2685 case IDHK_NEXT_TASK
:
2687 case IDHK_PREV_TASK
:
2689 case IDHK_MINIMIZE_ALL
:
2691 case IDHK_RESTORE_ALL
:
2702 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2704 LRESULT Ret
= FALSE
;
2706 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2712 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2714 switch (LOWORD(wParam
))
2716 /* FIXME: Handle these commands as well */
2717 case IDM_TASKBARANDSTARTMENU
:
2718 DisplayProperties();
2722 SHFindFiles(NULL
, NULL
);
2725 case IDM_HELPANDSUPPORT
:
2726 ExecResourceCmd(IDS_HELP_COMMAND
);
2730 DisplayRunFileDlg();
2733 /* FIXME: Handle these commands as well */
2734 case IDM_SYNCHRONIZE
:
2736 case IDM_DISCONNECT
:
2737 case IDM_UNDOCKCOMPUTER
:
2748 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2752 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2758 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2760 if (wParam
== TIMER_ID_MOUSETRACK
)
2762 ProcessMouseTracking();
2764 else if (wParam
== TIMER_ID_AUTOHIDE
)
2773 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2776 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2782 ::GetWindowRect(m_hWnd
, &rc
);
2786 rc
.bottom
- rc
.top
};
2788 as
->rcTarget
.right
- as
->rcTarget
.left
,
2789 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2791 as
->rcActual
.right
- as
->rcActual
.left
,
2792 as
->rcActual
.bottom
- as
->rcActual
.top
};
2795 szWindow
.cx
- szTarget
.cx
,
2796 szWindow
.cy
- szTarget
.cx
,
2802 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2805 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2808 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2809 rc
.left
= rc
.right
- szWindow
.cy
;
2812 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2813 rc
.top
= rc
.bottom
- szWindow
.cy
;
2817 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2824 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2826 BEGIN_MSG_MAP(CTrayWindow
)
2827 if (m_StartMenuBand
!= NULL
)
2834 Msg
.wParam
= wParam
;
2835 Msg
.lParam
= lParam
;
2837 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2842 wParam
= Msg
.wParam
;
2843 lParam
= Msg
.lParam
;
2845 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2846 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2847 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2848 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2849 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2850 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2851 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2852 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2853 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2854 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2855 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2856 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2857 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2858 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2859 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2860 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2861 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2862 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2863 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2864 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2865 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2866 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2867 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2868 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2869 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2870 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2871 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2872 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2873 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2874 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2878 /*****************************************************************************/
2880 VOID
TrayProcessMessages()
2884 /* FIXME: We should keep a reference here... */
2886 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2888 if (Msg
.message
== WM_QUIT
)
2891 if (m_StartMenuBand
== NULL
||
2892 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2894 TranslateMessage(&Msg
);
2895 DispatchMessage(&Msg
);
2900 VOID
TrayMessageLoop()
2905 /* FIXME: We should keep a reference here... */
2909 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2911 if (!Ret
|| Ret
== -1)
2914 if (m_StartMenuBand
== NULL
||
2915 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2917 TranslateMessage(&Msg
);
2918 DispatchMessage(&Msg
);
2926 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2927 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2928 * The reason we implement it is because we have to use SHCreateDesktop() so
2929 * that the shell provides the desktop window and all the features that come
2930 * with it (especially positioning of desktop icons)
2933 virtual ULONG STDMETHODCALLTYPE
GetState()
2935 /* FIXME: Return ABS_ flags? */
2936 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2940 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2942 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2943 *phWndTray
= m_hWnd
;
2947 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2949 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2951 m_DesktopWnd
= hWndDesktop
;
2955 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2957 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2961 virtual HRESULT
RaiseStartButton()
2963 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2969 m_Position
= (DWORD
) -1;
2972 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2974 DECLARE_PROTECT_FINAL_CONSTRUCT()
2975 BEGIN_COM_MAP(CTrayWindow
)
2976 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2977 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2981 class CTrayWindowCtxMenu
:
2982 public CComCoClass
<CTrayWindowCtxMenu
>,
2983 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2987 CComPtr
<CTrayWindow
> TrayWnd
;
2988 CComPtr
<IContextMenu
> pcm
;
2991 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2993 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2994 this->hWndOwner
= hWndOwner
;
2998 virtual HRESULT STDMETHODCALLTYPE
2999 QueryContextMenu(HMENU hPopup
,
3005 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
3008 return HRESULT_FROM_WIN32(GetLastError());
3010 int count
= ::GetMenuItemCount(menubase
);
3012 for (int i
= 0; i
< count
; i
++)
3016 MENUITEMINFOW mii
= { 0 };
3017 mii
.cbSize
= sizeof(mii
);
3018 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3019 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3020 mii
.dwTypeData
= label
;
3021 mii
.cch
= _countof(label
);
3022 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3024 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3026 mii
.fType
|= MFT_RADIOCHECK
;
3028 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3031 ::DestroyMenu(menubase
);
3033 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3040 CheckMenuItem(hPopup
,
3042 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3044 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3046 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3054 WARN("AddContextMenus failed.\n");
3062 virtual HRESULT STDMETHODCALLTYPE
3063 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3065 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3068 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3070 CMINVOKECOMMANDINFO cmici
= { 0 };
3074 /* Setup and invoke the shell command */
3075 cmici
.cbSize
= sizeof(cmici
);
3076 cmici
.hwnd
= hWndOwner
;
3077 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3078 cmici
.nShow
= SW_NORMAL
;
3080 pcm
->InvokeCommand(&cmici
);
3085 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3092 virtual HRESULT STDMETHODCALLTYPE
3093 GetCommandString(UINT_PTR idCmd
,
3102 CTrayWindowCtxMenu()
3106 virtual ~CTrayWindowCtxMenu()
3110 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3111 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3115 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3117 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3118 mnu
->Initialize(TrayWnd
, hWndOwner
);
3123 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3125 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3127 return E_OUTOFMEMORY
;
3132 *ppTray
= (ITrayWindow
*) Tray
;
3138 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3140 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3141 return TrayWindow
->RaiseStartButton();
3144 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3146 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3147 TrayWindow
->TrayProcessMessages();
3150 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3152 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3153 TrayWindow
->TrayMessageLoop();