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
),
83 virtual ~CStartButton()
85 if (m_ImageList
!= NULL
)
86 ImageList_Destroy(m_ImageList
);
102 VOID
UpdateSize(IN HBITMAP hbmStart
= NULL
)
104 SIZE Size
= { 0, 0 };
106 if (m_ImageList
== NULL
||
107 !SendMessageW(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
109 Size
.cx
= 2 * GetSystemMetrics(SM_CXEDGE
);
110 Size
.cy
= 2 * GetSystemMetrics(SM_CYEDGE
);
112 if (hbmStart
== NULL
)
114 hbmStart
= (HBITMAP
) SendMessageW(BM_GETIMAGE
, IMAGE_BITMAP
, 0);
117 if (hbmStart
!= NULL
)
121 if (GetObject(hbmStart
, 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
)
166 m_ImageList
= ImageList_Create(IconSize
.cx
,
168 ILC_COLOR32
| ILC_MASK
,
170 if (m_ImageList
== NULL
)
173 int s
= ImageList_ReplaceIcon(m_ImageList
, -1, hIconStart
);
176 /* Failed to add the icon! */
177 ImageList_Destroy(m_ImageList
);
186 HBITMAP
CreateBitmap()
188 WCHAR szStartCaption
[32];
191 HDC hDCScreen
= NULL
;
192 SIZE Size
, SmallIcon
;
193 HBITMAP hbmpOld
, hbmp
= NULL
;
194 HBITMAP hBitmap
= NULL
;
200 /* NOTE: this is the backwards compatibility code that is used if the
201 Common Controls Version 6.0 are not available! */
203 if (!LoadString(hExplorerInstance
,
206 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
211 /* Load the start button icon */
212 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
213 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
214 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
215 MAKEINTRESOURCE(IDI_START
),
219 LR_SHARED
| LR_DEFAULTCOLOR
);
221 hDCScreen
= GetDC(NULL
);
222 if (hDCScreen
== NULL
)
225 hDC
= CreateCompatibleDC(hDCScreen
);
229 hFontOld
= (HFONT
) SelectObject(hDC
, m_Font
);
231 Ret
= GetTextExtentPoint32(hDC
,
233 _tcslen(szStartCaption
),
236 SelectObject(hDC
, hFontOld
);
240 /* Make sure the height is at least the size of a caption icon. */
241 if (hIconStart
!= NULL
)
242 Size
.cx
+= SmallIcon
.cx
+ 4;
243 Size
.cy
= max(Size
.cy
, SmallIcon
.cy
);
245 /* Create the bitmap */
246 hbmp
= CreateCompatibleBitmap(hDCScreen
,
252 /* Caluclate the button rect */
255 rcButton
.right
= Size
.cx
;
256 rcButton
.bottom
= Size
.cy
;
258 /* Draw the button */
259 hbmpOld
= (HBITMAP
) SelectObject(hDC
, hbmp
);
261 Flags
= DC_TEXT
| DC_INBUTTON
;
262 if (hIconStart
!= NULL
)
265 DrawCaptionTemp(NULL
,
273 SelectObject(hDC
, hbmpOld
);
278 /* We successfully created the bitmap! */
283 if (hDCScreen
!= NULL
)
285 ReleaseDC(NULL
, hDCScreen
);
299 NONCLIENTMETRICS ncm
;
301 SetWindowTheme(m_hWnd
, L
"Start", NULL
);
305 /* Get the system fonts, we use the caption font, always bold, though. */
306 ncm
.cbSize
= sizeof(ncm
);
307 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
309 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
310 m_Font
= CreateFontIndirect(&ncm
.lfCaptionFont
);
314 SendMessage(WM_SETFONT
, (WPARAM
) m_Font
, FALSE
);
316 if (CreateImageList())
318 BUTTON_IMAGELIST bil
;
320 /* Try to set the start button image. this requires the Common
321 Controls 6.0 to be present (XP and later) */
322 bil
.himl
= m_ImageList
;
323 bil
.margin
.left
= bil
.margin
.right
= 1;
324 bil
.margin
.top
= bil
.margin
.bottom
= 1;
325 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
327 if (SendMessageW(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
))
329 /* We're using the image list, remove the BS_BITMAP style and
330 don't center it horizontally */
331 SetWindowStyle(m_hWnd
, BS_BITMAP
| BS_RIGHT
, 0);
337 /* Fall back to the deprecated method on older systems that don't
338 support Common Controls 6.0 */
339 ImageList_Destroy(m_ImageList
);
343 HBITMAP hbmStart
= CreateBitmap();
344 if (hbmStart
!= NULL
)
346 UpdateSize(hbmStart
);
348 HBITMAP hbmOld
= (HBITMAP
) SendMessageW(BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbmStart
);
351 DeleteObject(hbmOld
);
357 public CComCoClass
<CTrayWindow
>,
358 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
359 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
361 public IShellDesktopTray
363 CStartButton m_StartButton
;
365 CComPtr
<IMenuBand
> m_StartMenuBand
;
366 CComPtr
<IMenuPopup
> m_StartMenuPopup
;
378 CTrayNotifyWnd
* m_TrayNotifyInstance
;
382 HMONITOR m_PreviousMonitor
;
383 DWORD m_DraggingPosition
;
384 HMONITOR m_DraggingMonitor
;
389 HWND m_TrayPropertiesOwner
;
390 HWND m_RunFileDlgOwner
;
392 UINT m_AutoHideState
;
393 SIZE m_AutoHideOffset
;
394 TRACKMOUSEEVENT m_MouseTrackingInfo
;
396 HDPA m_ShellServices
;
399 CComPtr
<ITrayBandSite
> m_TrayBandSite
;
407 DWORD AlwaysOnTop
: 1;
408 DWORD SmSmallIcons
: 1;
413 DWORD InSizeMove
: 1;
414 DWORD IsDragging
: 1;
415 DWORD NewPosSize
: 1;
421 m_StartButton(this, 1),
431 m_PreviousMonitor(NULL
),
432 m_DraggingPosition(0),
433 m_DraggingMonitor(NULL
),
434 m_TrayPropertiesOwner(NULL
),
435 m_RunFileDlgOwner(NULL
),
436 m_AutoHideState(NULL
),
437 m_ShellServices(NULL
),
440 ZeroMemory(&m_TrayRects
, sizeof(m_TrayRects
));
441 ZeroMemory(&m_TraySize
, sizeof(m_TraySize
));
442 ZeroMemory(&m_AutoHideOffset
, sizeof(m_AutoHideOffset
));
443 ZeroMemory(&m_MouseTrackingInfo
, sizeof(m_MouseTrackingInfo
));
446 virtual ~CTrayWindow()
448 if (m_ShellServices
!= NULL
)
450 ShutdownShellServices(m_ShellServices
);
451 m_ShellServices
= NULL
;
454 if (m_CaptionFont
!= NULL
)
456 DeleteObject(m_CaptionFont
);
457 m_CaptionFont
= NULL
;
462 DeleteObject(m_Font
);
468 CloseThemeData(m_Theme
);
472 if (InterlockedDecrement(&TrayWndCount
) == 0)
480 BOOL
UpdateNonClientMetrics()
482 NONCLIENTMETRICS ncm
;
483 ncm
.cbSize
= sizeof(ncm
);
484 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
487 DeleteObject(m_Font
);
489 m_Font
= CreateFontIndirect(&ncm
.lfMessageFont
);
496 VOID
SetWindowsFont()
498 if (m_TrayNotify
!= NULL
)
500 SendMessage(m_TrayNotify
, WM_SETFONT
, (WPARAM
) m_Font
, TRUE
);
504 HMONITOR
GetScreenRectFromRect(
511 mi
.cbSize
= sizeof(mi
);
512 hMon
= MonitorFromRect(pRect
,
518 *pRect
= mi
.rcMonitor
;
524 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
525 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
533 HMONITOR
GetMonitorFromRect(
534 IN
const RECT
*pRect
)
538 /* In case the monitor sizes or saved sizes differ a bit (probably
539 not a lot, only so the tray window overlaps into another monitor
540 now), minimize the risk that we determine a wrong monitor by
541 using the center point of the tray window if we can't determine
542 it using the rectangle. */
543 hMon
= MonitorFromRect(pRect
,
544 MONITOR_DEFAULTTONULL
);
549 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
550 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
552 /* be less error-prone, find the nearest monitor */
553 hMon
= MonitorFromPoint(pt
,
554 MONITOR_DEFAULTTONEAREST
);
560 HMONITOR
GetScreenRect(
561 IN HMONITOR hMonitor
,
564 HMONITOR hMon
= NULL
;
566 if (hMonitor
!= NULL
)
570 mi
.cbSize
= sizeof(mi
);
571 if (!GetMonitorInfo(hMonitor
,
574 /* Hm, the monitor is gone? Try to find a monitor where it
575 could be located now */
576 hMon
= GetMonitorFromRect(
579 !GetMonitorInfo(hMon
,
587 *pRect
= mi
.rcMonitor
;
594 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
595 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
601 VOID
MakeTrayRectWithSize(IN DWORD Position
,
602 IN
const SIZE
*pTraySize
,
608 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
612 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
616 pRect
->left
= pRect
->right
- pTraySize
->cx
;
621 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
626 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
627 IN
const RECT
*pScreen
,
628 IN
const SIZE
*pTraySize OPTIONAL
,
631 if (pTraySize
== NULL
)
632 pTraySize
= &m_TraySize
;
636 /* Move the border outside of the screen */
638 GetSystemMetrics(SM_CXEDGE
),
639 GetSystemMetrics(SM_CYEDGE
));
641 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
644 BOOL
IsPosHorizontal()
646 return m_Position
== ABE_TOP
|| m_Position
== ABE_BOTTOM
;
649 HMONITOR
CalculateValidSize(
658 //Horizontal = IsPosHorizontal();
660 szWnd
.cx
= pRect
->right
- pRect
->left
;
661 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
664 hMon
= GetScreenRectFromRect(
666 MONITOR_DEFAULTTONEAREST
);
668 /* Calculate the maximum size of the tray window and limit the window
669 size to half of the screen's size. */
670 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
671 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
672 if (szWnd
.cx
> szMax
.cx
)
674 if (szWnd
.cy
> szMax
.cy
)
677 /* FIXME - calculate */
679 GetTrayRectFromScreenRect(
690 GetMinimumWindowSize(
695 AdjustWindowRectEx(&rcMin
,
696 GetWindowLong(m_hWnd
,
699 GetWindowLong(m_hWnd
,
707 DWORD
GetDraggingRectFromPt(
710 OUT HMONITOR
*phMonitor
)
712 HMONITOR hMon
, hMonNew
;
713 DWORD PosH
, PosV
, Pos
;
714 SIZE DeltaPt
, ScreenOffset
;
720 /* Determine the screen rectangle */
721 hMon
= MonitorFromPoint(pt
,
722 MONITOR_DEFAULTTONULL
);
728 mi
.cbSize
= sizeof(mi
);
729 if (!GetMonitorInfo(hMon
,
733 goto GetPrimaryScreenRect
;
736 /* make left top corner of the screen zero based to
737 make calculations easier */
738 pt
.x
-= mi
.rcMonitor
.left
;
739 pt
.y
-= mi
.rcMonitor
.top
;
741 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
742 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
743 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
744 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
748 GetPrimaryScreenRect
:
751 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
752 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
755 /* Calculate the nearest screen border */
756 if (pt
.x
< rcScreen
.right
/ 2)
763 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
767 if (pt
.y
< rcScreen
.bottom
/ 2)
774 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
778 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
780 /* Fix the screen origin to be relative to the primary monitor again */
781 OffsetRect(&rcScreen
,
785 RECT rcPos
= m_TrayRects
[Pos
];
787 hMonNew
= GetMonitorFromRect(&rcPos
);
792 /* Recalculate the rectangle, we're dragging to another monitor.
793 We don't need to recalculate the rect on single monitor systems. */
794 szTray
.cx
= rcPos
.right
- rcPos
.left
;
795 szTray
.cy
= rcPos
.bottom
- rcPos
.top
;
797 GetTrayRectFromScreenRect(Pos
, &rcScreen
, &szTray
, pRect
);
800 pRect
->left
+= m_AutoHideOffset
.cx
;
801 pRect
->right
+= m_AutoHideOffset
.cx
;
802 pRect
->top
+= m_AutoHideOffset
.cy
;
803 pRect
->bottom
+= m_AutoHideOffset
.cy
;
809 /* The user is dragging the tray window on the same monitor. We don't need
810 to recalculate the rectangle */
814 pRect
->left
+= m_AutoHideOffset
.cx
;
815 pRect
->right
+= m_AutoHideOffset
.cx
;
816 pRect
->top
+= m_AutoHideOffset
.cy
;
817 pRect
->bottom
+= m_AutoHideOffset
.cy
;
826 DWORD
GetDraggingRectFromRect(
828 OUT HMONITOR
*phMonitor
)
832 /* Calculate the center of the rectangle. We call
833 GetDraggingRectFromPt to calculate a valid
834 dragging rectangle */
835 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
836 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
838 return GetDraggingRectFromPt(
844 VOID
ChangingWinPos(IN OUT LPWINDOWPOS pwp
)
850 rcTray
.left
= pwp
->x
;
852 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
853 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
856 rcTray
.left
-= m_AutoHideOffset
.cx
;
857 rcTray
.right
-= m_AutoHideOffset
.cx
;
858 rcTray
.top
-= m_AutoHideOffset
.cy
;
859 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
862 if (!EqualRect(&rcTray
,
863 &m_TrayRects
[m_DraggingPosition
]))
865 /* Recalculate the rectangle, the user dragged the tray
866 window to another monitor or the window was somehow else
868 m_DraggingPosition
= GetDraggingRectFromRect(
871 //m_TrayRects[DraggingPosition] = rcTray;
874 //Monitor = CalculateValidSize(
878 m_Monitor
= m_DraggingMonitor
;
879 m_Position
= m_DraggingPosition
;
882 m_TrayRects
[m_Position
] = rcTray
;
885 else if (GetWindowRect(m_hWnd
, &rcTray
))
889 if (!(pwp
->flags
& SWP_NOMOVE
))
891 rcTray
.left
= pwp
->x
;
895 if (!(pwp
->flags
& SWP_NOSIZE
))
897 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
898 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
901 m_Position
= GetDraggingRectFromRect(&rcTray
, &m_Monitor
);
903 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
910 MakeTrayRectWithSize(m_Position
, &szWnd
, &rcTray
);
915 rcTray
.left
-= m_AutoHideOffset
.cx
;
916 rcTray
.right
-= m_AutoHideOffset
.cx
;
917 rcTray
.top
-= m_AutoHideOffset
.cy
;
918 rcTray
.bottom
-= m_AutoHideOffset
.cy
;
920 m_TrayRects
[m_Position
] = rcTray
;
924 /* If the user isn't resizing the tray window we need to make sure the
925 new size or position is valid. this is to prevent changes to the window
926 without user interaction. */
927 rcTray
= m_TrayRects
[m_Position
];
931 m_TraySize
.cx
= rcTray
.right
- rcTray
.left
;
932 m_TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
936 rcTray
.left
+= m_AutoHideOffset
.cx
;
937 rcTray
.right
+= m_AutoHideOffset
.cx
;
938 rcTray
.top
+= m_AutoHideOffset
.cy
;
939 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
942 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
943 pwp
->x
= rcTray
.left
;
945 pwp
->cx
= m_TraySize
.cx
;
946 pwp
->cy
= m_TraySize
.cy
;
950 VOID
ApplyClipping(IN BOOL Clip
)
952 RECT rcClip
, rcWindow
;
955 if (GetWindowRect(m_hWnd
, &rcWindow
))
957 /* Disable clipping on systems with only one monitor */
958 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
965 GetScreenRect(m_Monitor
, &rcClip
);
967 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
976 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
981 /* Set the clipping region or make sure the window isn't clipped
982 by disabling it explicitly. */
983 SetWindowRgn(m_hWnd
, hClipRgn
, TRUE
);
987 VOID
ResizeWorkArea()
989 #if !WIN7_COMPAT_MODE
990 RECT rcTray
, rcWorkArea
;
992 /* If monitor has changed then fix the previous monitors work area */
993 if (m_PreviousMonitor
!= m_Monitor
)
995 GetScreenRect(m_PreviousMonitor
, &rcWorkArea
);
996 SystemParametersInfo(SPI_SETWORKAREA
,
1002 rcTray
= m_TrayRects
[m_Position
];
1004 GetScreenRect(m_Monitor
, &rcWorkArea
);
1005 m_PreviousMonitor
= m_Monitor
;
1007 /* If AutoHide is false then change the workarea to exclude the area that
1008 the taskbar covers. */
1014 rcWorkArea
.top
= rcTray
.bottom
;
1017 rcWorkArea
.left
= rcTray
.right
;
1020 rcWorkArea
.right
= rcTray
.left
;
1023 rcWorkArea
.bottom
= rcTray
.top
;
1028 SystemParametersInfo(SPI_SETWORKAREA
,
1035 VOID
CheckTrayWndPosition()
1039 rcTray
= m_TrayRects
[m_Position
];
1043 rcTray
.left
+= m_AutoHideOffset
.cx
;
1044 rcTray
.right
+= m_AutoHideOffset
.cx
;
1045 rcTray
.top
+= m_AutoHideOffset
.cy
;
1046 rcTray
.bottom
+= m_AutoHideOffset
.cy
;
1049 /* Move the tray window */
1053 rcTray
.right
- rcTray
.left
,
1054 rcTray
.bottom
- rcTray
.top
,
1059 ApplyClipping(TRUE
);
1062 typedef struct _TW_STUCKRECTS2
1070 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
1072 VOID
RegLoadSettings()
1077 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
1078 DWORD cbSize
= sizeof(sr
);
1079 SIZE StartBtnSize
= m_StartButton
.GetSize();
1081 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
1082 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
1083 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
1084 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
1086 if (SHGetValue(hkExplorer
,
1087 TEXT("StuckRects2"),
1091 &cbSize
) == ERROR_SUCCESS
&&
1092 sr
.cbSize
== sizeof(sr
))
1094 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
1095 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
1096 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
1097 HideClock
= (sr
.dwFlags
& 0x8) != 0;
1099 /* FIXME: Are there more flags? */
1101 #if WIN7_COMPAT_MODE
1102 m_Position
= ABE_LEFT
;
1104 if (sr
.Position
> ABE_BOTTOM
)
1105 m_Position
= ABE_BOTTOM
;
1107 m_Position
= sr
.Position
;
1110 /* Try to find out which monitor the tray window was located on last.
1111 Here we're only interested in the monitor screen that we think
1112 is the last one used. We're going to determine on which monitor
1113 we really are after calculating the docked position. */
1115 GetScreenRectFromRect(
1117 MONITOR_DEFAULTTONEAREST
);
1121 m_Position
= ABE_BOTTOM
;
1124 /* Use the minimum size of the taskbar, we'll use the start
1125 button as a minimum for now. Make sure we calculate the
1126 entire window size, not just the client size. However, we
1127 use a thinner border than a standard thick border, so that
1128 the start button and bands are not stuck to the screen border. */
1129 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
1130 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1132 /* Use the primary screen by default */
1135 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
1136 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
1137 GetScreenRectFromRect(
1139 MONITOR_DEFAULTTOPRIMARY
);
1144 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
1149 SWP_NOMOVE
| SWP_NOSIZE
);
1151 /* Determine a minimum tray window rectangle. The "client" height is
1152 zero here since we cannot determine an optimal minimum width when
1153 loaded as a vertical tray window. We just need to make sure the values
1154 loaded from the registry are at least. The windows explorer behaves
1155 the same way, it allows the user to save a zero width vertical tray
1156 window, but not a zero height horizontal tray window. */
1157 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
1158 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
1160 if (WndSize
.cx
< sr
.Size
.cx
)
1161 WndSize
.cx
= sr
.Size
.cx
;
1162 if (WndSize
.cy
< sr
.Size
.cy
)
1163 WndSize
.cy
= sr
.Size
.cy
;
1165 /* Save the calculated size */
1166 m_TraySize
= WndSize
;
1168 /* Calculate all docking rectangles. We need to do this here so they're
1169 initialized and dragging the tray window to another position gives
1171 for (Pos
= ABE_LEFT
;
1175 GetTrayRectFromScreenRect(
1180 // 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);
1183 /* Determine which monitor we are on. It shouldn't matter which docked
1184 position rectangle we use */
1185 m_Monitor
= GetMonitorFromRect(&m_TrayRects
[ABE_LEFT
]);
1190 IN POINT
*ppt OPTIONAL
,
1191 IN HWND hwndExclude OPTIONAL
,
1193 IN BOOL IsContextMenu
)
1195 TPMPARAMS tmp
, *ptmp
= NULL
;
1200 if (hwndExclude
!= NULL
)
1202 /* Get the client rectangle and map it to screen coordinates */
1203 if (::GetClientRect(hwndExclude
,
1205 MapWindowPoints(hwndExclude
,
1207 (LPPOINT
) &tmp
.rcExclude
,
1217 GetClientRect(&tmp
.rcExclude
) &&
1218 MapWindowPoints(m_hWnd
,
1220 (LPPOINT
) &tmp
.rcExclude
,
1228 /* NOTE: TrackPopupMenuEx will eventually align the track position
1229 for us, no need to take care of it here as long as the
1230 coordinates are somewhere within the exclusion rectangle */
1231 pt
.x
= ptmp
->rcExclude
.left
;
1232 pt
.y
= ptmp
->rcExclude
.top
;
1240 tmp
.cbSize
= sizeof(tmp
);
1242 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
1243 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
1245 fuFlags
|= TPM_RIGHTBUTTON
;
1247 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
1249 cmdId
= TrackPopupMenuEx(hMenu
,
1259 HRESULT
TrackCtxMenu(
1260 IN IContextMenu
* contextMenu
,
1261 IN POINT
*ppt OPTIONAL
,
1262 IN HWND hwndExclude OPTIONAL
,
1264 IN PVOID Context OPTIONAL
)
1270 HMENU popup
= CreatePopupMenu();
1275 TRACE("Before Query\n");
1276 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
1277 if (FAILED_UNEXPECTEDLY(hr
))
1279 TRACE("Query failed\n");
1284 TRACE("Before Tracking\n");
1285 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
1289 TRACE("Before InvokeCommand\n");
1290 CMINVOKECOMMANDINFO cmi
= { 0 };
1291 cmi
.cbSize
= sizeof(cmi
);
1292 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
1294 hr
= contextMenu
->InvokeCommand(&cmi
);
1298 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
1306 VOID
AlignControls(IN PRECT prcClient OPTIONAL
)
1309 SIZE TraySize
, StartSize
;
1310 POINT ptTrayNotify
= { 0, 0 };
1314 m_StartButton
.UpdateSize();
1315 if (prcClient
!= NULL
)
1317 rcClient
= *prcClient
;
1321 if (!GetClientRect(&rcClient
))
1323 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1328 Horizontal
= IsPosHorizontal();
1330 /* We're about to resize/move the start button, the rebar control and
1331 the tray notification control */
1332 dwp
= BeginDeferWindowPos(3);
1335 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1339 /* Limit the Start button width to the client width, if neccessary */
1340 StartSize
= m_StartButton
.GetSize();
1341 if (StartSize
.cx
> rcClient
.right
)
1342 StartSize
.cx
= rcClient
.right
;
1344 if (m_StartButton
.m_hWnd
!= NULL
)
1346 /* Resize and reposition the button */
1347 dwp
= DeferWindowPos(dwp
,
1348 m_StartButton
.m_hWnd
,
1354 SWP_NOZORDER
| SWP_NOACTIVATE
);
1357 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1362 /* Determine the size that the tray notification window needs */
1366 TraySize
.cy
= rcClient
.bottom
;
1370 TraySize
.cx
= rcClient
.right
;
1374 if (m_TrayNotify
!= NULL
&&
1375 SendMessage(m_TrayNotify
,
1376 TNWM_GETMINIMUMSIZE
,
1377 (WPARAM
) Horizontal
,
1378 (LPARAM
) &TraySize
))
1380 /* Move the tray notification window to the desired location */
1382 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1384 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1386 dwp
= DeferWindowPos(dwp
,
1393 SWP_NOZORDER
| SWP_NOACTIVATE
);
1396 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1401 /* Resize/Move the rebar control */
1402 if (m_Rebar
!= NULL
)
1404 POINT ptRebar
= { 0, 0 };
1407 SetWindowStyle(m_Rebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1411 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1412 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1413 szRebar
.cy
= rcClient
.bottom
;
1417 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1418 szRebar
.cx
= rcClient
.right
;
1419 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1422 dwp
= DeferWindowPos(dwp
,
1429 SWP_NOZORDER
| SWP_NOACTIVATE
);
1433 EndDeferWindowPos(dwp
);
1435 if (m_TaskSwitch
!= NULL
)
1437 /* Update the task switch window configuration */
1438 SendMessage(m_TaskSwitch
, TSWM_UPDATETASKBARPOS
, 0, 0);
1442 LRESULT
OnThemeChanged()
1445 CloseThemeData(m_Theme
);
1447 if (IsThemeActive())
1448 m_Theme
= OpenThemeData(m_hWnd
, L
"TaskBar");
1452 if (Locked
&& m_Theme
)
1454 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1458 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1460 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1465 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1467 return OnThemeChanged();
1470 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1472 WCHAR szStartCaption
[32];
1474 ((ITrayWindow
*)this)->AddRef();
1476 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1479 InterlockedIncrement(&TrayWndCount
);
1481 if (!LoadString(hExplorerInstance
,
1484 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1486 szStartCaption
[0] = TEXT('\0');
1489 if (m_CaptionFont
== NULL
)
1491 NONCLIENTMETRICS ncm
;
1493 /* Get the system fonts, we use the caption font,
1494 always bold, though. */
1495 ncm
.cbSize
= sizeof(ncm
);
1496 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, FALSE
))
1498 if (m_CaptionFont
== NULL
)
1500 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1501 m_CaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1506 /* Create the Start button */
1507 m_StartButton
.SubclassWindow(CreateWindowEx(
1511 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1512 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1518 (HMENU
) IDC_STARTBTN
,
1522 if (m_StartButton
.m_hWnd
)
1524 m_StartButton
.Initialize();
1527 /* Load the saved tray window settings */
1530 /* Create and initialize the start menu */
1531 HBITMAP hbmBanner
= LoadBitmap(hExplorerInstance
, MAKEINTRESOURCE(IDB_STARTMENU
));
1532 m_StartMenuPopup
= CreateStartMenu(this, &m_StartMenuBand
, hbmBanner
, 0);
1534 /* Load the tray band site */
1535 if (m_TrayBandSite
!= NULL
)
1537 m_TrayBandSite
.Release();
1540 m_TrayBandSite
= CreateTrayBandSite(this, &m_Rebar
, &m_TaskSwitch
);
1541 SetWindowTheme(m_Rebar
, L
"TaskBar", NULL
);
1543 /* Create the tray notification window */
1544 m_TrayNotify
= CreateTrayNotifyWnd(this, HideClock
, &m_TrayNotifyInstance
);
1546 if (UpdateNonClientMetrics())
1551 /* Move the tray window to the right position and resize it if neccessary */
1552 CheckTrayWndPosition();
1554 /* Align all controls on the tray window */
1555 AlignControls(NULL
);
1557 InitShellServices(&(m_ShellServices
));
1561 m_AutoHideState
= AUTOHIDE_HIDING
;
1562 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1565 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
1566 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
1567 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
1568 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
1569 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
1570 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
1571 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
1572 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
1573 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
1574 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
1575 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
1576 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
1581 HRESULT STDMETHODCALLTYPE
Open()
1585 /* Check if there's already a window created and try to show it.
1586 If it was somehow destroyed just create a new tray window. */
1587 if (m_hWnd
!= NULL
&& IsWindow())
1589 if (!IsWindowVisible(m_hWnd
))
1591 CheckTrayWndPosition();
1593 ShowWindow(SW_SHOW
);
1599 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1601 dwExStyle
|= WS_EX_TOPMOST
;
1603 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1604 WS_BORDER
| WS_THICKFRAME
;
1606 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1607 if (m_Position
!= (DWORD
) -1)
1608 rcWnd
= m_TrayRects
[m_Position
];
1610 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1616 HRESULT STDMETHODCALLTYPE
Close()
1629 HWND STDMETHODCALLTYPE
GetHWND()
1634 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1636 return (m_hWnd
== hWnd
||
1637 (m_DesktopWnd
!= NULL
&& m_hWnd
== m_DesktopWnd
));
1640 BOOL STDMETHODCALLTYPE
1643 return IsPosHorizontal();
1646 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1648 if (phBoldCaption
!= NULL
)
1649 *phBoldCaption
= m_StartButton
.GetFont();
1651 return m_CaptionFont
;
1654 DWORD WINAPI
TrayPropertiesThread()
1659 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1660 hwnd
= CreateWindowEx(0,
1663 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1666 posRect
.right
- posRect
.left
,
1667 posRect
.bottom
- posRect
.top
,
1673 m_TrayPropertiesOwner
= hwnd
;
1675 DisplayTrayProperties(hwnd
);
1677 m_TrayPropertiesOwner
= NULL
;
1678 ::DestroyWindow(hwnd
);
1683 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1685 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1687 return This
->TrayPropertiesThread();
1690 HWND STDMETHODCALLTYPE
DisplayProperties()
1694 if (m_TrayPropertiesOwner
)
1696 hTrayProp
= GetLastActivePopup(m_TrayPropertiesOwner
);
1697 if (hTrayProp
!= NULL
&&
1698 hTrayProp
!= m_TrayPropertiesOwner
)
1700 SetForegroundWindow(hTrayProp
);
1705 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1709 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1711 WCHAR szDir
[MAX_PATH
];
1713 if (SHGetSpecialFolderPath(hWndOwner
,
1715 CSIDL_COMMON_STARTMENU
,
1718 ShellExecute(hWndOwner
,
1727 VOID
OpenTaskManager(IN HWND hWndOwner
)
1729 ShellExecute(hWndOwner
,
1731 TEXT("taskmgr.exe"),
1737 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1739 BOOL bHandled
= TRUE
;
1743 case ID_SHELL_CMD_PROPERTIES
:
1744 DisplayProperties();
1747 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1748 OpenCommonStartMenuDirectory(m_hWnd
,
1752 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1753 OpenCommonStartMenuDirectory(m_hWnd
,
1757 case ID_LOCKTASKBAR
:
1758 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1764 case ID_SHELL_CMD_OPEN_TASKMGR
:
1765 OpenTaskManager(m_hWnd
);
1768 case ID_SHELL_CMD_UNDO_ACTION
:
1771 case ID_SHELL_CMD_SHOW_DESKTOP
:
1774 case ID_SHELL_CMD_TILE_WND_H
:
1775 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1778 case ID_SHELL_CMD_TILE_WND_V
:
1779 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1782 case ID_SHELL_CMD_CASCADE_WND
:
1783 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1786 case ID_SHELL_CMD_CUST_NOTIF
:
1789 case ID_SHELL_CMD_ADJUST_DAT
:
1790 //FIXME: Use SHRunControlPanel
1791 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
1795 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1803 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1805 BOOL bPrevLock
= Locked
;
1807 if (Locked
!= bLock
)
1811 if (m_TrayBandSite
!= NULL
)
1813 if (!SUCCEEDED(m_TrayBandSite
->Lock(bLock
)))
1821 if (Locked
&& m_Theme
)
1823 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1827 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1829 SetWindowPos(NULL
, 0, 0, 0, 0, SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOOWNERZORDER
);
1837 LRESULT
DrawBackground(HDC hdc
)
1843 GetClientRect(&rect
);
1847 GetClientRect(&rect
);
1851 partId
= TBP_BACKGROUNDLEFT
;
1854 partId
= TBP_BACKGROUNDTOP
;
1857 partId
= TBP_BACKGROUNDRIGHT
;
1861 partId
= TBP_BACKGROUNDBOTTOM
;
1864 res
= DrawThemeBackground(m_Theme
, hdc
, partId
, 0, &rect
, 0);
1870 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1872 HDC hdc
= (HDC
) wParam
;
1880 return DrawBackground(hdc
);
1883 int DrawSizer(IN HRGN hRgn
)
1889 GetWindowRect(m_hWnd
, &rect
);
1890 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1892 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1897 backoundPart
= TBP_SIZINGBARLEFT
;
1898 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1901 backoundPart
= TBP_SIZINGBARTOP
;
1902 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1905 backoundPart
= TBP_SIZINGBARRIGHT
;
1906 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1910 backoundPart
= TBP_SIZINGBARBOTTOM
;
1911 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1914 if (IsThemeBackgroundPartiallyTransparent(m_Theme
, backoundPart
, 0))
1916 DrawThemeParentBackground(m_hWnd
, hdc
, &rect
);
1918 DrawThemeBackground(m_Theme
, hdc
, backoundPart
, 0, &rect
, 0);
1920 ReleaseDC(m_hWnd
, hdc
);
1924 DWORD WINAPI
RunFileDlgThread()
1929 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1931 hwnd
= CreateWindowEx(0,
1934 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1937 posRect
.right
- posRect
.left
,
1938 posRect
.bottom
- posRect
.top
,
1944 m_RunFileDlgOwner
= hwnd
;
1946 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1948 m_RunFileDlgOwner
= NULL
;
1949 ::DestroyWindow(hwnd
);
1954 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1956 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1957 return This
->RunFileDlgThread();
1960 void DisplayRunFileDlg()
1963 if (m_RunFileDlgOwner
)
1965 hRunDlg
= GetLastActivePopup(m_RunFileDlgOwner
);
1966 if (hRunDlg
!= NULL
&&
1967 hRunDlg
!= m_RunFileDlgOwner
)
1969 SetForegroundWindow(hRunDlg
);
1974 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1977 void PopupStartMenu()
1979 if (m_StartMenuPopup
!= NULL
)
1985 if (GetWindowRect(m_StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1990 pt
.x
= rcExclude
.left
;
1991 pt
.y
= rcExclude
.top
;
1992 dwFlags
|= MPPF_TOP
;
1995 pt
.x
= rcExclude
.left
;
1996 pt
.y
= rcExclude
.bottom
;
1997 dwFlags
|= MPPF_BOTTOM
;
2000 pt
.x
= rcExclude
.right
;
2001 pt
.y
= rcExclude
.top
;
2002 dwFlags
|= MPPF_RIGHT
;
2005 pt
.x
= rcExclude
.left
;
2006 pt
.y
= rcExclude
.top
;
2007 dwFlags
|= MPPF_LEFT
;
2011 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
2013 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
2018 void ProcessMouseTracking()
2023 UINT state
= m_AutoHideState
;
2026 GetWindowRect(m_hWnd
, &rcCurrent
);
2027 over
= PtInRect(&rcCurrent
, pt
);
2029 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2036 if (state
== AUTOHIDE_HIDING
)
2038 TRACE("AutoHide cancelling hide.\n");
2039 m_AutoHideState
= AUTOHIDE_SHOWING
;
2040 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2042 else if (state
== AUTOHIDE_HIDDEN
)
2044 TRACE("AutoHide starting show.\n");
2045 m_AutoHideState
= AUTOHIDE_SHOWING
;
2046 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2051 if (state
== AUTOHIDE_SHOWING
)
2053 TRACE("AutoHide cancelling show.\n");
2054 m_AutoHideState
= AUTOHIDE_HIDING
;
2055 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2057 else if (state
== AUTOHIDE_SHOWN
)
2059 TRACE("AutoHide starting hide.\n");
2060 m_AutoHideState
= AUTOHIDE_HIDING
;
2061 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2064 KillTimer(TIMER_ID_MOUSETRACK
);
2068 void ProcessAutoHide()
2070 RECT rc
= m_TrayRects
[m_Position
];
2071 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2072 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2074 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
);
2076 switch (m_AutoHideState
)
2078 case AUTOHIDE_HIDING
:
2082 m_AutoHideOffset
.cy
= 0;
2083 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2084 if (m_AutoHideOffset
.cx
< -w
)
2085 m_AutoHideOffset
.cx
= -w
;
2088 m_AutoHideOffset
.cx
= 0;
2089 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2090 if (m_AutoHideOffset
.cy
< -h
)
2091 m_AutoHideOffset
.cy
= -h
;
2094 m_AutoHideOffset
.cy
= 0;
2095 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2096 if (m_AutoHideOffset
.cx
> w
)
2097 m_AutoHideOffset
.cx
= w
;
2100 m_AutoHideOffset
.cx
= 0;
2101 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2102 if (m_AutoHideOffset
.cy
> h
)
2103 m_AutoHideOffset
.cy
= h
;
2107 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
2109 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2114 case AUTOHIDE_HIDDEN
:
2119 m_AutoHideOffset
.cx
= -w
;
2120 m_AutoHideOffset
.cy
= 0;
2123 m_AutoHideOffset
.cx
= 0;
2124 m_AutoHideOffset
.cy
= -h
;
2127 m_AutoHideOffset
.cx
= w
;
2128 m_AutoHideOffset
.cy
= 0;
2131 m_AutoHideOffset
.cx
= 0;
2132 m_AutoHideOffset
.cy
= h
;
2136 KillTimer(TIMER_ID_AUTOHIDE
);
2137 m_AutoHideState
= AUTOHIDE_HIDDEN
;
2140 case AUTOHIDE_SHOWING
:
2141 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2143 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2145 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2147 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2151 m_AutoHideOffset
.cx
= 0;
2154 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2156 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2158 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2160 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2164 m_AutoHideOffset
.cy
= 0;
2167 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
2169 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2174 case AUTOHIDE_SHOWN
:
2176 KillTimer(TIMER_ID_AUTOHIDE
);
2177 m_AutoHideState
= AUTOHIDE_SHOWN
;
2181 rc
.left
+= m_AutoHideOffset
.cx
;
2182 rc
.right
+= m_AutoHideOffset
.cx
;
2183 rc
.top
+= m_AutoHideOffset
.cy
;
2184 rc
.bottom
+= m_AutoHideOffset
.cy
;
2186 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
2187 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2190 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2192 /* Load the saved tray window settings */
2195 /* Move the tray window to the right position and resize it if neccessary */
2196 CheckTrayWndPosition();
2198 /* Align all controls on the tray window */
2199 AlignControls(NULL
);
2204 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2208 TRACE("WM_COPYDATA notify message received. Handling...\n");
2209 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2214 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2222 return DrawSizer((HRGN
) wParam
);
2225 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2227 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2228 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2231 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2238 /* The user may not be able to resize the tray window.
2239 Pretend like the window is not sizeable when the user
2240 clicks on the border. */
2244 SetLastError(ERROR_SUCCESS
);
2245 if (GetClientRect(&rcClient
) &&
2246 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2248 pt
.x
= (SHORT
) LOWORD(lParam
);
2249 pt
.y
= (SHORT
) HIWORD(lParam
);
2251 if (PtInRect(&rcClient
,
2254 /* The user is trying to drag the tray window */
2258 /* Depending on the position of the tray window, allow only
2259 changing the border next to the monitor working area */
2263 if (pt
.y
> rcClient
.bottom
)
2267 if (pt
.x
> rcClient
.right
)
2271 if (pt
.x
< rcClient
.left
)
2276 if (pt
.y
< rcClient
.top
)
2285 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2288 PRECT pRect
= (PRECT
) lParam
;
2290 /* We need to ensure that an application can not accidently
2291 move the tray window (using SetWindowPos). However, we still
2292 need to be able to move the window in case the user wants to
2293 drag the tray window to another position or in case the user
2294 wants to resize the tray window. */
2295 if (!Locked
&& GetCursorPos(&ptCursor
))
2298 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2302 *pRect
= m_TrayRects
[m_Position
];
2306 pRect
->left
+= m_AutoHideOffset
.cx
;
2307 pRect
->right
+= m_AutoHideOffset
.cx
;
2308 pRect
->top
+= m_AutoHideOffset
.cy
;
2309 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2315 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2317 PRECT pRect
= (PRECT
) lParam
;
2321 CalculateValidSize(m_Position
, pRect
);
2325 *pRect
= m_TrayRects
[m_Position
];
2329 pRect
->left
+= m_AutoHideOffset
.cx
;
2330 pRect
->right
+= m_AutoHideOffset
.cx
;
2331 pRect
->top
+= m_AutoHideOffset
.cy
;
2332 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2338 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2340 ChangingWinPos((LPWINDOWPOS
) lParam
);
2344 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2347 InvalidateRect(NULL
, TRUE
);
2348 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2351 /* Clip the tray window on multi monitor systems so the edges can't
2352 overlap into another monitor */
2353 ApplyClipping(TRUE
);
2355 if (!GetClientRect(&rcClient
))
2362 rcClient
.left
= rcClient
.top
= 0;
2363 rcClient
.right
= LOWORD(lParam
);
2364 rcClient
.bottom
= HIWORD(lParam
);
2367 AlignControls(&rcClient
);
2371 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2377 /* Remove the clipping on multi monitor systems while dragging around */
2378 ApplyClipping(FALSE
);
2383 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2388 /* Apply clipping */
2389 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2394 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2400 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2401 The tray window needs to handle this specially, since it normally doesn't have
2404 static const UINT uidDisableItem
[] = {
2415 /* temporarily enable the system menu */
2416 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2418 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2419 if (hSysMenu
!= NULL
)
2421 /* Disable all items that are not relevant */
2422 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2424 EnableMenuItem(hSysMenu
,
2426 MF_BYCOMMAND
| MF_GRAYED
);
2429 EnableMenuItem(hSysMenu
,
2432 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2434 /* Display the system menu */
2438 m_StartButton
.m_hWnd
,
2439 m_Position
!= ABE_TOP
,
2443 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2447 /* revert the system menu window style */
2448 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2458 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2460 /* We want the user to be able to get a context menu even on the nonclient
2461 area (including the sizing border)! */
2462 uMsg
= WM_CONTEXTMENU
;
2463 wParam
= (WPARAM
) m_hWnd
;
2465 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2468 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2470 LRESULT Ret
= FALSE
;
2471 POINT pt
, *ppt
= NULL
;
2472 HWND hWndExclude
= NULL
;
2474 /* Check if the administrator has forbidden access to context menus */
2475 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2478 pt
.x
= (SHORT
) LOWORD(lParam
);
2479 pt
.y
= (SHORT
) HIWORD(lParam
);
2481 if (pt
.x
!= -1 || pt
.y
!= -1)
2484 hWndExclude
= m_StartButton
.m_hWnd
;
2486 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2488 /* Make sure we can't track the context menu if the start
2489 menu is currently being shown */
2490 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2492 CComPtr
<IContextMenu
> ctxMenu
;
2493 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2494 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2499 /* See if the context menu should be handled by the task band site */
2500 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2503 POINT ptClient
= *ppt
;
2505 /* Convert the coordinates to client-coordinates */
2506 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2508 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2509 if (hWndAtPt
!= NULL
&&
2510 (hWndAtPt
== m_Rebar
|| IsChild(m_Rebar
, hWndAtPt
)))
2512 /* Check if the user clicked on the task switch window */
2514 MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2516 hWndAtPt
= ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2517 if (hWndAtPt
== m_TaskSwitch
)
2518 goto HandleTrayContextMenu
;
2520 /* Forward the message to the task band site */
2521 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2524 goto HandleTrayContextMenu
;
2528 HandleTrayContextMenu
:
2529 /* Tray the default tray window context menu */
2530 CComPtr
<IContextMenu
> ctxMenu
;
2531 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2532 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2538 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2540 LRESULT Ret
= FALSE
;
2541 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2542 the rebar control! But we shouldn't forward messages that the band
2543 site doesn't handle, such as other controls (start button, tray window */
2545 HRESULT hr
= E_FAIL
;
2549 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2554 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2556 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2558 if (nmh
->hwndFrom
== m_TrayNotify
)
2563 /* Cause all controls to be aligned */
2564 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2572 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2574 /* We "handle" this message so users can't cause a weird maximize/restore
2575 window animation when double-clicking the tray window! */
2577 /* We should forward mouse messages to child windows here.
2578 Right now, this is only clock double-click */
2580 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2583 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2584 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2585 if (PtInRect(&rcClock
, ptClick
))
2587 //FIXME: use SHRunControlPanel
2588 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2594 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2600 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2603 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2604 if (FAILED_UNEXPECTEDLY(hr
))
2607 if (IsWindowVisible(hwndStartMenu
))
2609 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2619 LRESULT
DoExitWindows()
2621 ExitWindowsDialog(m_hWnd
);
2625 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2628 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2629 * to show the shutdown dialog.
2631 return DoExitWindows();
2634 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2636 if (wParam
== SC_CLOSE
)
2638 return DoExitWindows();
2645 HRESULT
ExecResourceCmd(int id
)
2647 WCHAR szCommand
[256];
2648 WCHAR
*pszParameters
;
2650 if (!LoadString(hExplorerInstance
,
2653 sizeof(szCommand
) / sizeof(szCommand
[0])))
2658 pszParameters
= wcschr(szCommand
, L
'>');
2665 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, SW_SHOWNORMAL
);
2669 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2674 DisplayRunFileDlg();
2677 ExecResourceCmd(IDS_HELP_COMMAND
);
2680 //FIXME: We don't support this yet:
2681 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
2682 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
2685 SHFindFiles(NULL
, NULL
);
2687 case IDHK_FIND_COMPUTER
:
2688 SHFindComputer(NULL
, NULL
);
2690 case IDHK_SYS_PROPERTIES
:
2691 //FIXME: Use SHRunControlPanel
2692 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
2694 case IDHK_NEXT_TASK
:
2696 case IDHK_PREV_TASK
:
2698 case IDHK_MINIMIZE_ALL
:
2700 case IDHK_RESTORE_ALL
:
2711 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2713 LRESULT Ret
= FALSE
;
2715 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2721 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2723 switch (LOWORD(wParam
))
2725 case IDM_TASKBARANDSTARTMENU
:
2726 DisplayProperties();
2730 SHFindFiles(NULL
, NULL
);
2733 case IDM_HELPANDSUPPORT
:
2734 ExecResourceCmd(IDS_HELP_COMMAND
);
2738 DisplayRunFileDlg();
2741 /* FIXME: Handle these commands as well */
2742 case IDM_SYNCHRONIZE
:
2743 case IDM_DISCONNECT
:
2744 case IDM_UNDOCKCOMPUTER
:
2748 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
2759 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2763 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2769 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2771 if (wParam
== TIMER_ID_MOUSETRACK
)
2773 ProcessMouseTracking();
2775 else if (wParam
== TIMER_ID_AUTOHIDE
)
2784 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2787 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2793 ::GetWindowRect(m_hWnd
, &rc
);
2797 rc
.bottom
- rc
.top
};
2799 as
->rcTarget
.right
- as
->rcTarget
.left
,
2800 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2802 as
->rcActual
.right
- as
->rcActual
.left
,
2803 as
->rcActual
.bottom
- as
->rcActual
.top
};
2806 szWindow
.cx
- szTarget
.cx
,
2807 szWindow
.cy
- szTarget
.cx
,
2813 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2816 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2819 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2820 rc
.left
= rc
.right
- szWindow
.cy
;
2823 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2824 rc
.top
= rc
.bottom
- szWindow
.cy
;
2828 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2835 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2837 BEGIN_MSG_MAP(CTrayWindow
)
2838 if (m_StartMenuBand
!= NULL
)
2845 Msg
.wParam
= wParam
;
2846 Msg
.lParam
= lParam
;
2848 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2853 wParam
= Msg
.wParam
;
2854 lParam
= Msg
.lParam
;
2856 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2857 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2858 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2859 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2860 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2861 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2862 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2863 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2864 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2865 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2866 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2867 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2868 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2869 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2870 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2871 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2872 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2873 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2874 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2875 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2876 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2877 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2878 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2879 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2880 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2881 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2882 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2883 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2884 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2885 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2889 /*****************************************************************************/
2891 VOID
TrayProcessMessages()
2895 /* FIXME: We should keep a reference here... */
2897 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2899 if (Msg
.message
== WM_QUIT
)
2902 if (m_StartMenuBand
== NULL
||
2903 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2905 TranslateMessage(&Msg
);
2906 DispatchMessage(&Msg
);
2911 VOID
TrayMessageLoop()
2916 /* FIXME: We should keep a reference here... */
2920 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2922 if (!Ret
|| Ret
== -1)
2925 if (m_StartMenuBand
== NULL
||
2926 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2928 TranslateMessage(&Msg
);
2929 DispatchMessage(&Msg
);
2937 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2938 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2939 * The reason we implement it is because we have to use SHCreateDesktop() so
2940 * that the shell provides the desktop window and all the features that come
2941 * with it (especially positioning of desktop icons)
2944 virtual ULONG STDMETHODCALLTYPE
GetState()
2946 /* FIXME: Return ABS_ flags? */
2947 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2951 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2953 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2954 *phWndTray
= m_hWnd
;
2958 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2960 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2962 m_DesktopWnd
= hWndDesktop
;
2966 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2968 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2972 virtual HRESULT
RaiseStartButton()
2974 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2980 m_Position
= (DWORD
) -1;
2983 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2985 DECLARE_PROTECT_FINAL_CONSTRUCT()
2986 BEGIN_COM_MAP(CTrayWindow
)
2987 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2988 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2992 class CTrayWindowCtxMenu
:
2993 public CComCoClass
<CTrayWindowCtxMenu
>,
2994 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2998 CComPtr
<CTrayWindow
> TrayWnd
;
2999 CComPtr
<IContextMenu
> pcm
;
3002 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3004 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3005 this->hWndOwner
= hWndOwner
;
3009 virtual HRESULT STDMETHODCALLTYPE
3010 QueryContextMenu(HMENU hPopup
,
3016 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
3019 return HRESULT_FROM_WIN32(GetLastError());
3021 int count
= ::GetMenuItemCount(menubase
);
3023 for (int i
= 0; i
< count
; i
++)
3027 MENUITEMINFOW mii
= { 0 };
3028 mii
.cbSize
= sizeof(mii
);
3029 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3030 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3031 mii
.dwTypeData
= label
;
3032 mii
.cch
= _countof(label
);
3033 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3035 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3037 mii
.fType
|= MFT_RADIOCHECK
;
3039 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3042 ::DestroyMenu(menubase
);
3044 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3051 CheckMenuItem(hPopup
,
3053 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3055 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3057 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3065 WARN("AddContextMenus failed.\n");
3073 virtual HRESULT STDMETHODCALLTYPE
3074 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3076 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3079 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3081 CMINVOKECOMMANDINFO cmici
= { 0 };
3085 /* Setup and invoke the shell command */
3086 cmici
.cbSize
= sizeof(cmici
);
3087 cmici
.hwnd
= hWndOwner
;
3088 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3089 cmici
.nShow
= SW_NORMAL
;
3091 pcm
->InvokeCommand(&cmici
);
3096 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3103 virtual HRESULT STDMETHODCALLTYPE
3104 GetCommandString(UINT_PTR idCmd
,
3113 CTrayWindowCtxMenu()
3117 virtual ~CTrayWindowCtxMenu()
3121 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3122 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3126 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3128 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3129 mnu
->Initialize(TrayWnd
, hWndOwner
);
3134 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3136 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3138 return E_OUTOFMEMORY
;
3143 *ppTray
= (ITrayWindow
*) Tray
;
3149 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3151 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3152 return TrayWindow
->RaiseStartButton();
3155 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3157 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3158 TrayWindow
->TrayProcessMessages();
3161 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3163 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3164 TrayWindow
->TrayMessageLoop();