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
;
75 CStartButton(CMessageMap
*pObject
, DWORD dwMsgMapID
)
76 : CContainedWindow(pObject
, dwMsgMapID
)
80 virtual ~CStartButton()
82 if (m_ImageList
!= NULL
)
83 ImageList_Destroy(m_ImageList
);
89 DeleteObject(m_Bitmap
);
104 SIZE Size
= { 0, 0 };
106 if (m_ImageList
== NULL
||
107 !SendMessage(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
109 Size
.cx
= GetSystemMetrics(SM_CXEDGE
);
110 Size
.cy
= GetSystemMetrics(SM_CYEDGE
);
112 if (m_Bitmap
== NULL
)
114 m_Bitmap
= (HBITMAP
) SendMessage(BM_GETIMAGE
, IMAGE_BITMAP
, 0);
117 if (m_Bitmap
!= NULL
)
121 if (GetObject(m_Bitmap
, sizeof(bmp
), &bmp
) != 0)
123 Size
.cx
+= bmp
.bmWidth
;
124 Size
.cy
+= max(bmp
.bmHeight
, GetSystemMetrics(SM_CYCAPTION
));
128 /* Huh?! Shouldn't happen... */
135 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
136 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
140 /* Save the size of the start button */
144 BOOL
CreateImageList()
149 if (m_ImageList
!= NULL
)
152 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
153 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
155 /* Load the start button icon and create a image list for it */
156 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
157 MAKEINTRESOURCE(IDI_START
),
161 LR_SHARED
| LR_DEFAULTCOLOR
);
163 if (hIconStart
!= NULL
)
165 m_ImageList
= ImageList_Create(IconSize
.cx
,
167 ILC_COLOR32
| ILC_MASK
,
170 if (m_ImageList
!= NULL
)
172 int s
= ImageList_ReplaceIcon(m_ImageList
, -1, hIconStart
);
178 /* Failed to add the icon! */
179 ImageList_Destroy(m_ImageList
);
187 HBITMAP
CreateBitmap()
189 WCHAR szStartCaption
[32];
192 HDC hDCScreen
= NULL
;
193 SIZE Size
, SmallIcon
;
194 HBITMAP hbmpOld
, hbmp
= NULL
;
195 HBITMAP hBitmap
= NULL
;
201 /* NOTE: this is the backwards compatibility code that is used if the
202 Common Controls Version 6.0 are not available! */
204 if (!LoadString(hExplorerInstance
,
207 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
212 /* Load the start button icon */
213 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
214 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
215 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
216 MAKEINTRESOURCE(IDI_START
),
220 LR_SHARED
| LR_DEFAULTCOLOR
);
222 hDCScreen
= GetDC(NULL
);
223 if (hDCScreen
== NULL
)
226 hDC
= CreateCompatibleDC(hDCScreen
);
230 hFontOld
= (HFONT
) SelectObject(hDC
, m_Font
);
232 Ret
= GetTextExtentPoint32(hDC
,
234 _tcslen(szStartCaption
),
237 SelectObject(hDC
, hFontOld
);
241 /* Make sure the height is at least the size of a caption icon. */
242 if (hIconStart
!= NULL
)
243 Size
.cx
+= SmallIcon
.cx
+ 4;
244 Size
.cy
= max(Size
.cy
, SmallIcon
.cy
);
246 /* Create the bitmap */
247 hbmp
= CreateCompatibleBitmap(hDCScreen
,
253 /* Caluclate the button rect */
256 rcButton
.right
= Size
.cx
;
257 rcButton
.bottom
= Size
.cy
;
259 /* Draw the button */
260 hbmpOld
= (HBITMAP
) SelectObject(hDC
, hbmp
);
262 Flags
= DC_TEXT
| DC_INBUTTON
;
263 if (hIconStart
!= NULL
)
266 DrawCaptionTemp(NULL
,
274 SelectObject(hDC
, hbmpOld
);
279 /* We successfully created the bitmap! */
284 if (hDCScreen
!= NULL
)
286 ReleaseDC(NULL
, hDCScreen
);
300 NONCLIENTMETRICS ncm
;
302 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
306 /* Get the system fonts, we use the caption font, always bold, though. */
307 ncm
.cbSize
= sizeof(ncm
);
308 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
310 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
311 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
315 SendMessage(WM_SETFONT
, (WPARAM
) m_Font
, FALSE
);
317 BUTTON_IMAGELIST bil
;
319 /* Try to set the start button image. this requires the Common
320 Controls 6.0 to be present (XP and later) */
321 bil
.himl
= m_ImageList
;
322 bil
.margin
.left
= bil
.margin
.right
= 1;
323 bil
.margin
.top
= bil
.margin
.bottom
= 1;
324 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
326 if (SendMessage(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
))
328 /* We're using the image list, remove the BS_BITMAP style and
329 don't center it horizontally */
330 SetWindowStyle(m_hWnd
, BS_BITMAP
| BS_RIGHT
, 0);
334 /* Fall back to the deprecated method on older systems that don't
335 support Common Controls 6.0 */
336 ImageList_Destroy(m_ImageList
);
341 m_Bitmap
= CreateBitmap();
342 if (m_Bitmap
!= NULL
)
344 hbmOld
= (HBITMAP
) SendMessage(BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) m_Bitmap
);
347 DeleteObject(hbmOld
);
356 public CComCoClass
<CTrayWindow
>,
357 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
358 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
360 public IShellDesktopTray
362 CStartButton m_StartButton
;
364 CComPtr
<IMenuBand
> m_StartMenuBand
;
365 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
379 HMONITOR m_PreviousMonitor
;
380 DWORD m_DraggingPosition
;
381 HMONITOR m_DraggingMonitor
;
386 HWND m_TrayPropertiesOwner
;
387 HWND m_RunFileDlgOwner
;
389 UINT m_AutoHideState
;
390 SIZE m_AutoHideOffset
;
391 TRACKMOUSEEVENT m_MouseTrackingInfo
;
393 HDPA m_ShellServices
;
396 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
404 DWORD AlwaysOnTop
: 1;
405 DWORD SmSmallIcons
: 1;
410 DWORD InSizeMove
: 1;
411 DWORD IsDragging
: 1;
412 DWORD NewPosSize
: 1;
418 m_StartButton(this, 1),
428 m_PreviousMonitor(NULL
),
429 m_DraggingPosition(0),
430 m_DraggingMonitor(NULL
),
431 m_TrayPropertiesOwner(NULL
),
432 m_RunFileDlgOwner(NULL
),
433 m_AutoHideState(NULL
),
434 m_ShellServices(NULL
),
437 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
438 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
439 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
440 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
443 virtual ~CTrayWindow()
445 if (m_ShellServices
!= NULL
)
447 ShutdownShellServices(m_ShellServices
);
448 m_ShellServices
= NULL
;
451 if (m_CaptionFont
!= NULL
)
453 DeleteObject(m_CaptionFont
);
454 m_CaptionFont
= NULL
;
459 DeleteObject(m_Font
);
465 CloseThemeData(m_Theme
);
469 if (InterlockedDecrement(&TrayWndCount
) == 0)
477 BOOL
UpdateNonClientMetrics()
479 NONCLIENTMETRICS ncm
;
480 ncm
.cbSize
= sizeof(ncm
);
481 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
484 DeleteObject(m_Font
);
486 m_Font
= CreateFontIndirect(&ncm
.lfMessageFont
);
493 VOID
SetWindowsFont()
495 if (m_TrayNotify
!= NULL
)
497 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
501 HMONITOR
GetScreenRectFromRect(
508 mi
.cbSize
= sizeof(mi
);
509 hMon
= MonitorFromRect(pRect
,
515 *pRect
= mi
.rcMonitor
;
521 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
522 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
530 HMONITOR
GetMonitorFromRect(
531 IN
const RECT
*pRect
)
535 /* In case the monitor sizes or saved sizes differ a bit (probably
536 not a lot, only so the tray window overlaps into another monitor
537 now), minimize the risk that we determine a wrong monitor by
538 using the center point of the tray window if we can't determine
539 it using the rectangle. */
540 hMon
= MonitorFromRect(pRect
,
541 MONITOR_DEFAULTTONULL
);
546 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
547 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
549 /* be less error-prone, find the nearest monitor */
550 hMon
= MonitorFromPoint(pt
,
551 MONITOR_DEFAULTTONEAREST
);
557 HMONITOR
GetScreenRect(
558 IN HMONITOR hMonitor
,
561 HMONITOR hMon
= NULL
;
563 if (hMonitor
!= NULL
)
567 mi
.cbSize
= sizeof(mi
);
568 if (!GetMonitorInfo(hMonitor
,
571 /* Hm, the monitor is gone? Try to find a monitor where it
572 could be located now */
573 hMon
= GetMonitorFromRect(
576 !GetMonitorInfo(hMon
,
584 *pRect
= mi
.rcMonitor
;
591 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
592 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
598 VOID
MakeTrayRectWithSize(IN DWORD Position
,
599 IN
const SIZE
*pTraySize
,
605 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
609 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
613 pRect
->left
= pRect
->right
- pTraySize
->cx
;
618 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
623 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
624 IN
const RECT
*pScreen
,
625 IN
const SIZE
*pTraySize OPTIONAL
,
628 if (pTraySize
== NULL
)
629 pTraySize
= &m_TraySize
;
633 /* Move the border outside of the screen */
635 GetSystemMetrics(SM_CXEDGE
),
636 GetSystemMetrics(SM_CYEDGE
));
638 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
641 BOOL
IsPosHorizontal()
643 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
646 HMONITOR
CalculateValidSize(
655 //Horizontal = IsPosHorizontal();
657 szWnd
.cx
= pRect
->right
- pRect
->left
;
658 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
661 hMon
= GetScreenRectFromRect(
663 MONITOR_DEFAULTTONEAREST
);
665 /* Calculate the maximum size of the tray window and limit the window
666 size to half of the screen's size. */
667 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
668 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
669 if (szWnd
.cx
> szMax
.cx
)
671 if (szWnd
.cy
> szMax
.cy
)
674 /* FIXME - calculate */
676 GetTrayRectFromScreenRect(
687 GetMinimumWindowSize(
692 AdjustWindowRectEx(&rcMin
,
693 GetWindowLong(m_hWnd
,
696 GetWindowLong(m_hWnd
,
704 DWORD
GetDraggingRectFromPt(
707 OUT HMONITOR
*phMonitor
)
709 HMONITOR hMon
, hMonNew
;
710 DWORD PosH
, PosV
, Pos
;
711 SIZE DeltaPt
, ScreenOffset
;
717 /* Determine the screen rectangle */
718 hMon
= MonitorFromPoint(pt
,
719 MONITOR_DEFAULTTONULL
);
725 mi
.cbSize
= sizeof(mi
);
726 if (!GetMonitorInfo(hMon
,
730 goto GetPrimaryScreenRect
;
733 /* make left top corner of the screen zero based to
734 make calculations easier */
735 pt
.x
-= mi
.rcMonitor
.left
;
736 pt
.y
-= mi
.rcMonitor
.top
;
738 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
739 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
740 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
741 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
745 GetPrimaryScreenRect
:
748 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
749 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
752 /* Calculate the nearest screen border */
753 if (pt
.x
< rcScreen
.right
/ 2)
760 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
764 if (pt
.y
< rcScreen
.bottom
/ 2)
771 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
775 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
777 /* Fix the screen origin to be relative to the primary monitor again */
778 OffsetRect(&rcScreen
,
782 RECT rcPos
= m_TrayRects
[Pos
];
784 hMonNew
= GetMonitorFromRect(&rcPos
);
789 /* Recalculate the rectangle, we're dragging to another monitor.
790 We don't need to recalculate the rect on single monitor systems. */
791 szTray
.cx
= rcPos
.right
- rcPos
.left
;
792 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
794 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
797 pRect
->left
+= m_AutoHideOffset
.cx
;
798 pRect
->right
+= m_AutoHideOffset
.cx
;
799 pRect
->top
+= m_AutoHideOffset
.cy
;
800 pRect
->bottom
+= m_AutoHideOffset
.cy
;
806 /* The user is dragging the tray window on the same monitor. We don't need
807 to recalculate the rectangle */
811 pRect
->left
+= m_AutoHideOffset
.cx
;
812 pRect
->right
+= m_AutoHideOffset
.cx
;
813 pRect
->top
+= m_AutoHideOffset
.cy
;
814 pRect
->bottom
+= m_AutoHideOffset
.cy
;
823 DWORD
GetDraggingRectFromRect(
825 OUT HMONITOR
*phMonitor
)
829 /* Calculate the center of the rectangle. We call
830 GetDraggingRectFromPt to calculate a valid
831 dragging rectangle */
832 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
833 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
835 return GetDraggingRectFromPt(
841 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
847 rcTray
.left
= pwp
->x
;
849 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
850 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
853 rcTray
.left
-= m_AutoHideOffset
.cx
;
854 rcTray
.right
-= m_AutoHideOffset
.cx
;
855 rcTray
.top
-= m_AutoHideOffset
.cy
;
856 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
859 if (!EqualRect(&rcTray
,
860 &m_TrayRects
[m_DraggingPosition
]))
862 /* Recalculate the rectangle, the user dragged the tray
863 window to another monitor or the window was somehow else
865 m_DraggingPosition
= GetDraggingRectFromRect(
868 //m_TrayRects[DraggingPosition] = rcTray;
871 //Monitor = CalculateValidSize(
875 m_Monitor
= m_DraggingMonitor
;
876 m_Position
= m_DraggingPosition
;
879 m_TrayRects
[m_Position
] = rcTray
;
882 else if (GetWindowRect(m_hWnd
, &rcTray
))
886 if (!(pwp
->flags
& SWP_NOMOVE
))
888 rcTray
.left
= pwp
->x
;
892 if (!(pwp
->flags
& SWP_NOSIZE
))
894 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
895 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
898 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
900 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
907 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
912 rcTray
.left
-= m_AutoHideOffset
.cx
;
913 rcTray
.right
-= m_AutoHideOffset
.cx
;
914 rcTray
.top
-= m_AutoHideOffset
.cy
;
915 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
917 m_TrayRects
[m_Position
] = rcTray
;
921 /* If the user isn't resizing the tray window we need to make sure the
922 new size or position is valid. this is to prevent changes to the window
923 without user interaction. */
924 rcTray
= m_TrayRects
[m_Position
];
928 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
929 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
933 rcTray
.left
+= m_AutoHideOffset
.cx
;
934 rcTray
.right
+= m_AutoHideOffset
.cx
;
935 rcTray
.top
+= m_AutoHideOffset
.cy
;
936 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
939 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
940 pwp
->x
= rcTray
.left
;
942 pwp
->cx
= m_TraySize
.cx
;
943 pwp
->cy
= m_TraySize
.cy
;
947 VOID
ApplyClipping(IN BOOL Clip
)
949 RECT rcClip
, rcWindow
;
952 if (GetWindowRect(m_hWnd
, &rcWindow
))
954 /* Disable clipping on systems with only one monitor */
955 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
962 GetScreenRect(m_Monitor
, &rcClip
);
964 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
973 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
978 /* Set the clipping region or make sure the window isn't clipped
979 by disabling it explicitly. */
980 SetWindowRgn(m_hWnd
, hClipRgn
, TRUE
);
984 VOID
ResizeWorkArea()
986 #if !WIN7_COMPAT_MODE
987 RECT rcTray
, rcWorkArea
;
989 /* If monitor has changed then fix the previous monitors work area */
990 if (m_PreviousMonitor
!= m_Monitor
)
992 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
993 SystemParametersInfo(SPI_SETWORKAREA
,
999 rcTray
= m_TrayRects
[m_Position
];
1001 GetScreenRect(m_Monitor
, &rcWorkArea
);
1002 m_PreviousMonitor
= m_Monitor
;
1004 /* If AutoHide is false then change the workarea to exclude the area that
1005 the taskbar covers. */
1011 rcWorkArea
.top
= rcTray
.bottom
;
1014 rcWorkArea
.left
= rcTray
.right
;
1017 rcWorkArea
.right
= rcTray
.left
;
1020 rcWorkArea
.bottom
= rcTray
.top
;
1025 SystemParametersInfo(SPI_SETWORKAREA
,
1032 VOID
CheckTrayWndPosition()
1036 rcTray
= m_TrayRects
[m_Position
];
1040 rcTray
.left
+= m_AutoHideOffset
.cx
;
1041 rcTray
.right
+= m_AutoHideOffset
.cx
;
1042 rcTray
.top
+= m_AutoHideOffset
.cy
;
1043 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1046 /* Move the tray window */
1050 rcTray
.right
- rcTray
.left
,
1051 rcTray
.bottom
- rcTray
.top
,
1056 ApplyClipping(TRUE
);
1059 typedef struct _TW_STUCKRECTS2
1067 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1069 VOID
RegLoadSettings()
1074 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1075 DWORD cbSize
= sizeof(sr
);
1076 SIZE StartBtnSize
= m_StartButton
.GetSize();
1078 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1079 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1080 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1081 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1083 if (SHGetValue(hkExplorer
,
1084 TEXT("StuckRects2"),
1088 &cbSize
) == ERROR_SUCCESS
&&
1089 sr
.cbSize
== sizeof(sr
))
1091 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1092 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1093 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1094 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1096 /* FIXME: Are there more flags? */
1098 #if WIN7_COMPAT_MODE
1099 m_Position
= ABE_LEFT
;
1101 if (sr
.Position
> ABE_BOTTOM
)
1102 m_Position
= ABE_BOTTOM
;
1104 m_Position
= sr
.Position
;
1107 /* Try to find out which monitor the tray window was located on last.
1108 Here we're only interested in the monitor screen that we think
1109 is the last one used. We're going to determine on which monitor
1110 we really are after calculating the docked position. */
1112 GetScreenRectFromRect(
1114 MONITOR_DEFAULTTONEAREST
);
1118 m_Position
= ABE_BOTTOM
;
1121 /* Use the minimum size of the taskbar, we'll use the start
1122 button as a minimum for now. Make sure we calculate the
1123 entire window size, not just the client size. However, we
1124 use a thinner border than a standard thick border, so that
1125 the start button and bands are not stuck to the screen border. */
1126 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1127 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1129 /* Use the primary screen by default */
1132 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1133 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1134 GetScreenRectFromRect(
1136 MONITOR_DEFAULTTOPRIMARY
);
1141 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1146 SWP_NOMOVE
| SWP_NOSIZE
);
1148 /* Determine a minimum tray window rectangle. The "client" height is
1149 zero here since we cannot determine an optimal minimum width when
1150 loaded as a vertical tray window. We just need to make sure the values
1151 loaded from the registry are at least. The windows explorer behaves
1152 the same way, it allows the user to save a zero width vertical tray
1153 window, but not a zero height horizontal tray window. */
1154 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1155 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1157 if (WndSize
.cx
< sr
.Size
.cx
)
1158 WndSize
.cx
= sr
.Size
.cx
;
1159 if (WndSize
.cy
< sr
.Size
.cy
)
1160 WndSize
.cy
= sr
.Size
.cy
;
1162 /* Save the calculated size */
1163 m_TraySize
= WndSize
;
1165 /* Calculate all docking rectangles. We need to do this here so they're
1166 initialized and dragging the tray window to another position gives
1168 for (Pos
= ABE_LEFT
;
1172 GetTrayRectFromScreenRect(
1177 // 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);
1180 /* Determine which monitor we are on. It shouldn't matter which docked
1181 position rectangle we use */
1182 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1187 IN POINT
*ppt OPTIONAL
,
1188 IN HWND hwndExclude OPTIONAL
,
1190 IN BOOL IsContextMenu
)
1192 TPMPARAMS tmp
, *ptmp
= NULL
;
1197 if (hwndExclude
!= NULL
)
1199 /* Get the client rectangle and map it to screen coordinates */
1200 if (::GetClientRect(hwndExclude
,
1202 MapWindowPoints(hwndExclude
,
1204 (LPPOINT
) &tmp
.rcExclude
,
1214 GetClientRect(&tmp
.rcExclude
) &&
1215 MapWindowPoints(m_hWnd
,
1217 (LPPOINT
) &tmp
.rcExclude
,
1225 /* NOTE: TrackPopupMenuEx will eventually align the track position
1226 for us, no need to take care of it here as long as the
1227 coordinates are somewhere within the exclusion rectangle */
1228 pt
.x
= ptmp
->rcExclude
.left
;
1229 pt
.y
= ptmp
->rcExclude
.top
;
1237 tmp
.cbSize
= sizeof(tmp
);
1239 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
1240 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
1242 fuFlags
|= TPM_RIGHTBUTTON
;
1244 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
1246 cmdId
= TrackPopupMenuEx(hMenu
,
1256 HRESULT
TrackCtxMenu(
1257 IN IContextMenu
* contextMenu
,
1258 IN POINT
*ppt OPTIONAL
,
1259 IN HWND hwndExclude OPTIONAL
,
1261 IN PVOID Context OPTIONAL
)
1267 HMENU popup
= CreatePopupMenu();
1272 TRACE("Before Query\n");
1273 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
1274 if (FAILED_UNEXPECTEDLY(hr
))
1276 TRACE("Query failed\n");
1281 TRACE("Before Tracking\n");
1282 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
1286 TRACE("Before InvokeCommand\n");
1287 CMINVOKECOMMANDINFO cmi
= { 0 };
1288 cmi
.cbSize
= sizeof(cmi
);
1289 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
1291 hr
= contextMenu
->InvokeCommand(&cmi
);
1295 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
1303 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1306 SIZE TraySize
, StartSize
;
1307 POINT ptTrayNotify
= { 0, 0 };
1311 m_StartButton
.UpdateSize();
1312 if (prcClient
!= NULL
)
1314 rcClient
= *prcClient
;
1318 if (!GetClientRect(&rcClient
))
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);
1332 /* Limit the Start button width to the client width, if neccessary */
1333 StartSize
= m_StartButton
.GetSize();
1334 if (StartSize
.cx
> rcClient
.right
)
1335 StartSize
.cx
= rcClient
.right
;
1337 if (m_StartButton
.m_hWnd
!= NULL
)
1339 /* Resize and reposition the button */
1340 dwp
= DeferWindowPos(dwp
,
1341 m_StartButton
.m_hWnd
,
1347 SWP_NOZORDER
| SWP_NOACTIVATE
);
1352 /* Determine the size that the tray notification window needs */
1356 TraySize
.cy
= rcClient
.bottom
;
1360 TraySize
.cx
= rcClient
.right
;
1364 if (m_TrayNotify
!= NULL
&&
1365 SendMessage(m_TrayNotify
,
1366 TNWM_GETMINIMUMSIZE
,
1367 (WPARAM
) Horizontal
,
1368 (LPARAM
) &TraySize
))
1370 /* Move the tray notification window to the desired location */
1372 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1374 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1376 dwp
= DeferWindowPos(dwp
,
1383 SWP_NOZORDER
| SWP_NOACTIVATE
);
1388 /* Resize/Move the rebar control */
1389 if (m_Rebar
!= NULL
)
1391 POINT ptRebar
= { 0, 0 };
1394 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1398 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1399 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1400 szRebar
.cy
= rcClient
.bottom
;
1404 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1405 szRebar
.cx
= rcClient
.right
;
1406 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1409 dwp
= DeferWindowPos(dwp
,
1416 SWP_NOZORDER
| SWP_NOACTIVATE
);
1420 EndDeferWindowPos(dwp
);
1422 if (m_TaskSwitch
!= NULL
)
1424 /* Update the task switch window configuration */
1425 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1429 LRESULT
OnThemeChanged()
1432 CloseThemeData(m_Theme
);
1434 if (IsThemeActive())
1435 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
1441 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1445 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1451 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1453 return OnThemeChanged();
1456 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1458 WCHAR szStartCaption
[32];
1460 ((ITrayWindow
*)this)->AddRef();
1462 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1465 InterlockedIncrement(&TrayWndCount
);
1467 if (!LoadString(hExplorerInstance
,
1470 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1472 szStartCaption
[0] = TEXT('\0');
1475 if (m_CaptionFont
== NULL
)
1477 NONCLIENTMETRICS ncm
;
1479 /* Get the system fonts, we use the caption font,
1480 always bold, though. */
1481 ncm
.cbSize
= sizeof(ncm
);
1482 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
1484 if (m_CaptionFont
== NULL
)
1486 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1487 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1492 /* Create the Start button */
1493 m_StartButton
.SubclassWindow(CreateWindowEx(
1497 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1498 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1504 (HMENU
) IDC_STARTBTN
,
1508 if (m_StartButton
.m_hWnd
)
1510 m_StartButton
.Initialize();
1513 /* Load the saved tray window settings */
1516 /* Create and initialize the start menu */
1517 HBITMAP hbmBanner
= LoadBitmap(hExplorerInstance
, MAKEINTRESOURCE(IDB_STARTMENU
));
1518 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
1520 /* Load the tray band site */
1521 if (m_TrayBandSite
!= NULL
)
1523 m_TrayBandSite
.Release();
1526 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
1527 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
1529 /* Create the tray notification window */
1530 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
);
1532 if (UpdateNonClientMetrics())
1537 /* Move the tray window to the right position and resize it if neccessary */
1538 CheckTrayWndPosition();
1540 /* Align all controls on the tray window */
1544 InitShellServices(&(m_ShellServices
));
1548 m_AutoHideState
= AUTOHIDE_HIDING
;
1549 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1552 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
1553 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
1554 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
1555 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
1556 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
1557 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
1558 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
1559 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
1560 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
1561 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
1562 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
1563 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
1568 HRESULT STDMETHODCALLTYPE
Open()
1572 /* Check if there's already a window created and try to show it.
1573 If it was somehow destroyed just create a new tray window. */
1574 if (m_hWnd
!= NULL
&& IsWindow())
1576 if (!IsWindowVisible(m_hWnd
))
1578 CheckTrayWndPosition();
1580 ShowWindow(SW_SHOW
);
1586 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1588 dwExStyle
|= WS_EX_TOPMOST
;
1590 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1591 WS_BORDER
| WS_THICKFRAME
;
1593 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1594 if (m_Position
!= (DWORD
) -1)
1595 rcWnd
= m_TrayRects
[m_Position
];
1597 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1603 HRESULT STDMETHODCALLTYPE
Close()
1616 HWND STDMETHODCALLTYPE
GetHWND()
1621 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1623 return (m_hWnd
== hWnd
||
1624 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1627 BOOL STDMETHODCALLTYPE
1630 return IsPosHorizontal();
1633 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1635 if (phBoldCaption
!= NULL
)
1636 *phBoldCaption
= m_StartButton
.GetFont();
1638 return m_CaptionFont
;
1641 DWORD WINAPI
TrayPropertiesThread()
1646 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1647 hwnd
= CreateWindowEx(0,
1650 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1653 posRect
.right
- posRect
.left
,
1654 posRect
.bottom
- posRect
.top
,
1660 m_TrayPropertiesOwner
= hwnd
;
1662 DisplayTrayProperties(hwnd
);
1664 m_TrayPropertiesOwner
= NULL
;
1670 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1672 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1674 return This
->TrayPropertiesThread();
1677 HWND STDMETHODCALLTYPE
DisplayProperties()
1681 if (m_TrayPropertiesOwner
)
1683 hTrayProp
= GetLastActivePopup(m_TrayPropertiesOwner
);
1684 if (hTrayProp
!= NULL
&&
1685 hTrayProp
!= m_TrayPropertiesOwner
)
1687 SetForegroundWindow(hTrayProp
);
1692 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1696 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1698 WCHAR szDir
[MAX_PATH
];
1700 if (SHGetSpecialFolderPath(hWndOwner
,
1702 CSIDL_COMMON_STARTMENU
,
1705 ShellExecute(hWndOwner
,
1714 VOID
OpenTaskManager(IN HWND hWndOwner
)
1716 ShellExecute(hWndOwner
,
1718 TEXT("taskmgr.exe"),
1724 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1726 BOOL bHandled
= TRUE
;
1730 case ID_SHELL_CMD_PROPERTIES
:
1731 DisplayProperties();
1734 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1735 OpenCommonStartMenuDirectory(m_hWnd
,
1739 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1740 OpenCommonStartMenuDirectory(m_hWnd
,
1744 case ID_LOCKTASKBAR
:
1745 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1751 case ID_SHELL_CMD_OPEN_TASKMGR
:
1752 OpenTaskManager(m_hWnd
);
1755 case ID_SHELL_CMD_UNDO_ACTION
:
1758 case ID_SHELL_CMD_SHOW_DESKTOP
:
1761 case ID_SHELL_CMD_TILE_WND_H
:
1762 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1765 case ID_SHELL_CMD_TILE_WND_V
:
1766 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1769 case ID_SHELL_CMD_CASCADE_WND
:
1770 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1773 case ID_SHELL_CMD_CUST_NOTIF
:
1776 case ID_SHELL_CMD_ADJUST_DAT
:
1777 //FIXME: Use SHRunControlPanel
1778 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
1782 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1790 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1795 if (Locked
!= bLock
)
1799 if (m_TrayBandSite
!= NULL
)
1801 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1813 LRESULT
DrawBackground(HDC hdc
)
1818 GetClientRect(&rect
);
1822 GetClientRect(&rect
);
1826 partId
= TBP_BACKGROUNDLEFT
;
1829 partId
= TBP_BACKGROUNDTOP
;
1832 partId
= TBP_BACKGROUNDRIGHT
;
1836 partId
= TBP_BACKGROUNDBOTTOM
;
1840 DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1846 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1848 HDC hdc
= (HDC
) wParam
;
1856 return DrawBackground(hdc
);
1859 int DrawSizer(IN HRGN hRgn
)
1865 GetWindowRect(m_hWnd
, &rect
);
1866 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1868 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1873 backoundPart
= TBP_SIZINGBARLEFT
;
1874 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1877 backoundPart
= TBP_SIZINGBARTOP
;
1878 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1881 backoundPart
= TBP_SIZINGBARRIGHT
;
1882 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1886 backoundPart
= TBP_SIZINGBARBOTTOM
;
1887 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1891 DrawThemeBackground(m_Theme
, hdc
, backoundPart
, 0, &rect
, 0);
1893 ReleaseDC(m_hWnd
, hdc
);
1897 DWORD WINAPI
RunFileDlgThread()
1902 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1904 hwnd
= CreateWindowEx(0,
1907 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1910 posRect
.right
- posRect
.left
,
1911 posRect
.bottom
- posRect
.top
,
1917 m_RunFileDlgOwner
= hwnd
;
1919 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1921 m_RunFileDlgOwner
= NULL
;
1922 ::DestroyWindow(hwnd
);
1927 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1929 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1930 return This
->RunFileDlgThread();
1933 void DisplayRunFileDlg()
1936 if (m_RunFileDlgOwner
)
1938 hRunDlg
= GetLastActivePopup(m_RunFileDlgOwner
);
1939 if (hRunDlg
!= NULL
&&
1940 hRunDlg
!= m_RunFileDlgOwner
)
1942 SetForegroundWindow(hRunDlg
);
1947 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1950 void PopupStartMenu()
1952 if (m_StartMenuPopup
!= NULL
)
1958 if (GetWindowRect(m_StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1963 pt
.x
= rcExclude
.left
;
1964 pt
.y
= rcExclude
.top
;
1965 dwFlags
|= MPPF_BOTTOM
;
1969 pt
.x
= rcExclude
.left
;
1970 pt
.y
= rcExclude
.bottom
;
1971 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
1974 pt
.x
= rcExclude
.right
;
1975 pt
.y
= rcExclude
.bottom
;
1976 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
1980 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
1982 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
1987 void ProcessMouseTracking()
1992 UINT state
= m_AutoHideState
;
1995 GetWindowRect(m_hWnd
, &rcCurrent
);
1996 over
= PtInRect(&rcCurrent
, pt
);
1998 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2005 if (state
== AUTOHIDE_HIDING
)
2007 TRACE("AutoHide cancelling hide.\n");
2008 m_AutoHideState
= AUTOHIDE_SHOWING
;
2009 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2011 else if (state
== AUTOHIDE_HIDDEN
)
2013 TRACE("AutoHide starting show.\n");
2014 m_AutoHideState
= AUTOHIDE_SHOWING
;
2015 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2020 if (state
== AUTOHIDE_SHOWING
)
2022 TRACE("AutoHide cancelling show.\n");
2023 m_AutoHideState
= AUTOHIDE_HIDING
;
2024 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2026 else if (state
== AUTOHIDE_SHOWN
)
2028 TRACE("AutoHide starting hide.\n");
2029 m_AutoHideState
= AUTOHIDE_HIDING
;
2030 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2033 KillTimer(TIMER_ID_MOUSETRACK
);
2037 void ProcessAutoHide()
2039 RECT rc
= m_TrayRects
[m_Position
];
2040 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2041 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2043 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
);
2045 switch (m_AutoHideState
)
2047 case AUTOHIDE_HIDING
:
2051 m_AutoHideOffset
.cy
= 0;
2052 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2053 if (m_AutoHideOffset
.cx
< -w
)
2054 m_AutoHideOffset
.cx
= -w
;
2057 m_AutoHideOffset
.cx
= 0;
2058 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2059 if (m_AutoHideOffset
.cy
< -h
)
2060 m_AutoHideOffset
.cy
= -h
;
2063 m_AutoHideOffset
.cy
= 0;
2064 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2065 if (m_AutoHideOffset
.cx
> w
)
2066 m_AutoHideOffset
.cx
= w
;
2069 m_AutoHideOffset
.cx
= 0;
2070 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2071 if (m_AutoHideOffset
.cy
> h
)
2072 m_AutoHideOffset
.cy
= h
;
2076 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
2078 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2083 case AUTOHIDE_HIDDEN
:
2088 m_AutoHideOffset
.cx
= -w
;
2089 m_AutoHideOffset
.cy
= 0;
2092 m_AutoHideOffset
.cx
= 0;
2093 m_AutoHideOffset
.cy
= -h
;
2096 m_AutoHideOffset
.cx
= w
;
2097 m_AutoHideOffset
.cy
= 0;
2100 m_AutoHideOffset
.cx
= 0;
2101 m_AutoHideOffset
.cy
= h
;
2105 KillTimer(TIMER_ID_AUTOHIDE
);
2106 m_AutoHideState
= AUTOHIDE_HIDDEN
;
2109 case AUTOHIDE_SHOWING
:
2110 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2112 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2114 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2116 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2120 m_AutoHideOffset
.cx
= 0;
2123 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2125 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2127 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2129 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2133 m_AutoHideOffset
.cy
= 0;
2136 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
2138 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2143 case AUTOHIDE_SHOWN
:
2145 KillTimer(TIMER_ID_AUTOHIDE
);
2146 m_AutoHideState
= AUTOHIDE_SHOWN
;
2150 rc
.left
+= m_AutoHideOffset
.cx
;
2151 rc
.right
+= m_AutoHideOffset
.cx
;
2152 rc
.top
+= m_AutoHideOffset
.cy
;
2153 rc
.bottom
+= m_AutoHideOffset
.cy
;
2155 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
2156 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2159 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2161 /* Load the saved tray window settings */
2164 /* Move the tray window to the right position and resize it if neccessary */
2165 CheckTrayWndPosition();
2167 /* Align all controls on the tray window */
2168 AlignControls(NULL
);
2173 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2177 TrayNotify_NotifyMsg(wParam
, lParam
);
2182 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2190 return DrawSizer((HRGN
) wParam
);
2193 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2195 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2196 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2199 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2206 /* The user may not be able to resize the tray window.
2207 Pretend like the window is not sizeable when the user
2208 clicks on the border. */
2212 SetLastError(ERROR_SUCCESS
);
2213 if (GetClientRect(&rcClient
) &&
2214 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2216 pt
.x
= (SHORT
) LOWORD(lParam
);
2217 pt
.y
= (SHORT
) HIWORD(lParam
);
2219 if (PtInRect(&rcClient
,
2222 /* The user is trying to drag the tray window */
2226 /* Depending on the position of the tray window, allow only
2227 changing the border next to the monitor working area */
2231 if (pt
.y
> rcClient
.bottom
)
2235 if (pt
.x
> rcClient
.right
)
2239 if (pt
.x
< rcClient
.left
)
2244 if (pt
.y
< rcClient
.top
)
2253 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2256 PRECT pRect
= (PRECT
) lParam
;
2258 /* We need to ensure that an application can not accidently
2259 move the tray window (using SetWindowPos). However, we still
2260 need to be able to move the window in case the user wants to
2261 drag the tray window to another position or in case the user
2262 wants to resize the tray window. */
2263 if (!Locked
&& GetCursorPos(&ptCursor
))
2266 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2270 *pRect
= m_TrayRects
[m_Position
];
2274 pRect
->left
+= m_AutoHideOffset
.cx
;
2275 pRect
->right
+= m_AutoHideOffset
.cx
;
2276 pRect
->top
+= m_AutoHideOffset
.cy
;
2277 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2283 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2285 PRECT pRect
= (PRECT
) lParam
;
2289 CalculateValidSize(m_Position
, pRect
);
2293 *pRect
= m_TrayRects
[m_Position
];
2297 pRect
->left
+= m_AutoHideOffset
.cx
;
2298 pRect
->right
+= m_AutoHideOffset
.cx
;
2299 pRect
->top
+= m_AutoHideOffset
.cy
;
2300 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2306 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2308 ChangingWinPos((LPWINDOWPOS
) lParam
);
2312 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2315 InvalidateRect(NULL
, TRUE
);
2316 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2319 /* Clip the tray window on multi monitor systems so the edges can't
2320 overlap into another monitor */
2321 ApplyClipping(TRUE
);
2323 if (!GetClientRect(&rcClient
))
2330 rcClient
.left
= rcClient
.top
= 0;
2331 rcClient
.right
= LOWORD(lParam
);
2332 rcClient
.bottom
= HIWORD(lParam
);
2335 AlignControls(&rcClient
);
2339 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2345 /* Remove the clipping on multi monitor systems while dragging around */
2346 ApplyClipping(FALSE
);
2351 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2356 /* Apply clipping */
2357 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2362 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2368 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2369 The tray window needs to handle this specially, since it normally doesn't have
2372 static const UINT uidDisableItem
[] = {
2383 /* temporarily enable the system menu */
2384 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2386 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2387 if (hSysMenu
!= NULL
)
2389 /* Disable all items that are not relevant */
2390 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2392 EnableMenuItem(hSysMenu
,
2394 MF_BYCOMMAND
| MF_GRAYED
);
2397 EnableMenuItem(hSysMenu
,
2400 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2402 /* Display the system menu */
2406 m_StartButton
.m_hWnd
,
2407 m_Position
!= ABE_TOP
,
2411 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2415 /* revert the system menu window style */
2416 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2426 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2428 /* We want the user to be able to get a context menu even on the nonclient
2429 area (including the sizing border)! */
2430 uMsg
= WM_CONTEXTMENU
;
2431 wParam
= (WPARAM
) m_hWnd
;
2433 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2436 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2438 LRESULT Ret
= FALSE
;
2439 POINT pt
, *ppt
= NULL
;
2440 HWND hWndExclude
= NULL
;
2442 /* Check if the administrator has forbidden access to context menus */
2443 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2446 pt
.x
= (SHORT
) LOWORD(lParam
);
2447 pt
.y
= (SHORT
) HIWORD(lParam
);
2449 if (pt
.x
!= -1 || pt
.y
!= -1)
2452 hWndExclude
= m_StartButton
.m_hWnd
;
2454 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2456 /* Make sure we can't track the context menu if the start
2457 menu is currently being shown */
2458 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2460 CComPtr
<IContextMenu
> ctxMenu
;
2461 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2462 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2467 /* See if the context menu should be handled by the task band site */
2468 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2471 POINT ptClient
= *ppt
;
2473 /* Convert the coordinates to client-coordinates */
2474 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2476 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2477 if (hWndAtPt
!= NULL
&&
2478 (hWndAtPt
== m_Rebar
|| IsChild(m_Rebar
, hWndAtPt
)))
2480 /* Check if the user clicked on the task switch window */
2482 MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2484 hWndAtPt
= ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2485 if (hWndAtPt
== m_TaskSwitch
)
2486 goto HandleTrayContextMenu
;
2488 /* Forward the message to the task band site */
2489 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2492 goto HandleTrayContextMenu
;
2496 HandleTrayContextMenu
:
2497 /* Tray the default tray window context menu */
2498 CComPtr
<IContextMenu
> ctxMenu
;
2499 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2500 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2506 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2508 LRESULT Ret
= FALSE
;
2509 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2510 the rebar control! But we shouldn't forward messages that the band
2511 site doesn't handle, such as other controls (start button, tray window */
2513 HRESULT hr
= E_FAIL
;
2517 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2522 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2524 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2526 if (nmh
->hwndFrom
== m_TrayNotify
)
2531 /* Cause all controls to be aligned */
2532 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2540 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2542 /* We "handle" this message so users can't cause a weird maximize/restore
2543 window animation when double-clicking the tray window! */
2545 /* We should forward mouse messages to child windows here.
2546 Right now, this is only clock double-click */
2548 if (TrayNotify_GetClockRect(&rcClock
))
2551 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2552 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2553 if (PtInRect(&rcClock
, ptClick
))
2555 //FIXME: use SHRunControlPanel
2556 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2562 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2568 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2571 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2572 if (FAILED_UNEXPECTEDLY(hr
))
2575 if (IsWindowVisible(hwndStartMenu
))
2577 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2587 LRESULT
DoExitWindows()
2589 ExitWindowsDialog(m_hWnd
);
2593 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2596 * TWM_DOEXITWINDOWS is send by the CDesktopBrowserr to us to
2597 * show the shutdown dialog
2599 return DoExitWindows();
2602 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2604 if (wParam
== SC_CLOSE
)
2606 return DoExitWindows();
2613 HRESULT
ExecResourceCmd(int id
)
2615 WCHAR szCommand
[256];
2616 WCHAR
*pszParameters
;
2618 if (!LoadString(hExplorerInstance
,
2621 sizeof(szCommand
) / sizeof(szCommand
[0])))
2626 pszParameters
= wcschr(szCommand
, L
'>');
2633 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, 0);
2637 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2642 DisplayRunFileDlg();
2645 ExecResourceCmd(IDS_HELP_COMMAND
);
2648 ShellExecuteW(0, L
"explore", NULL
, NULL
, NULL
, 1);
2651 SHFindFiles(NULL
, NULL
);
2653 case IDHK_FIND_COMPUTER
:
2654 SHFindComputer(NULL
, NULL
);
2656 case IDHK_SYS_PROPERTIES
:
2657 //FIXME: Use SHRunControlPanel
2658 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
2660 case IDHK_NEXT_TASK
:
2662 case IDHK_PREV_TASK
:
2664 case IDHK_MINIMIZE_ALL
:
2666 case IDHK_RESTORE_ALL
:
2677 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2679 LRESULT Ret
= FALSE
;
2681 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2687 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2689 switch (LOWORD(wParam
))
2691 /* FIXME: Handle these commands as well */
2692 case IDM_TASKBARANDSTARTMENU
:
2693 DisplayProperties();
2697 SHFindFiles(NULL
, NULL
);
2700 case IDM_HELPANDSUPPORT
:
2701 ExecResourceCmd(IDS_HELP_COMMAND
);
2705 DisplayRunFileDlg();
2708 /* FIXME: Handle these commands as well */
2709 case IDM_SYNCHRONIZE
:
2711 case IDM_DISCONNECT
:
2712 case IDM_UNDOCKCOMPUTER
:
2723 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2727 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2733 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2735 if (wParam
== TIMER_ID_MOUSETRACK
)
2737 ProcessMouseTracking();
2739 else if (wParam
== TIMER_ID_AUTOHIDE
)
2748 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2751 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2757 ::GetWindowRect(m_hWnd
, &rc
);
2761 rc
.bottom
- rc
.top
};
2763 as
->rcTarget
.right
- as
->rcTarget
.left
,
2764 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2766 as
->rcActual
.right
- as
->rcActual
.left
,
2767 as
->rcActual
.bottom
- as
->rcActual
.top
};
2770 szWindow
.cx
- szTarget
.cx
,
2771 szWindow
.cy
- szTarget
.cx
,
2777 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2780 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2783 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2784 rc
.left
= rc
.right
- szWindow
.cy
;
2787 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2788 rc
.top
= rc
.bottom
- szWindow
.cy
;
2792 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2799 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2801 BEGIN_MSG_MAP(CTrayWindow
)
2802 if (m_StartMenuBand
!= NULL
)
2809 Msg
.wParam
= wParam
;
2810 Msg
.lParam
= lParam
;
2812 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2817 wParam
= Msg
.wParam
;
2818 lParam
= Msg
.lParam
;
2820 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2821 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2822 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2823 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2824 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2825 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2826 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2827 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2828 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2829 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2830 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2831 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2832 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2833 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2834 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2835 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2836 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2837 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2838 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2839 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2840 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2841 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2842 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2843 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2844 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2845 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2846 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2847 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2848 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2849 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2853 /*****************************************************************************/
2855 VOID
TrayProcessMessages()
2859 /* FIXME: We should keep a reference here... */
2861 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2863 if (Msg
.message
== WM_QUIT
)
2866 if (m_StartMenuBand
== NULL
||
2867 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2869 TranslateMessage(&Msg
);
2870 DispatchMessage(&Msg
);
2875 VOID
TrayMessageLoop()
2880 /* FIXME: We should keep a reference here... */
2884 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2886 if (!Ret
|| Ret
== -1)
2889 if (m_StartMenuBand
== NULL
||
2890 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2892 TranslateMessage(&Msg
);
2893 DispatchMessage(&Msg
);
2901 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2902 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2903 * The reason we implement it is because we have to use SHCreateDesktop() so
2904 * that the shell provides the desktop window and all the features that come
2905 * with it (especially positioning of desktop icons)
2908 virtual ULONG STDMETHODCALLTYPE
GetState()
2910 /* FIXME: Return ABS_ flags? */
2911 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2915 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2917 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2918 *phWndTray
= m_hWnd
;
2922 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2924 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2926 m_DesktopWnd
= hWndDesktop
;
2930 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2932 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2936 virtual HRESULT
RaiseStartButton()
2938 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2944 m_Position
= (DWORD
) -1;
2947 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2949 DECLARE_PROTECT_FINAL_CONSTRUCT()
2950 BEGIN_COM_MAP(CTrayWindow
)
2951 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2952 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2956 class CTrayWindowCtxMenu
:
2957 public CComCoClass
<CTrayWindowCtxMenu
>,
2958 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2962 CComPtr
<CTrayWindow
> TrayWnd
;
2963 CComPtr
<IContextMenu
> pcm
;
2966 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
2968 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
2969 this->hWndOwner
= hWndOwner
;
2973 virtual HRESULT STDMETHODCALLTYPE
2974 QueryContextMenu(HMENU hPopup
,
2980 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
2983 return HRESULT_FROM_WIN32(GetLastError());
2985 int count
= ::GetMenuItemCount(menubase
);
2987 for (int i
= 0; i
< count
; i
++)
2991 MENUITEMINFOW mii
= { 0 };
2992 mii
.cbSize
= sizeof(mii
);
2993 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
2994 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
2995 mii
.dwTypeData
= label
;
2996 mii
.cch
= _countof(label
);
2997 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
2999 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3001 mii
.fType
|= MFT_RADIOCHECK
;
3003 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3006 ::DestroyMenu(menubase
);
3008 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3015 CheckMenuItem(hPopup
,
3017 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3019 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3021 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3029 WARN("AddContextMenus failed.\n");
3037 virtual HRESULT STDMETHODCALLTYPE
3038 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3040 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3043 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3045 CMINVOKECOMMANDINFO cmici
= { 0 };
3049 /* Setup and invoke the shell command */
3050 cmici
.cbSize
= sizeof(cmici
);
3051 cmici
.hwnd
= hWndOwner
;
3052 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3053 cmici
.nShow
= SW_NORMAL
;
3055 pcm
->InvokeCommand(&cmici
);
3060 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3067 virtual HRESULT STDMETHODCALLTYPE
3068 GetCommandString(UINT_PTR idCmd
,
3077 CTrayWindowCtxMenu()
3081 virtual ~CTrayWindowCtxMenu()
3085 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3086 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3090 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3092 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3093 mnu
->Initialize(TrayWnd
, hWndOwner
);
3098 CTrayWindow
* g_TrayWindow
;
3101 Tray_OnStartMenuDismissed()
3103 return g_TrayWindow
->RaiseStartButton();
3107 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3109 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3111 return E_OUTOFMEMORY
;
3115 g_TrayWindow
= Tray
;
3117 *ppTray
= (ITrayWindow
*) Tray
;
3122 VOID
TrayProcessMessages(ITrayWindow
*)
3124 g_TrayWindow
->TrayProcessMessages();
3127 VOID
TrayMessageLoop(ITrayWindow
*)
3129 g_TrayWindow
->TrayMessageLoop();