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
)
1842 GetClientRect(&rect
);
1846 GetClientRect(&rect
);
1850 partId
= TBP_BACKGROUNDLEFT
;
1853 partId
= TBP_BACKGROUNDTOP
;
1856 partId
= TBP_BACKGROUNDRIGHT
;
1860 partId
= TBP_BACKGROUNDBOTTOM
;
1864 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
);
1915 DrawThemeBackground(m_Theme
, hdc
, backoundPart
, 0, &rect
, 0);
1917 ReleaseDC(m_hWnd
, hdc
);
1921 DWORD WINAPI
RunFileDlgThread()
1926 GetWindowRect(m_StartButton
.m_hWnd
, &posRect
);
1928 hwnd
= CreateWindowEx(0,
1931 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1934 posRect
.right
- posRect
.left
,
1935 posRect
.bottom
- posRect
.top
,
1941 m_RunFileDlgOwner
= hwnd
;
1943 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1945 m_RunFileDlgOwner
= NULL
;
1946 ::DestroyWindow(hwnd
);
1951 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1953 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1954 return This
->RunFileDlgThread();
1957 void DisplayRunFileDlg()
1960 if (m_RunFileDlgOwner
)
1962 hRunDlg
= GetLastActivePopup(m_RunFileDlgOwner
);
1963 if (hRunDlg
!= NULL
&&
1964 hRunDlg
!= m_RunFileDlgOwner
)
1966 SetForegroundWindow(hRunDlg
);
1971 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1974 void PopupStartMenu()
1976 if (m_StartMenuPopup
!= NULL
)
1982 if (GetWindowRect(m_StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1987 pt
.x
= rcExclude
.left
;
1988 pt
.y
= rcExclude
.top
;
1989 dwFlags
|= MPPF_TOP
;
1992 pt
.x
= rcExclude
.left
;
1993 pt
.y
= rcExclude
.bottom
;
1994 dwFlags
|= MPPF_BOTTOM
;
1997 pt
.x
= rcExclude
.right
;
1998 pt
.y
= rcExclude
.top
;
1999 dwFlags
|= MPPF_RIGHT
;
2002 pt
.x
= rcExclude
.left
;
2003 pt
.y
= rcExclude
.top
;
2004 dwFlags
|= MPPF_LEFT
;
2008 m_StartMenuPopup
->Popup(&pt
, &rcExclude
, dwFlags
);
2010 m_StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
2015 void ProcessMouseTracking()
2020 UINT state
= m_AutoHideState
;
2023 GetWindowRect(m_hWnd
, &rcCurrent
);
2024 over
= PtInRect(&rcCurrent
, pt
);
2026 if (m_StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2033 if (state
== AUTOHIDE_HIDING
)
2035 TRACE("AutoHide cancelling hide.\n");
2036 m_AutoHideState
= AUTOHIDE_SHOWING
;
2037 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2039 else if (state
== AUTOHIDE_HIDDEN
)
2041 TRACE("AutoHide starting show.\n");
2042 m_AutoHideState
= AUTOHIDE_SHOWING
;
2043 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2048 if (state
== AUTOHIDE_SHOWING
)
2050 TRACE("AutoHide cancelling show.\n");
2051 m_AutoHideState
= AUTOHIDE_HIDING
;
2052 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2054 else if (state
== AUTOHIDE_SHOWN
)
2056 TRACE("AutoHide starting hide.\n");
2057 m_AutoHideState
= AUTOHIDE_HIDING
;
2058 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2061 KillTimer(TIMER_ID_MOUSETRACK
);
2065 void ProcessAutoHide()
2067 RECT rc
= m_TrayRects
[m_Position
];
2068 INT w
= m_TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2069 INT h
= m_TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2071 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
);
2073 switch (m_AutoHideState
)
2075 case AUTOHIDE_HIDING
:
2079 m_AutoHideOffset
.cy
= 0;
2080 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2081 if (m_AutoHideOffset
.cx
< -w
)
2082 m_AutoHideOffset
.cx
= -w
;
2085 m_AutoHideOffset
.cx
= 0;
2086 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2087 if (m_AutoHideOffset
.cy
< -h
)
2088 m_AutoHideOffset
.cy
= -h
;
2091 m_AutoHideOffset
.cy
= 0;
2092 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2093 if (m_AutoHideOffset
.cx
> w
)
2094 m_AutoHideOffset
.cx
= w
;
2097 m_AutoHideOffset
.cx
= 0;
2098 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2099 if (m_AutoHideOffset
.cy
> h
)
2100 m_AutoHideOffset
.cy
= h
;
2104 if (m_AutoHideOffset
.cx
!= w
&& m_AutoHideOffset
.cy
!= h
)
2106 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2111 case AUTOHIDE_HIDDEN
:
2116 m_AutoHideOffset
.cx
= -w
;
2117 m_AutoHideOffset
.cy
= 0;
2120 m_AutoHideOffset
.cx
= 0;
2121 m_AutoHideOffset
.cy
= -h
;
2124 m_AutoHideOffset
.cx
= w
;
2125 m_AutoHideOffset
.cy
= 0;
2128 m_AutoHideOffset
.cx
= 0;
2129 m_AutoHideOffset
.cy
= h
;
2133 KillTimer(TIMER_ID_AUTOHIDE
);
2134 m_AutoHideState
= AUTOHIDE_HIDDEN
;
2137 case AUTOHIDE_SHOWING
:
2138 if (m_AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2140 m_AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2142 else if (m_AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2144 m_AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2148 m_AutoHideOffset
.cx
= 0;
2151 if (m_AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2153 m_AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2155 else if (m_AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2157 m_AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2161 m_AutoHideOffset
.cy
= 0;
2164 if (m_AutoHideOffset
.cx
!= 0 || m_AutoHideOffset
.cy
!= 0)
2166 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2171 case AUTOHIDE_SHOWN
:
2173 KillTimer(TIMER_ID_AUTOHIDE
);
2174 m_AutoHideState
= AUTOHIDE_SHOWN
;
2178 rc
.left
+= m_AutoHideOffset
.cx
;
2179 rc
.right
+= m_AutoHideOffset
.cx
;
2180 rc
.top
+= m_AutoHideOffset
.cy
;
2181 rc
.bottom
+= m_AutoHideOffset
.cy
;
2183 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, m_AutoHideState
);
2184 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2187 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2189 /* Load the saved tray window settings */
2192 /* Move the tray window to the right position and resize it if neccessary */
2193 CheckTrayWndPosition();
2195 /* Align all controls on the tray window */
2196 AlignControls(NULL
);
2201 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2205 TRACE("WM_COPYDATA notify message received. Handling...\n");
2206 return TrayNotify_NotifyIconCmd(m_TrayNotifyInstance
, wParam
, lParam
);
2211 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2219 return DrawSizer((HRGN
) wParam
);
2222 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2224 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2225 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2228 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2235 /* The user may not be able to resize the tray window.
2236 Pretend like the window is not sizeable when the user
2237 clicks on the border. */
2241 SetLastError(ERROR_SUCCESS
);
2242 if (GetClientRect(&rcClient
) &&
2243 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2245 pt
.x
= (SHORT
) LOWORD(lParam
);
2246 pt
.y
= (SHORT
) HIWORD(lParam
);
2248 if (PtInRect(&rcClient
,
2251 /* The user is trying to drag the tray window */
2255 /* Depending on the position of the tray window, allow only
2256 changing the border next to the monitor working area */
2260 if (pt
.y
> rcClient
.bottom
)
2264 if (pt
.x
> rcClient
.right
)
2268 if (pt
.x
< rcClient
.left
)
2273 if (pt
.y
< rcClient
.top
)
2282 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2285 PRECT pRect
= (PRECT
) lParam
;
2287 /* We need to ensure that an application can not accidently
2288 move the tray window (using SetWindowPos). However, we still
2289 need to be able to move the window in case the user wants to
2290 drag the tray window to another position or in case the user
2291 wants to resize the tray window. */
2292 if (!Locked
&& GetCursorPos(&ptCursor
))
2295 m_DraggingPosition
= GetDraggingRectFromPt(ptCursor
, pRect
, &m_DraggingMonitor
);
2299 *pRect
= m_TrayRects
[m_Position
];
2303 pRect
->left
+= m_AutoHideOffset
.cx
;
2304 pRect
->right
+= m_AutoHideOffset
.cx
;
2305 pRect
->top
+= m_AutoHideOffset
.cy
;
2306 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2312 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2314 PRECT pRect
= (PRECT
) lParam
;
2318 CalculateValidSize(m_Position
, pRect
);
2322 *pRect
= m_TrayRects
[m_Position
];
2326 pRect
->left
+= m_AutoHideOffset
.cx
;
2327 pRect
->right
+= m_AutoHideOffset
.cx
;
2328 pRect
->top
+= m_AutoHideOffset
.cy
;
2329 pRect
->bottom
+= m_AutoHideOffset
.cy
;
2335 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2337 ChangingWinPos((LPWINDOWPOS
) lParam
);
2341 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2344 InvalidateRect(NULL
, TRUE
);
2345 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2348 /* Clip the tray window on multi monitor systems so the edges can't
2349 overlap into another monitor */
2350 ApplyClipping(TRUE
);
2352 if (!GetClientRect(&rcClient
))
2359 rcClient
.left
= rcClient
.top
= 0;
2360 rcClient
.right
= LOWORD(lParam
);
2361 rcClient
.bottom
= HIWORD(lParam
);
2364 AlignControls(&rcClient
);
2368 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2374 /* Remove the clipping on multi monitor systems while dragging around */
2375 ApplyClipping(FALSE
);
2380 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2385 /* Apply clipping */
2386 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2391 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2397 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2398 The tray window needs to handle this specially, since it normally doesn't have
2401 static const UINT uidDisableItem
[] = {
2412 /* temporarily enable the system menu */
2413 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2415 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2416 if (hSysMenu
!= NULL
)
2418 /* Disable all items that are not relevant */
2419 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2421 EnableMenuItem(hSysMenu
,
2423 MF_BYCOMMAND
| MF_GRAYED
);
2426 EnableMenuItem(hSysMenu
,
2429 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2431 /* Display the system menu */
2435 m_StartButton
.m_hWnd
,
2436 m_Position
!= ABE_TOP
,
2440 SendMessage(m_hWnd
, WM_SYSCOMMAND
, (WPARAM
) uId
, 0);
2444 /* revert the system menu window style */
2445 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2455 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2457 /* We want the user to be able to get a context menu even on the nonclient
2458 area (including the sizing border)! */
2459 uMsg
= WM_CONTEXTMENU
;
2460 wParam
= (WPARAM
) m_hWnd
;
2462 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2465 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2467 LRESULT Ret
= FALSE
;
2468 POINT pt
, *ppt
= NULL
;
2469 HWND hWndExclude
= NULL
;
2471 /* Check if the administrator has forbidden access to context menus */
2472 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2475 pt
.x
= (SHORT
) LOWORD(lParam
);
2476 pt
.y
= (SHORT
) HIWORD(lParam
);
2478 if (pt
.x
!= -1 || pt
.y
!= -1)
2481 hWndExclude
= m_StartButton
.m_hWnd
;
2483 if ((HWND
) wParam
== m_StartButton
.m_hWnd
)
2485 /* Make sure we can't track the context menu if the start
2486 menu is currently being shown */
2487 if (!(m_StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2489 CComPtr
<IContextMenu
> ctxMenu
;
2490 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2491 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, m_Position
== ABE_BOTTOM
, this);
2496 /* See if the context menu should be handled by the task band site */
2497 if (ppt
!= NULL
&& m_TrayBandSite
!= NULL
)
2500 POINT ptClient
= *ppt
;
2502 /* Convert the coordinates to client-coordinates */
2503 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2505 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2506 if (hWndAtPt
!= NULL
&&
2507 (hWndAtPt
== m_Rebar
|| IsChild(m_Rebar
, hWndAtPt
)))
2509 /* Check if the user clicked on the task switch window */
2511 MapWindowPoints(NULL
, m_Rebar
, &ptClient
, 1);
2513 hWndAtPt
= ChildWindowFromPointEx(m_Rebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2514 if (hWndAtPt
== m_TaskSwitch
)
2515 goto HandleTrayContextMenu
;
2517 /* Forward the message to the task band site */
2518 m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2521 goto HandleTrayContextMenu
;
2525 HandleTrayContextMenu
:
2526 /* Tray the default tray window context menu */
2527 CComPtr
<IContextMenu
> ctxMenu
;
2528 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2529 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2535 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2537 LRESULT Ret
= FALSE
;
2538 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2539 the rebar control! But we shouldn't forward messages that the band
2540 site doesn't handle, such as other controls (start button, tray window */
2542 HRESULT hr
= E_FAIL
;
2546 hr
= m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2551 if (m_TrayBandSite
== NULL
|| FAILED(hr
))
2553 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2555 if (nmh
->hwndFrom
== m_TrayNotify
)
2560 /* Cause all controls to be aligned */
2561 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2569 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2571 /* We "handle" this message so users can't cause a weird maximize/restore
2572 window animation when double-clicking the tray window! */
2574 /* We should forward mouse messages to child windows here.
2575 Right now, this is only clock double-click */
2577 if (TrayNotify_GetClockRect(m_TrayNotifyInstance
, &rcClock
))
2580 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2581 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2582 if (PtInRect(&rcClock
, ptClick
))
2584 //FIXME: use SHRunControlPanel
2585 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2591 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2597 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2600 HRESULT hr
= IUnknown_GetWindow(m_StartMenuPopup
, &hwndStartMenu
);
2601 if (FAILED_UNEXPECTEDLY(hr
))
2604 if (IsWindowVisible(hwndStartMenu
))
2606 m_StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2616 LRESULT
DoExitWindows()
2618 ExitWindowsDialog(m_hWnd
);
2622 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2625 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
2626 * to show the shutdown dialog.
2628 return DoExitWindows();
2631 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2633 if (wParam
== SC_CLOSE
)
2635 return DoExitWindows();
2642 HRESULT
ExecResourceCmd(int id
)
2644 WCHAR szCommand
[256];
2645 WCHAR
*pszParameters
;
2647 if (!LoadString(hExplorerInstance
,
2650 sizeof(szCommand
) / sizeof(szCommand
[0])))
2655 pszParameters
= wcschr(szCommand
, L
'>');
2662 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, 0);
2666 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2671 DisplayRunFileDlg();
2674 ExecResourceCmd(IDS_HELP_COMMAND
);
2677 //FIXME: We don't support this yet:
2678 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
2679 ShellExecuteW(0, NULL
, L
"explorer.exe", NULL
, NULL
, 1);
2682 SHFindFiles(NULL
, NULL
);
2684 case IDHK_FIND_COMPUTER
:
2685 SHFindComputer(NULL
, NULL
);
2687 case IDHK_SYS_PROPERTIES
:
2688 //FIXME: Use SHRunControlPanel
2689 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
2691 case IDHK_NEXT_TASK
:
2693 case IDHK_PREV_TASK
:
2695 case IDHK_MINIMIZE_ALL
:
2697 case IDHK_RESTORE_ALL
:
2708 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2710 LRESULT Ret
= FALSE
;
2712 if ((HWND
) lParam
== m_StartButton
.m_hWnd
)
2718 if (m_TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(m_TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2720 switch (LOWORD(wParam
))
2722 case IDM_TASKBARANDSTARTMENU
:
2723 DisplayProperties();
2727 SHFindFiles(NULL
, NULL
);
2730 case IDM_HELPANDSUPPORT
:
2731 ExecResourceCmd(IDS_HELP_COMMAND
);
2735 DisplayRunFileDlg();
2738 /* FIXME: Handle these commands as well */
2739 case IDM_SYNCHRONIZE
:
2740 case IDM_DISCONNECT
:
2741 case IDM_UNDOCKCOMPUTER
:
2745 LogoffWindowsDialog(m_hWnd
); // FIXME: Maybe handle it in a similar way as DoExitWindows?
2756 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2760 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2766 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2768 if (wParam
== TIMER_ID_MOUSETRACK
)
2770 ProcessMouseTracking();
2772 else if (wParam
== TIMER_ID_AUTOHIDE
)
2781 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2784 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2790 ::GetWindowRect(m_hWnd
, &rc
);
2794 rc
.bottom
- rc
.top
};
2796 as
->rcTarget
.right
- as
->rcTarget
.left
,
2797 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2799 as
->rcActual
.right
- as
->rcActual
.left
,
2800 as
->rcActual
.bottom
- as
->rcActual
.top
};
2803 szWindow
.cx
- szTarget
.cx
,
2804 szWindow
.cy
- szTarget
.cx
,
2810 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2813 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2816 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2817 rc
.left
= rc
.right
- szWindow
.cy
;
2820 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2821 rc
.top
= rc
.bottom
- szWindow
.cy
;
2825 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2832 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2834 BEGIN_MSG_MAP(CTrayWindow
)
2835 if (m_StartMenuBand
!= NULL
)
2842 Msg
.wParam
= wParam
;
2843 Msg
.lParam
= lParam
;
2845 if (m_StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2850 wParam
= Msg
.wParam
;
2851 lParam
= Msg
.lParam
;
2853 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2854 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2855 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2856 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2857 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2858 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2859 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2860 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2861 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2862 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2863 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2864 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2865 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2866 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2867 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2868 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2869 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2870 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2871 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2872 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2873 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2874 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2875 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2876 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2877 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2878 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2879 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2880 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2881 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2882 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2886 /*****************************************************************************/
2888 VOID
TrayProcessMessages()
2892 /* FIXME: We should keep a reference here... */
2894 while (PeekMessage(&Msg
, NULL
, 0, 0, PM_REMOVE
))
2896 if (Msg
.message
== WM_QUIT
)
2899 if (m_StartMenuBand
== NULL
||
2900 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2902 TranslateMessage(&Msg
);
2903 DispatchMessage(&Msg
);
2908 VOID
TrayMessageLoop()
2913 /* FIXME: We should keep a reference here... */
2917 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2919 if (!Ret
|| Ret
== -1)
2922 if (m_StartMenuBand
== NULL
||
2923 m_StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2925 TranslateMessage(&Msg
);
2926 DispatchMessage(&Msg
);
2934 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2935 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2936 * The reason we implement it is because we have to use SHCreateDesktop() so
2937 * that the shell provides the desktop window and all the features that come
2938 * with it (especially positioning of desktop icons)
2941 virtual ULONG STDMETHODCALLTYPE
GetState()
2943 /* FIXME: Return ABS_ flags? */
2944 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2948 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2950 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2951 *phWndTray
= m_hWnd
;
2955 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2957 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2959 m_DesktopWnd
= hWndDesktop
;
2963 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2965 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2969 virtual HRESULT
RaiseStartButton()
2971 m_StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2977 m_Position
= (DWORD
) -1;
2980 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2982 DECLARE_PROTECT_FINAL_CONSTRUCT()
2983 BEGIN_COM_MAP(CTrayWindow
)
2984 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
2985 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
2989 class CTrayWindowCtxMenu
:
2990 public CComCoClass
<CTrayWindowCtxMenu
>,
2991 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
2995 CComPtr
<CTrayWindow
> TrayWnd
;
2996 CComPtr
<IContextMenu
> pcm
;
2999 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3001 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3002 this->hWndOwner
= hWndOwner
;
3006 virtual HRESULT STDMETHODCALLTYPE
3007 QueryContextMenu(HMENU hPopup
,
3013 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
3016 return HRESULT_FROM_WIN32(GetLastError());
3018 int count
= ::GetMenuItemCount(menubase
);
3020 for (int i
= 0; i
< count
; i
++)
3024 MENUITEMINFOW mii
= { 0 };
3025 mii
.cbSize
= sizeof(mii
);
3026 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3027 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3028 mii
.dwTypeData
= label
;
3029 mii
.cch
= _countof(label
);
3030 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3032 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3034 mii
.fType
|= MFT_RADIOCHECK
;
3036 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3039 ::DestroyMenu(menubase
);
3041 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3048 CheckMenuItem(hPopup
,
3050 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3052 if (TrayWnd
->m_TrayBandSite
!= NULL
)
3054 if (FAILED(TrayWnd
->m_TrayBandSite
->AddContextMenus(
3062 WARN("AddContextMenus failed.\n");
3070 virtual HRESULT STDMETHODCALLTYPE
3071 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3073 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3076 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3078 CMINVOKECOMMANDINFO cmici
= { 0 };
3082 /* Setup and invoke the shell command */
3083 cmici
.cbSize
= sizeof(cmici
);
3084 cmici
.hwnd
= hWndOwner
;
3085 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3086 cmici
.nShow
= SW_NORMAL
;
3088 pcm
->InvokeCommand(&cmici
);
3093 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3100 virtual HRESULT STDMETHODCALLTYPE
3101 GetCommandString(UINT_PTR idCmd
,
3110 CTrayWindowCtxMenu()
3114 virtual ~CTrayWindowCtxMenu()
3118 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3119 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3123 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3125 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3126 mnu
->Initialize(TrayWnd
, hWndOwner
);
3131 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3133 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3135 return E_OUTOFMEMORY
;
3140 *ppTray
= (ITrayWindow
*) Tray
;
3146 Tray_OnStartMenuDismissed(ITrayWindow
* Tray
)
3148 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3149 return TrayWindow
->RaiseStartButton();
3152 VOID
TrayProcessMessages(ITrayWindow
*Tray
)
3154 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3155 TrayWindow
->TrayProcessMessages();
3158 VOID
TrayMessageLoop(ITrayWindow
*Tray
)
3160 CTrayWindow
* TrayWindow
= static_cast<CTrayWindow
*>(Tray
);
3161 TrayWindow
->TrayMessageLoop();