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 CComCoClass
<CTrayWindow
>,
68 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
69 public CWindowImpl
< CTrayWindow
, CWindow
, CControlWinTraits
>,
71 public IShellDesktopTray
73 CContainedWindow StartButton
;
78 IImageList
* himlStartBtn
;
89 HMONITOR PreviousMonitor
;
90 DWORD DraggingPosition
;
91 HMONITOR DraggingMonitor
;
100 CComPtr
<IMenuBand
> StartMenuBand
;
101 CComPtr
<IMenuPopup
> StartMenuPopup
;
102 HBITMAP hbmStartMenu
;
104 HWND hwndTrayPropertiesOwner
;
105 HWND hwndRunFileDlgOwner
;
109 TRACKMOUSEEVENT MouseTrackingInfo
;
111 HDPA hdpaShellServices
;
114 CComPtr
<ITrayBandSite
> TrayBandSite
;
121 DWORD AlwaysOnTop
: 1;
122 DWORD SmSmallIcons
: 1;
127 DWORD InSizeMove
: 1;
128 DWORD IsDragging
: 1;
129 DWORD NewPosSize
: 1;
135 StartButton(this, 1),
142 hwndTaskSwitch(NULL
),
143 hwndTrayNotify(NULL
),
146 PreviousMonitor(NULL
),
148 DraggingMonitor(NULL
),
151 hwndTrayPropertiesOwner(NULL
),
152 hwndRunFileDlgOwner(NULL
),
154 hdpaShellServices(NULL
),
157 ZeroMemory(&StartBtnSize
, sizeof(StartBtnSize
));
158 ZeroMemory(&rcTrayWnd
, sizeof(rcTrayWnd
));
159 ZeroMemory(&rcNewPosSize
, sizeof(rcNewPosSize
));
160 ZeroMemory(&TraySize
, sizeof(TraySize
));
161 ZeroMemory(&ncm
, sizeof(ncm
));
162 ZeroMemory(&AutoHideOffset
, sizeof(AutoHideOffset
));
163 ZeroMemory(&MouseTrackingInfo
, sizeof(MouseTrackingInfo
));
166 virtual ~CTrayWindow()
168 (void) InterlockedExchangePointer((PVOID
*) &m_hWnd
, NULL
);
171 if (hdpaShellServices
!= NULL
)
173 ShutdownShellServices(hdpaShellServices
);
174 hdpaShellServices
= NULL
;
177 if (himlStartBtn
!= NULL
)
179 himlStartBtn
->Release();
183 if (hCaptionFont
!= NULL
)
185 DeleteObject(hCaptionFont
);
189 if (hStartBtnFont
!= NULL
)
191 DeleteObject(hStartBtnFont
);
192 hStartBtnFont
= NULL
;
201 if (hbmStartMenu
!= NULL
)
203 DeleteObject(hbmStartMenu
);
209 CloseThemeData(TaskbarTheme
);
213 if (InterlockedDecrement(&TrayWndCount
) == 0)
221 BOOL
UpdateNonClientMetrics()
223 ncm
.cbSize
= sizeof(ncm
);
224 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
229 hFont
= CreateFontIndirect(&ncm
.lfMessageFont
);
236 VOID
SetWindowsFont()
238 if (hwndTrayNotify
!= NULL
)
240 SendMessage(hwndTrayNotify
, WM_SETFONT
, (WPARAM
) hFont
, TRUE
);
244 HMONITOR
GetScreenRectFromRect(
251 mi
.cbSize
= sizeof(mi
);
252 hMon
= MonitorFromRect(pRect
,
258 *pRect
= mi
.rcMonitor
;
264 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
265 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
273 HMONITOR
GetMonitorFromRect(
274 IN
const RECT
*pRect
)
278 /* In case the monitor sizes or saved sizes differ a bit (probably
279 not a lot, only so the tray window overlaps into another monitor
280 now), minimize the risk that we determine a wrong monitor by
281 using the center point of the tray window if we can't determine
282 it using the rectangle. */
283 hMon
= MonitorFromRect(pRect
,
284 MONITOR_DEFAULTTONULL
);
289 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
290 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
292 /* be less error-prone, find the nearest monitor */
293 hMon
= MonitorFromPoint(pt
,
294 MONITOR_DEFAULTTONEAREST
);
300 HMONITOR
GetScreenRect(
301 IN HMONITOR hMonitor
,
304 HMONITOR hMon
= NULL
;
306 if (hMonitor
!= NULL
)
310 mi
.cbSize
= sizeof(mi
);
311 if (!GetMonitorInfo(hMonitor
,
314 /* Hm, the monitor is gone? Try to find a monitor where it
315 could be located now */
316 hMon
= GetMonitorFromRect(
319 !GetMonitorInfo(hMon
,
327 *pRect
= mi
.rcMonitor
;
334 pRect
->right
= GetSystemMetrics(SM_CXSCREEN
);
335 pRect
->bottom
= GetSystemMetrics(SM_CYSCREEN
);
341 VOID
MakeTrayRectWithSize(IN DWORD Position
,
342 IN
const SIZE
*pTraySize
,
348 pRect
->right
= pRect
->left
+ pTraySize
->cx
;
352 pRect
->bottom
= pRect
->top
+ pTraySize
->cy
;
356 pRect
->left
= pRect
->right
- pTraySize
->cx
;
361 pRect
->top
= pRect
->bottom
- pTraySize
->cy
;
366 VOID
GetTrayRectFromScreenRect(IN DWORD Position
,
367 IN
const RECT
*pScreen
,
368 IN
const SIZE
*pTraySize OPTIONAL
,
371 if (pTraySize
== NULL
)
372 pTraySize
= &TraySize
;
376 /* Move the border outside of the screen */
378 GetSystemMetrics(SM_CXEDGE
),
379 GetSystemMetrics(SM_CYEDGE
));
381 MakeTrayRectWithSize(Position
, pTraySize
, pRect
);
387 return Position
== ABE_TOP
|| Position
== ABE_BOTTOM
;
400 //Horizontal = IsPosHorizontal();
402 szWnd
.cx
= pRect
->right
- pRect
->left
;
403 szWnd
.cy
= pRect
->bottom
- pRect
->top
;
406 hMon
= GetScreenRectFromRect(
408 MONITOR_DEFAULTTONEAREST
);
410 /* Calculate the maximum size of the tray window and limit the window
411 size to half of the screen's size. */
412 szMax
.cx
= (rcScreen
.right
- rcScreen
.left
) / 2;
413 szMax
.cy
= (rcScreen
.bottom
- rcScreen
.top
) / 2;
414 if (szWnd
.cx
> szMax
.cx
)
416 if (szWnd
.cy
> szMax
.cy
)
419 /* FIXME - calculate */
421 GetTrayRectFromScreenRect(
432 GetMinimumWindowSize(
437 AdjustWindowRectEx(&rcMin
,
438 GetWindowLong(m_hWnd
,
441 GetWindowLong(m_hWnd
,
450 GetDraggingRectFromPt(
453 OUT HMONITOR
*phMonitor
)
455 HMONITOR hMon
, hMonNew
;
456 DWORD PosH
, PosV
, Pos
;
457 SIZE DeltaPt
, ScreenOffset
;
463 /* Determine the screen rectangle */
464 hMon
= MonitorFromPoint(pt
,
465 MONITOR_DEFAULTTONULL
);
471 mi
.cbSize
= sizeof(mi
);
472 if (!GetMonitorInfo(hMon
,
476 goto GetPrimaryScreenRect
;
479 /* make left top corner of the screen zero based to
480 make calculations easier */
481 pt
.x
-= mi
.rcMonitor
.left
;
482 pt
.y
-= mi
.rcMonitor
.top
;
484 ScreenOffset
.cx
= mi
.rcMonitor
.left
;
485 ScreenOffset
.cy
= mi
.rcMonitor
.top
;
486 rcScreen
.right
= mi
.rcMonitor
.right
- mi
.rcMonitor
.left
;
487 rcScreen
.bottom
= mi
.rcMonitor
.bottom
- mi
.rcMonitor
.top
;
491 GetPrimaryScreenRect
:
494 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
495 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
498 /* Calculate the nearest screen border */
499 if (pt
.x
< rcScreen
.right
/ 2)
506 DeltaPt
.cx
= rcScreen
.right
- pt
.x
;
510 if (pt
.y
< rcScreen
.bottom
/ 2)
517 DeltaPt
.cy
= rcScreen
.bottom
- pt
.y
;
521 Pos
= (DeltaPt
.cx
* rcScreen
.bottom
< DeltaPt
.cy
* rcScreen
.right
) ? PosH
: PosV
;
523 /* Fix the screen origin to be relative to the primary monitor again */
524 OffsetRect(&rcScreen
,
528 hMonNew
= GetMonitorFromRect(
534 /* Recalculate the rectangle, we're dragging to another monitor.
535 We don't need to recalculate the rect on single monitor systems. */
536 szTray
.cx
= rcTrayWnd
[Pos
].right
- rcTrayWnd
[Pos
].left
;
537 szTray
.cy
= rcTrayWnd
[Pos
].bottom
- rcTrayWnd
[Pos
].top
;
539 GetTrayRectFromScreenRect(
546 pRect
->left
+= AutoHideOffset
.cx
;
547 pRect
->right
+= AutoHideOffset
.cx
;
548 pRect
->top
+= AutoHideOffset
.cy
;
549 pRect
->bottom
+= AutoHideOffset
.cy
;
555 /* The user is dragging the tray window on the same monitor. We don't need
556 to recalculate the rectangle */
557 *pRect
= rcTrayWnd
[Pos
];
560 pRect
->left
+= AutoHideOffset
.cx
;
561 pRect
->right
+= AutoHideOffset
.cx
;
562 pRect
->top
+= AutoHideOffset
.cy
;
563 pRect
->bottom
+= AutoHideOffset
.cy
;
573 GetDraggingRectFromRect(
575 OUT HMONITOR
*phMonitor
)
579 /* Calculate the center of the rectangle. We call
580 GetDraggingRectFromPt to calculate a valid
581 dragging rectangle */
582 pt
.x
= pRect
->left
+ ((pRect
->right
- pRect
->left
) / 2);
583 pt
.y
= pRect
->top
+ ((pRect
->bottom
- pRect
->top
) / 2);
585 return GetDraggingRectFromPt(
593 IN OUT LPWINDOWPOS pwp
)
599 rcTray
.left
= pwp
->x
;
601 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
602 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
605 rcTray
.left
-= AutoHideOffset
.cx
;
606 rcTray
.right
-= AutoHideOffset
.cx
;
607 rcTray
.top
-= AutoHideOffset
.cy
;
608 rcTray
.bottom
-= AutoHideOffset
.cy
;
611 if (!EqualRect(&rcTray
,
612 &rcTrayWnd
[DraggingPosition
]))
614 /* Recalculate the rectangle, the user dragged the tray
615 window to another monitor or the window was somehow else
617 DraggingPosition
= GetDraggingRectFromRect(
620 //rcTrayWnd[DraggingPosition] = rcTray;
623 //Monitor = CalculateValidSize(
627 Monitor
= DraggingMonitor
;
628 Position
= DraggingPosition
;
631 rcTrayWnd
[Position
] = rcTray
;
634 else if (GetWindowRect(m_hWnd
, &rcTray
))
638 if (!(pwp
->flags
& SWP_NOMOVE
))
640 rcTray
.left
= pwp
->x
;
644 if (!(pwp
->flags
& SWP_NOSIZE
))
646 rcTray
.right
= rcTray
.left
+ pwp
->cx
;
647 rcTray
.bottom
= rcTray
.top
+ pwp
->cy
;
650 Position
= GetDraggingRectFromRect(
654 if (!(pwp
->flags
& (SWP_NOMOVE
| SWP_NOSIZE
)))
661 MakeTrayRectWithSize(Position
, &szWnd
, &rcTray
);
666 rcTray
.left
-= AutoHideOffset
.cx
;
667 rcTray
.right
-= AutoHideOffset
.cx
;
668 rcTray
.top
-= AutoHideOffset
.cy
;
669 rcTray
.bottom
-= AutoHideOffset
.cy
;
671 rcTrayWnd
[Position
] = rcTray
;
675 /* If the user isn't resizing the tray window we need to make sure the
676 new size or position is valid. this is to prevent changes to the window
677 without user interaction. */
678 rcTray
= rcTrayWnd
[Position
];
682 TraySize
.cx
= rcTray
.right
- rcTray
.left
;
683 TraySize
.cy
= rcTray
.bottom
- rcTray
.top
;
687 rcTray
.left
+= AutoHideOffset
.cx
;
688 rcTray
.right
+= AutoHideOffset
.cx
;
689 rcTray
.top
+= AutoHideOffset
.cy
;
690 rcTray
.bottom
+= AutoHideOffset
.cy
;
693 pwp
->flags
&= ~(SWP_NOMOVE
| SWP_NOSIZE
);
694 pwp
->x
= rcTray
.left
;
696 pwp
->cx
= TraySize
.cx
;
697 pwp
->cy
= TraySize
.cy
;
702 ApplyClipping(IN BOOL Clip
)
704 RECT rcClip
, rcWindow
;
707 if (GetWindowRect(m_hWnd
, &rcWindow
))
709 /* Disable clipping on systems with only one monitor */
710 if (GetSystemMetrics(SM_CMONITORS
) <= 1)
717 GetScreenRect(Monitor
, &rcClip
);
719 if (!IntersectRect(&rcClip
, &rcClip
, &rcWindow
))
728 hClipRgn
= CreateRectRgnIndirect(&rcClip
);
733 /* Set the clipping region or make sure the window isn't clipped
734 by disabling it explicitly. */
735 SetWindowRgn(m_hWnd
, hClipRgn
, TRUE
);
739 VOID
ResizeWorkArea()
741 #if !WIN7_COMPAT_MODE
742 RECT rcTray
, rcWorkArea
;
744 /* If monitor has changed then fix the previous monitors work area */
745 if (PreviousMonitor
!= Monitor
)
750 SystemParametersInfo(SPI_SETWORKAREA
,
756 rcTray
= rcTrayWnd
[Position
];
761 PreviousMonitor
= Monitor
;
763 /* If AutoHide is false then change the workarea to exclude the area that
764 the taskbar covers. */
770 rcWorkArea
.top
= rcTray
.bottom
;
773 rcWorkArea
.left
= rcTray
.right
;
776 rcWorkArea
.right
= rcTray
.left
;
779 rcWorkArea
.bottom
= rcTray
.top
;
784 SystemParametersInfo(SPI_SETWORKAREA
,
791 VOID
CheckTrayWndPosition()
795 rcTray
= rcTrayWnd
[Position
];
799 rcTray
.left
+= AutoHideOffset
.cx
;
800 rcTray
.right
+= AutoHideOffset
.cx
;
801 rcTray
.top
+= AutoHideOffset
.cy
;
802 rcTray
.bottom
+= AutoHideOffset
.cy
;
805 // TRACE("CheckTray: %d: %d,%d,%d,%d\n", Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
807 /* Move the tray window */
811 rcTray
.right
- rcTray
.left
,
812 rcTray
.bottom
- rcTray
.top
,
820 typedef struct _TW_STUCKRECTS2
828 } TW_STRUCKRECTS2
, *PTW_STUCKRECTS2
;
836 SIZE WndSize
, EdgeSize
, DlgFrameSize
;
837 DWORD cbSize
= sizeof(sr
);
839 EdgeSize
.cx
= GetSystemMetrics(SM_CXEDGE
);
840 EdgeSize
.cy
= GetSystemMetrics(SM_CYEDGE
);
841 DlgFrameSize
.cx
= GetSystemMetrics(SM_CXDLGFRAME
);
842 DlgFrameSize
.cy
= GetSystemMetrics(SM_CYDLGFRAME
);
844 if (SHGetValue(hkExplorer
,
849 &cbSize
) == ERROR_SUCCESS
&&
850 sr
.cbSize
== sizeof(sr
))
852 AutoHide
= (sr
.dwFlags
& ABS_AUTOHIDE
) != 0;
853 AlwaysOnTop
= (sr
.dwFlags
& ABS_ALWAYSONTOP
) != 0;
854 SmSmallIcons
= (sr
.dwFlags
& 0x4) != 0;
855 HideClock
= (sr
.dwFlags
& 0x8) != 0;
857 /* FIXME: Are there more flags? */
862 if (sr
.Position
> ABE_BOTTOM
)
863 Position
= ABE_BOTTOM
;
865 Position
= sr
.Position
;
868 /* Try to find out which monitor the tray window was located on last.
869 Here we're only interested in the monitor screen that we think
870 is the last one used. We're going to determine on which monitor
871 we really are after calculating the docked position. */
873 GetScreenRectFromRect(
875 MONITOR_DEFAULTTONEAREST
);
879 Position
= ABE_BOTTOM
;
882 /* Use the minimum size of the taskbar, we'll use the start
883 button as a minimum for now. Make sure we calculate the
884 entire window size, not just the client size. However, we
885 use a thinner border than a standard thick border, so that
886 the start button and bands are not stuck to the screen border. */
887 sr
.Size
.cx
= StartBtnSize
.cx
+ (2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
));
888 sr
.Size
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
890 /* Use the primary screen by default */
893 rcScreen
.right
= GetSystemMetrics(SM_CXSCREEN
);
894 rcScreen
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
895 GetScreenRectFromRect(
897 MONITOR_DEFAULTTOPRIMARY
);
902 AlwaysOnTop
? HWND_TOPMOST
: HWND_NOTOPMOST
,
907 SWP_NOMOVE
| SWP_NOSIZE
);
909 /* Determine a minimum tray window rectangle. The "client" height is
910 zero here since we cannot determine an optimal minimum width when
911 loaded as a vertical tray window. We just need to make sure the values
912 loaded from the registry are at least. The windows explorer behaves
913 the same way, it allows the user to save a zero width vertical tray
914 window, but not a zero height horizontal tray window. */
915 WndSize
.cx
= 2 * (EdgeSize
.cx
+ DlgFrameSize
.cx
);
916 WndSize
.cy
= StartBtnSize
.cy
+ (2 * (EdgeSize
.cy
+ DlgFrameSize
.cy
));
918 if (WndSize
.cx
< sr
.Size
.cx
)
919 WndSize
.cx
= sr
.Size
.cx
;
920 if (WndSize
.cy
< sr
.Size
.cy
)
921 WndSize
.cy
= sr
.Size
.cy
;
923 /* Save the calculated size */
926 /* Calculate all docking rectangles. We need to do this here so they're
927 initialized and dragging the tray window to another position gives
933 GetTrayRectFromScreenRect(
938 // TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, rcTrayWnd[Pos].left, rcTrayWnd[Pos].top, rcTrayWnd[Pos].right, rcTrayWnd[Pos].bottom);
941 /* Determine which monitor we are on. It shouldn't matter which docked
942 position rectangle we use */
943 Monitor
= GetMonitorFromRect(
944 &rcTrayWnd
[ABE_LEFT
]);
950 IN POINT
*ppt OPTIONAL
,
951 IN HWND hwndExclude OPTIONAL
,
953 IN BOOL IsContextMenu
)
955 TPMPARAMS tmp
, *ptmp
= NULL
;
960 if (hwndExclude
!= NULL
)
962 /* Get the client rectangle and map it to screen coordinates */
963 if (::GetClientRect(hwndExclude
,
965 MapWindowPoints(hwndExclude
,
967 (LPPOINT
) &tmp
.rcExclude
,
977 GetClientRect(&tmp
.rcExclude
) &&
978 MapWindowPoints(m_hWnd
,
980 (LPPOINT
) &tmp
.rcExclude
,
988 /* NOTE: TrackPopupMenuEx will eventually align the track position
989 for us, no need to take care of it here as long as the
990 coordinates are somewhere within the exclusion rectangle */
991 pt
.x
= ptmp
->rcExclude
.left
;
992 pt
.y
= ptmp
->rcExclude
.top
;
1000 tmp
.cbSize
= sizeof(tmp
);
1002 fuFlags
= TPM_RETURNCMD
| TPM_VERTICAL
;
1003 fuFlags
|= (TrackUp
? TPM_BOTTOMALIGN
: TPM_TOPALIGN
);
1005 fuFlags
|= TPM_RIGHTBUTTON
;
1007 fuFlags
|= (TrackUp
? TPM_VERNEGANIMATION
: TPM_VERPOSANIMATION
);
1009 cmdId
= TrackPopupMenuEx(hMenu
,
1019 HRESULT
TrackCtxMenu(
1020 IN IContextMenu
* contextMenu
,
1021 IN POINT
*ppt OPTIONAL
,
1022 IN HWND hwndExclude OPTIONAL
,
1024 IN PVOID Context OPTIONAL
)
1030 HMENU popup
= CreatePopupMenu();
1035 TRACE("Before Query\n");
1036 hr
= contextMenu
->QueryContextMenu(popup
, 0, 0, UINT_MAX
, CMF_NORMAL
);
1037 if (FAILED_UNEXPECTEDLY(hr
))
1039 TRACE("Query failed\n");
1044 TRACE("Before Tracking\n");
1045 uCommand
= ::TrackPopupMenuEx(popup
, TPM_RETURNCMD
, x
, y
, m_hWnd
, NULL
);
1049 TRACE("Before InvokeCommand\n");
1050 CMINVOKECOMMANDINFO cmi
= { 0 };
1051 cmi
.cbSize
= sizeof(cmi
);
1052 cmi
.lpVerb
= MAKEINTRESOURCEA(uCommand
);
1054 hr
= contextMenu
->InvokeCommand(&cmi
);
1058 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand
, GetLastError());
1067 VOID
UpdateStartButton(IN HBITMAP hbmStart OPTIONAL
)
1069 SIZE Size
= { 0, 0 };
1071 if (himlStartBtn
== NULL
||
1072 !StartButton
.SendMessage(BCM_GETIDEALSIZE
, 0, (LPARAM
) &Size
))
1074 Size
.cx
= GetSystemMetrics(SM_CXEDGE
);
1075 Size
.cy
= GetSystemMetrics(SM_CYEDGE
);
1077 if (hbmStart
== NULL
)
1079 hbmStart
= (HBITMAP
) StartButton
.SendMessage(BM_GETIMAGE
, IMAGE_BITMAP
, 0);
1082 if (hbmStart
!= NULL
)
1086 if (GetObject(hbmStart
,
1090 Size
.cx
+= bmp
.bmWidth
;
1091 Size
.cy
+= max(bmp
.bmHeight
,
1092 GetSystemMetrics(SM_CYCAPTION
));
1096 /* Huh?! Shouldn't happen... */
1103 Size
.cx
+= GetSystemMetrics(SM_CXMINIMIZED
);
1104 Size
.cy
+= GetSystemMetrics(SM_CYCAPTION
);
1108 /* Save the size of the start button */
1109 StartBtnSize
= Size
;
1113 AlignControls(IN PRECT prcClient OPTIONAL
)
1116 SIZE TraySize
, StartSize
;
1117 POINT ptTrayNotify
= { 0, 0 };
1121 UpdateStartButton(NULL
);
1122 if (prcClient
!= NULL
)
1124 rcClient
= *prcClient
;
1128 if (!GetClientRect(&rcClient
))
1134 Horizontal
= IsPosHorizontal();
1136 /* We're about to resize/move the start button, the rebar control and
1137 the tray notification control */
1138 dwp
= BeginDeferWindowPos(3);
1142 /* Limit the Start button width to the client width, if neccessary */
1143 StartSize
= StartBtnSize
;
1144 if (StartSize
.cx
> rcClient
.right
)
1145 StartSize
.cx
= rcClient
.right
;
1147 if (StartButton
.m_hWnd
!= NULL
)
1149 /* Resize and reposition the button */
1150 dwp
= DeferWindowPos(dwp
,
1157 SWP_NOZORDER
| SWP_NOACTIVATE
);
1162 /* Determine the size that the tray notification window needs */
1166 TraySize
.cy
= rcClient
.bottom
;
1170 TraySize
.cx
= rcClient
.right
;
1174 if (hwndTrayNotify
!= NULL
&&
1175 SendMessage(hwndTrayNotify
,
1176 TNWM_GETMINIMUMSIZE
,
1177 (WPARAM
) Horizontal
,
1178 (LPARAM
) &TraySize
))
1180 /* Move the tray notification window to the desired location */
1182 ptTrayNotify
.x
= rcClient
.right
- TraySize
.cx
;
1184 ptTrayNotify
.y
= rcClient
.bottom
- TraySize
.cy
;
1186 dwp
= DeferWindowPos(dwp
,
1193 SWP_NOZORDER
| SWP_NOACTIVATE
);
1198 /* Resize/Move the rebar control */
1199 if (hwndRebar
!= NULL
)
1201 POINT ptRebar
= { 0, 0 };
1204 SetWindowStyle(hwndRebar
, CCS_VERT
, Horizontal
? 0 : CCS_VERT
);
1208 ptRebar
.x
= StartSize
.cx
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1209 szRebar
.cx
= ptTrayNotify
.x
- ptRebar
.x
;
1210 szRebar
.cy
= rcClient
.bottom
;
1214 ptRebar
.y
= StartSize
.cy
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1215 szRebar
.cx
= rcClient
.right
;
1216 szRebar
.cy
= ptTrayNotify
.y
- ptRebar
.y
;
1219 dwp
= DeferWindowPos(dwp
,
1226 SWP_NOZORDER
| SWP_NOACTIVATE
);
1230 EndDeferWindowPos(dwp
);
1232 if (hwndTaskSwitch
!= NULL
)
1234 /* Update the task switch window configuration */
1235 SendMessage(hwndTaskSwitch
,
1236 TSWM_UPDATETASKBARPOS
,
1243 CreateStartBtnImageList()
1248 if (himlStartBtn
!= NULL
)
1251 IconSize
.cx
= GetSystemMetrics(SM_CXSMICON
);
1252 IconSize
.cy
= GetSystemMetrics(SM_CYSMICON
);
1254 /* Load the start button icon and create a image list for it */
1255 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
1256 MAKEINTRESOURCE(IDI_START
),
1260 LR_SHARED
| LR_DEFAULTCOLOR
);
1262 if (hIconStart
!= NULL
)
1264 himlStartBtn
= (IImageList
*) ImageList_Create(IconSize
.cx
,
1266 ILC_COLOR32
| ILC_MASK
,
1269 if (himlStartBtn
!= NULL
)
1272 himlStartBtn
->ReplaceIcon(-1, hIconStart
, &s
);
1278 /* Failed to add the icon! */
1279 himlStartBtn
->Release();
1280 himlStartBtn
= NULL
;
1287 HBITMAP
CreateStartButtonBitmap()
1289 WCHAR szStartCaption
[32];
1292 HDC hDCScreen
= NULL
;
1293 SIZE Size
, SmallIcon
;
1294 HBITMAP hbmpOld
, hbmp
= NULL
;
1295 HBITMAP hBitmap
= NULL
;
1301 /* NOTE: this is the backwards compatibility code that is used if the
1302 Common Controls Version 6.0 are not available! */
1304 if (!LoadString(hExplorerInstance
,
1307 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1312 /* Load the start button icon */
1313 SmallIcon
.cx
= GetSystemMetrics(SM_CXSMICON
);
1314 SmallIcon
.cy
= GetSystemMetrics(SM_CYSMICON
);
1315 hIconStart
= (HICON
) LoadImage(hExplorerInstance
,
1316 MAKEINTRESOURCE(IDI_START
),
1320 LR_SHARED
| LR_DEFAULTCOLOR
);
1322 hDCScreen
= GetDC(NULL
);
1323 if (hDCScreen
== NULL
)
1326 hDC
= CreateCompatibleDC(hDCScreen
);
1330 hFontOld
= (HFONT
) SelectObject(hDC
, hStartBtnFont
);
1332 Ret
= GetTextExtentPoint32(hDC
,
1334 _tcslen(szStartCaption
),
1342 /* Make sure the height is at least the size of a caption icon. */
1343 if (hIconStart
!= NULL
)
1344 Size
.cx
+= SmallIcon
.cx
+ 4;
1345 Size
.cy
= max(Size
.cy
, SmallIcon
.cy
);
1347 /* Create the bitmap */
1348 hbmp
= CreateCompatibleBitmap(hDCScreen
,
1354 /* Caluclate the button rect */
1357 rcButton
.right
= Size
.cx
;
1358 rcButton
.bottom
= Size
.cy
;
1360 /* Draw the button */
1361 hbmpOld
= (HBITMAP
) SelectObject(hDC
, hbmp
);
1363 Flags
= DC_TEXT
| DC_INBUTTON
;
1364 if (hIconStart
!= NULL
)
1367 if (DrawCapTemp
!= NULL
)
1369 Ret
= DrawCapTemp(NULL
,
1384 /* We successfully created the bitmap! */
1389 if (hDCScreen
!= NULL
)
1404 LRESULT
OnThemeChanged()
1407 CloseThemeData(TaskbarTheme
);
1409 if (IsThemeActive())
1410 TaskbarTheme
= OpenThemeData(m_hWnd
, L
"TaskBar");
1412 TaskbarTheme
= NULL
;
1416 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, 0);
1420 SetWindowStyle(m_hWnd
, WS_THICKFRAME
| WS_BORDER
, WS_THICKFRAME
| WS_BORDER
);
1426 LRESULT
OnThemeChanged(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1428 return OnThemeChanged();
1431 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1433 WCHAR szStartCaption
[32];
1435 ((ITrayWindow
*)this)->AddRef();
1437 SetWindowTheme(m_hWnd
, L
"TaskBar", NULL
);
1440 InterlockedIncrement(&TrayWndCount
);
1442 if (!LoadString(hExplorerInstance
,
1445 sizeof(szStartCaption
) / sizeof(szStartCaption
[0])))
1447 szStartCaption
[0] = TEXT('\0');
1450 if (hStartBtnFont
== NULL
|| hCaptionFont
== NULL
)
1452 NONCLIENTMETRICS ncm
;
1454 /* Get the system fonts, we use the caption font,
1455 always bold, though. */
1456 ncm
.cbSize
= sizeof(ncm
);
1457 if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS
,
1462 if (hCaptionFont
== NULL
)
1464 ncm
.lfCaptionFont
.lfWeight
= FW_NORMAL
;
1465 hCaptionFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1468 if (hStartBtnFont
== NULL
)
1470 ncm
.lfCaptionFont
.lfWeight
= FW_BOLD
;
1471 hStartBtnFont
= CreateFontIndirect(&ncm
.lfCaptionFont
);
1476 /* Create the Start button */
1477 StartButton
.SubclassWindow(CreateWindowEx(
1481 WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
|
1482 BS_PUSHBUTTON
| BS_CENTER
| BS_VCENTER
| BS_BITMAP
,
1488 (HMENU
) IDC_STARTBTN
,
1491 if (StartButton
.m_hWnd
)
1493 SetWindowTheme(StartButton
.m_hWnd
, L
"Start", NULL
);
1494 StartButton
.SendMessage(WM_SETFONT
, (WPARAM
) hStartBtnFont
, FALSE
);
1496 if (CreateStartBtnImageList())
1498 BUTTON_IMAGELIST bil
;
1500 /* Try to set the start button image. this requires the Common
1501 Controls 6.0 to be present (XP and later) */
1502 bil
.himl
= (HIMAGELIST
) himlStartBtn
;
1503 bil
.margin
.left
= bil
.margin
.right
= 1;
1504 bil
.margin
.top
= bil
.margin
.bottom
= 1;
1505 bil
.uAlign
= BUTTON_IMAGELIST_ALIGN_LEFT
;
1507 if (!StartButton
.SendMessage(BCM_SETIMAGELIST
, 0, (LPARAM
) &bil
))
1509 /* Fall back to the deprecated method on older systems that don't
1510 support Common Controls 6.0 */
1511 himlStartBtn
->Release();
1512 himlStartBtn
= NULL
;
1514 goto SetStartBtnImage
;
1517 /* We're using the image list, remove the BS_BITMAP style and
1518 don't center it horizontally */
1519 SetWindowStyle(StartButton
.m_hWnd
, BS_BITMAP
| BS_RIGHT
, 0);
1521 UpdateStartButton(NULL
);
1525 HBITMAP hbmStart
, hbmOld
;
1528 hbmStart
= CreateStartButtonBitmap();
1529 if (hbmStart
!= NULL
)
1531 UpdateStartButton(hbmStart
);
1533 hbmOld
= (HBITMAP
) StartButton
.SendMessage(BM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbmStart
);
1536 DeleteObject(hbmOld
);
1541 /* Load the saved tray window settings */
1544 /* Create and initialize the start menu */
1545 hbmStartMenu
= LoadBitmap(hExplorerInstance
,
1546 MAKEINTRESOURCE(IDB_STARTMENU
));
1547 StartMenuPopup
= CreateStartMenu(this, &StartMenuBand
, hbmStartMenu
, 0);
1549 /* Load the tray band site */
1550 if (TrayBandSite
!= NULL
)
1552 TrayBandSite
.Release();
1555 TrayBandSite
= CreateTrayBandSite(this, &hwndRebar
, &hwndTaskSwitch
);
1556 SetWindowTheme(hwndRebar
, L
"TaskBar", NULL
);
1558 /* Create the tray notification window */
1559 hwndTrayNotify
= CreateTrayNotifyWnd(this, HideClock
);
1561 if (UpdateNonClientMetrics())
1566 /* Move the tray window to the right position and resize it if neccessary */
1567 CheckTrayWndPosition();
1569 /* Align all controls on the tray window */
1573 InitShellServices(&(hdpaShellServices
));
1577 AutoHideState
= AUTOHIDE_HIDING
;
1578 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
1581 RegisterHotKey(m_hWnd
, IDHK_RUN
, MOD_WIN
, 'R');
1582 RegisterHotKey(m_hWnd
, IDHK_MINIMIZE_ALL
, MOD_WIN
, 'M');
1583 RegisterHotKey(m_hWnd
, IDHK_RESTORE_ALL
, MOD_WIN
|MOD_SHIFT
, 'M');
1584 RegisterHotKey(m_hWnd
, IDHK_HELP
, MOD_WIN
, VK_F1
);
1585 RegisterHotKey(m_hWnd
, IDHK_EXPLORE
, MOD_WIN
, 'E');
1586 RegisterHotKey(m_hWnd
, IDHK_FIND
, MOD_WIN
, 'F');
1587 RegisterHotKey(m_hWnd
, IDHK_FIND_COMPUTER
, MOD_WIN
|MOD_CONTROL
, 'F');
1588 RegisterHotKey(m_hWnd
, IDHK_NEXT_TASK
, MOD_WIN
, VK_TAB
);
1589 RegisterHotKey(m_hWnd
, IDHK_PREV_TASK
, MOD_WIN
|MOD_SHIFT
, VK_TAB
);
1590 RegisterHotKey(m_hWnd
, IDHK_SYS_PROPERTIES
, MOD_WIN
, VK_PAUSE
);
1591 RegisterHotKey(m_hWnd
, IDHK_DESKTOP
, MOD_WIN
, 'D');
1592 RegisterHotKey(m_hWnd
, IDHK_PAGER
, MOD_WIN
, 'B');
1597 HRESULT STDMETHODCALLTYPE
Open()
1601 /* Check if there's already a window created and try to show it.
1602 If it was somehow destroyed just create a new tray window. */
1603 if (m_hWnd
!= NULL
&& IsWindow())
1605 if (!IsWindowVisible(m_hWnd
))
1607 CheckTrayWndPosition();
1609 ShowWindow(SW_SHOW
);
1615 DWORD dwExStyle
= WS_EX_TOOLWINDOW
| WS_EX_WINDOWEDGE
;
1617 dwExStyle
|= WS_EX_TOPMOST
;
1619 DWORD dwStyle
= WS_POPUP
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
|
1620 WS_BORDER
| WS_THICKFRAME
;
1622 ZeroMemory(&rcWnd
, sizeof(rcWnd
));
1623 if (Position
!= (DWORD
) -1)
1624 rcWnd
= rcTrayWnd
[Position
];
1626 if (!Create(NULL
, rcWnd
, NULL
, dwStyle
, dwExStyle
))
1632 HRESULT STDMETHODCALLTYPE
Close()
1645 HWND STDMETHODCALLTYPE
GetHWND()
1650 BOOL STDMETHODCALLTYPE
IsSpecialHWND(IN HWND hWnd
)
1652 return (m_hWnd
== hWnd
||
1653 (hWndDesktop
!= NULL
&& m_hWnd
== hWndDesktop
));
1656 BOOL STDMETHODCALLTYPE
1659 return IsPosHorizontal();
1662 HFONT STDMETHODCALLTYPE
GetCaptionFonts(OUT HFONT
*phBoldCaption OPTIONAL
)
1664 if (phBoldCaption
!= NULL
)
1665 *phBoldCaption
= hStartBtnFont
;
1667 return hCaptionFont
;
1670 DWORD WINAPI
TrayPropertiesThread()
1675 GetWindowRect(StartButton
.m_hWnd
, &posRect
);
1676 hwnd
= CreateWindowEx(0,
1679 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1682 posRect
.right
- posRect
.left
,
1683 posRect
.bottom
- posRect
.top
,
1689 hwndTrayPropertiesOwner
= hwnd
;
1691 DisplayTrayProperties(hwnd
);
1693 hwndTrayPropertiesOwner
= NULL
;
1699 static DWORD WINAPI
s_TrayPropertiesThread(IN OUT PVOID pParam
)
1701 CTrayWindow
*This
= (CTrayWindow
*) pParam
;
1703 return This
->TrayPropertiesThread();
1706 HWND STDMETHODCALLTYPE
DisplayProperties()
1710 if (hwndTrayPropertiesOwner
)
1712 hTrayProp
= GetLastActivePopup(hwndTrayPropertiesOwner
);
1713 if (hTrayProp
!= NULL
&&
1714 hTrayProp
!= hwndTrayPropertiesOwner
)
1716 SetForegroundWindow(hTrayProp
);
1721 CloseHandle(CreateThread(NULL
, 0, s_TrayPropertiesThread
, this, 0, NULL
));
1725 VOID
OpenCommonStartMenuDirectory(IN HWND hWndOwner
, IN LPCTSTR lpOperation
)
1727 WCHAR szDir
[MAX_PATH
];
1729 if (SHGetSpecialFolderPath(hWndOwner
,
1731 CSIDL_COMMON_STARTMENU
,
1734 ShellExecute(hWndOwner
,
1743 VOID
OpenTaskManager(IN HWND hWndOwner
)
1745 ShellExecute(hWndOwner
,
1747 TEXT("taskmgr.exe"),
1753 BOOL STDMETHODCALLTYPE
ExecContextMenuCmd(IN UINT uiCmd
)
1755 BOOL bHandled
= TRUE
;
1759 case ID_SHELL_CMD_PROPERTIES
:
1760 DisplayProperties();
1763 case ID_SHELL_CMD_OPEN_ALL_USERS
:
1764 OpenCommonStartMenuDirectory(m_hWnd
,
1768 case ID_SHELL_CMD_EXPLORE_ALL_USERS
:
1769 OpenCommonStartMenuDirectory(m_hWnd
,
1773 case ID_LOCKTASKBAR
:
1774 if (SHRestricted(REST_CLASSICSHELL
) == 0)
1780 case ID_SHELL_CMD_OPEN_TASKMGR
:
1781 OpenTaskManager(m_hWnd
);
1784 case ID_SHELL_CMD_UNDO_ACTION
:
1787 case ID_SHELL_CMD_SHOW_DESKTOP
:
1790 case ID_SHELL_CMD_TILE_WND_H
:
1791 TileWindows(NULL
, MDITILE_HORIZONTAL
, NULL
, 0, NULL
);
1794 case ID_SHELL_CMD_TILE_WND_V
:
1795 TileWindows(NULL
, MDITILE_VERTICAL
, NULL
, 0, NULL
);
1798 case ID_SHELL_CMD_CASCADE_WND
:
1799 CascadeWindows(NULL
, MDITILE_SKIPDISABLED
, NULL
, 0, NULL
);
1802 case ID_SHELL_CMD_CUST_NOTIF
:
1805 case ID_SHELL_CMD_ADJUST_DAT
:
1806 //FIXME: Use SHRunControlPanel
1807 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
1811 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd
);
1819 BOOL STDMETHODCALLTYPE
Lock(IN BOOL bLock
)
1824 if (Locked
!= bLock
)
1828 if (TrayBandSite
!= NULL
)
1830 if (!SUCCEEDED(TrayBandSite
->Lock(
1843 LRESULT
DrawBackground(HDC hdc
)
1848 GetClientRect(&rect
);
1852 GetClientRect(&rect
);
1856 partId
= TBP_BACKGROUNDLEFT
;
1859 partId
= TBP_BACKGROUNDTOP
;
1862 partId
= TBP_BACKGROUNDRIGHT
;
1866 partId
= TBP_BACKGROUNDBOTTOM
;
1870 DrawThemeBackground(TaskbarTheme
, hdc
, partId
, 0, &rect
, 0);
1876 LRESULT
OnEraseBackground(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1878 HDC hdc
= (HDC
) wParam
;
1886 return DrawBackground(hdc
);
1889 int DrawSizer(IN HRGN hRgn
)
1895 GetWindowRect(m_hWnd
, &rect
);
1896 OffsetRect(&rect
, -rect
.left
, -rect
.top
);
1898 hdc
= GetDCEx(m_hWnd
, hRgn
, DCX_WINDOW
| DCX_INTERSECTRGN
| DCX_PARENTCLIP
);
1903 backoundPart
= TBP_SIZINGBARLEFT
;
1904 rect
.left
= rect
.right
- GetSystemMetrics(SM_CXSIZEFRAME
);
1907 backoundPart
= TBP_SIZINGBARTOP
;
1908 rect
.top
= rect
.bottom
- GetSystemMetrics(SM_CYSIZEFRAME
);
1911 backoundPart
= TBP_SIZINGBARRIGHT
;
1912 rect
.right
= rect
.left
+ GetSystemMetrics(SM_CXSIZEFRAME
);
1916 backoundPart
= TBP_SIZINGBARBOTTOM
;
1917 rect
.bottom
= rect
.top
+ GetSystemMetrics(SM_CYSIZEFRAME
);
1921 DrawThemeBackground(TaskbarTheme
, hdc
, backoundPart
, 0, &rect
, 0);
1923 ReleaseDC(m_hWnd
, hdc
);
1927 DWORD WINAPI
RunFileDlgThread()
1930 RUNFILEDLG RunFileDlg
;
1934 GetWindowRect(StartButton
.m_hWnd
, &posRect
);
1936 hwnd
= CreateWindowEx(0,
1939 WS_OVERLAPPED
| WS_DISABLED
| WS_CLIPSIBLINGS
| WS_BORDER
| SS_LEFT
,
1942 posRect
.right
- posRect
.left
,
1943 posRect
.bottom
- posRect
.top
,
1949 hwndRunFileDlgOwner
= hwnd
;
1951 hShell32
= GetModuleHandle(TEXT("SHELL32.DLL"));
1952 RunFileDlg
= (RUNFILEDLG
) GetProcAddress(hShell32
, (LPCSTR
) 61);
1954 RunFileDlg(hwnd
, NULL
, NULL
, NULL
, NULL
, RFF_CALCDIRECTORY
);
1956 hwndRunFileDlgOwner
= NULL
;
1957 ::DestroyWindow(hwnd
);
1962 static DWORD WINAPI
s_RunFileDlgThread(IN OUT PVOID pParam
)
1964 CTrayWindow
* This
= (CTrayWindow
*) pParam
;
1965 return This
->RunFileDlgThread();
1968 void DisplayRunFileDlg()
1971 if (hwndRunFileDlgOwner
)
1973 hRunDlg
= GetLastActivePopup(hwndRunFileDlgOwner
);
1974 if (hRunDlg
!= NULL
&&
1975 hRunDlg
!= hwndRunFileDlgOwner
)
1977 SetForegroundWindow(hRunDlg
);
1982 CloseHandle(CreateThread(NULL
, 0, s_RunFileDlgThread
, this, 0, NULL
));
1985 void PopupStartMenu()
1987 if (StartMenuPopup
!= NULL
)
1993 if (GetWindowRect(StartButton
.m_hWnd
, (RECT
*) &rcExclude
))
1998 pt
.x
= rcExclude
.left
;
1999 pt
.y
= rcExclude
.top
;
2000 dwFlags
|= MPPF_BOTTOM
;
2004 pt
.x
= rcExclude
.left
;
2005 pt
.y
= rcExclude
.bottom
;
2006 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_RIGHT
;
2009 pt
.x
= rcExclude
.right
;
2010 pt
.y
= rcExclude
.bottom
;
2011 dwFlags
|= MPPF_TOP
| MPPF_ALIGN_LEFT
;
2015 StartMenuPopup
->Popup(
2020 StartButton
.SendMessageW(BM_SETSTATE
, TRUE
, 0);
2025 void ProcessMouseTracking()
2030 UINT state
= AutoHideState
;
2033 GetWindowRect(m_hWnd
, &rcCurrent
);
2034 over
= PtInRect(&rcCurrent
, pt
);
2036 if (StartButton
.SendMessage( BM_GETSTATE
, 0, 0) != BST_UNCHECKED
)
2043 if (state
== AUTOHIDE_HIDING
)
2045 TRACE("AutoHide cancelling hide.\n");
2046 AutoHideState
= AUTOHIDE_SHOWING
;
2047 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2049 else if (state
== AUTOHIDE_HIDDEN
)
2051 TRACE("AutoHide starting show.\n");
2052 AutoHideState
= AUTOHIDE_SHOWING
;
2053 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_SHOW
, NULL
);
2058 if (state
== AUTOHIDE_SHOWING
)
2060 TRACE("AutoHide cancelling show.\n");
2061 AutoHideState
= AUTOHIDE_HIDING
;
2062 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2064 else if (state
== AUTOHIDE_SHOWN
)
2066 TRACE("AutoHide starting hide.\n");
2067 AutoHideState
= AUTOHIDE_HIDING
;
2068 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_DELAY_HIDE
, NULL
);
2071 KillTimer(TIMER_ID_MOUSETRACK
);
2075 void ProcessAutoHide()
2077 RECT rc
= rcTrayWnd
[Position
];
2078 INT w
= TraySize
.cx
- GetSystemMetrics(SM_CXBORDER
) * 2 - 1;
2079 INT h
= TraySize
.cy
- GetSystemMetrics(SM_CYBORDER
) * 2 - 1;
2081 TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", AutoHideState
, rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, w
, h
);
2083 switch (AutoHideState
)
2085 case AUTOHIDE_HIDING
:
2089 AutoHideOffset
.cy
= 0;
2090 AutoHideOffset
.cx
-= AUTOHIDE_SPEED_HIDE
;
2091 if (AutoHideOffset
.cx
< -w
)
2092 AutoHideOffset
.cx
= -w
;
2095 AutoHideOffset
.cx
= 0;
2096 AutoHideOffset
.cy
-= AUTOHIDE_SPEED_HIDE
;
2097 if (AutoHideOffset
.cy
< -h
)
2098 AutoHideOffset
.cy
= -h
;
2101 AutoHideOffset
.cy
= 0;
2102 AutoHideOffset
.cx
+= AUTOHIDE_SPEED_HIDE
;
2103 if (AutoHideOffset
.cx
> w
)
2104 AutoHideOffset
.cx
= w
;
2107 AutoHideOffset
.cx
= 0;
2108 AutoHideOffset
.cy
+= AUTOHIDE_SPEED_HIDE
;
2109 if (AutoHideOffset
.cy
> h
)
2110 AutoHideOffset
.cy
= h
;
2114 if (AutoHideOffset
.cx
!= w
&& AutoHideOffset
.cy
!= h
)
2116 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2121 case AUTOHIDE_HIDDEN
:
2126 AutoHideOffset
.cx
= -w
;
2127 AutoHideOffset
.cy
= 0;
2130 AutoHideOffset
.cx
= 0;
2131 AutoHideOffset
.cy
= -h
;
2134 AutoHideOffset
.cx
= w
;
2135 AutoHideOffset
.cy
= 0;
2138 AutoHideOffset
.cx
= 0;
2139 AutoHideOffset
.cy
= h
;
2143 KillTimer(TIMER_ID_AUTOHIDE
);
2144 AutoHideState
= AUTOHIDE_HIDDEN
;
2147 case AUTOHIDE_SHOWING
:
2148 if (AutoHideOffset
.cx
>= AUTOHIDE_SPEED_SHOW
)
2150 AutoHideOffset
.cx
-= AUTOHIDE_SPEED_SHOW
;
2152 else if (AutoHideOffset
.cx
<= -AUTOHIDE_SPEED_SHOW
)
2154 AutoHideOffset
.cx
+= AUTOHIDE_SPEED_SHOW
;
2158 AutoHideOffset
.cx
= 0;
2161 if (AutoHideOffset
.cy
>= AUTOHIDE_SPEED_SHOW
)
2163 AutoHideOffset
.cy
-= AUTOHIDE_SPEED_SHOW
;
2165 else if (AutoHideOffset
.cy
<= -AUTOHIDE_SPEED_SHOW
)
2167 AutoHideOffset
.cy
+= AUTOHIDE_SPEED_SHOW
;
2171 AutoHideOffset
.cy
= 0;
2174 if (AutoHideOffset
.cx
!= 0 || AutoHideOffset
.cy
!= 0)
2176 SetTimer(TIMER_ID_AUTOHIDE
, AUTOHIDE_INTERVAL_ANIMATING
, NULL
);
2181 case AUTOHIDE_SHOWN
:
2183 KillTimer(TIMER_ID_AUTOHIDE
);
2184 AutoHideState
= AUTOHIDE_SHOWN
;
2188 rc
.left
+= AutoHideOffset
.cx
;
2189 rc
.right
+= AutoHideOffset
.cx
;
2190 rc
.top
+= AutoHideOffset
.cy
;
2191 rc
.bottom
+= AutoHideOffset
.cy
;
2193 TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc
.left
, rc
.top
, rc
.right
, rc
.bottom
, AutoHideState
);
2194 SetWindowPos(NULL
, rc
.left
, rc
.top
, rc
.right
- rc
.left
, rc
.bottom
- rc
.top
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2197 LRESULT
OnDisplayChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2199 /* Load the saved tray window settings */
2202 /* Move the tray window to the right position and resize it if neccessary */
2203 CheckTrayWndPosition();
2205 /* Align all controls on the tray window */
2206 AlignControls(NULL
);
2211 LRESULT
OnCopyData(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2215 TrayNotify_NotifyMsg(wParam
, lParam
);
2220 LRESULT
OnNcPaint(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2228 return DrawSizer((HRGN
) wParam
);
2231 LRESULT
OnCtlColorBtn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2233 SetBkMode((HDC
) wParam
, TRANSPARENT
);
2234 return (LRESULT
) GetStockObject(HOLLOW_BRUSH
);
2237 LRESULT
OnNcHitTest(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2244 /* The user may not be able to resize the tray window.
2245 Pretend like the window is not sizeable when the user
2246 clicks on the border. */
2250 SetLastError(ERROR_SUCCESS
);
2251 if (GetClientRect(&rcClient
) &&
2252 (MapWindowPoints(m_hWnd
, NULL
, (LPPOINT
) &rcClient
, 2) != 0 || GetLastError() == ERROR_SUCCESS
))
2254 pt
.x
= (SHORT
) LOWORD(lParam
);
2255 pt
.y
= (SHORT
) HIWORD(lParam
);
2257 if (PtInRect(&rcClient
,
2260 /* The user is trying to drag the tray window */
2264 /* Depending on the position of the tray window, allow only
2265 changing the border next to the monitor working area */
2269 if (pt
.y
> rcClient
.bottom
)
2273 if (pt
.x
> rcClient
.right
)
2277 if (pt
.x
< rcClient
.left
)
2282 if (pt
.y
< rcClient
.top
)
2291 LRESULT
OnMoving(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2294 PRECT pRect
= (PRECT
) lParam
;
2296 /* We need to ensure that an application can not accidently
2297 move the tray window (using SetWindowPos). However, we still
2298 need to be able to move the window in case the user wants to
2299 drag the tray window to another position or in case the user
2300 wants to resize the tray window. */
2301 if (!Locked
&& GetCursorPos(&ptCursor
))
2304 DraggingPosition
= GetDraggingRectFromPt(
2311 *pRect
= rcTrayWnd
[Position
];
2315 pRect
->left
+= AutoHideOffset
.cx
;
2316 pRect
->right
+= AutoHideOffset
.cx
;
2317 pRect
->top
+= AutoHideOffset
.cy
;
2318 pRect
->bottom
+= AutoHideOffset
.cy
;
2324 LRESULT
OnSizing(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2326 PRECT pRect
= (PRECT
) lParam
;
2330 CalculateValidSize(Position
, pRect
);
2334 *pRect
= rcTrayWnd
[Position
];
2338 pRect
->left
+= AutoHideOffset
.cx
;
2339 pRect
->right
+= AutoHideOffset
.cx
;
2340 pRect
->top
+= AutoHideOffset
.cy
;
2341 pRect
->bottom
+= AutoHideOffset
.cy
;
2347 LRESULT
OnWindowPosChange(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2349 ChangingWinPos((LPWINDOWPOS
) lParam
);
2353 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2356 InvalidateRect(NULL
, TRUE
);
2357 if (wParam
== SIZE_RESTORED
&& lParam
== 0)
2360 /* Clip the tray window on multi monitor systems so the edges can't
2361 overlap into another monitor */
2362 ApplyClipping(TRUE
);
2364 if (!GetClientRect(&rcClient
))
2371 rcClient
.left
= rcClient
.top
= 0;
2372 rcClient
.right
= LOWORD(lParam
);
2373 rcClient
.bottom
= HIWORD(lParam
);
2376 AlignControls(&rcClient
);
2380 LRESULT
OnEnterSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2386 /* Remove the clipping on multi monitor systems while dragging around */
2387 ApplyClipping(FALSE
);
2392 LRESULT
OnExitSizeMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2397 /* Apply clipping */
2398 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2403 LRESULT
OnSysChar(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2409 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2410 The tray window needs to handle this specially, since it normally doesn't have
2413 static const UINT uidDisableItem
[] = {
2424 /* temporarily enable the system menu */
2425 SetWindowStyle(m_hWnd
, WS_SYSMENU
, WS_SYSMENU
);
2427 hSysMenu
= GetSystemMenu(m_hWnd
, FALSE
);
2428 if (hSysMenu
!= NULL
)
2430 /* Disable all items that are not relevant */
2431 for (i
= 0; i
!= sizeof(uidDisableItem
) / sizeof(uidDisableItem
[0]); i
++)
2433 EnableMenuItem(hSysMenu
,
2435 MF_BYCOMMAND
| MF_GRAYED
);
2438 EnableMenuItem(hSysMenu
,
2441 (SHRestricted(REST_NOCLOSE
) ? MF_GRAYED
: MF_ENABLED
));
2443 /* Display the system menu */
2448 Position
!= ABE_TOP
,
2459 /* revert the system menu window style */
2460 SetWindowStyle(m_hWnd
, WS_SYSMENU
, 0);
2470 LRESULT
OnNcRButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2472 /* We want the user to be able to get a context menu even on the nonclient
2473 area (including the sizing border)! */
2474 uMsg
= WM_CONTEXTMENU
;
2475 wParam
= (WPARAM
) m_hWnd
;
2477 return OnContextMenu(uMsg
, wParam
, lParam
, bHandled
);
2480 LRESULT
OnContextMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2482 LRESULT Ret
= FALSE
;
2483 POINT pt
, *ppt
= NULL
;
2484 HWND hWndExclude
= NULL
;
2486 /* Check if the administrator has forbidden access to context menus */
2487 if (SHRestricted(REST_NOTRAYCONTEXTMENU
))
2490 pt
.x
= (SHORT
) LOWORD(lParam
);
2491 pt
.y
= (SHORT
) HIWORD(lParam
);
2493 if (pt
.x
!= -1 || pt
.y
!= -1)
2496 hWndExclude
= StartButton
.m_hWnd
;
2498 if ((HWND
) wParam
== StartButton
.m_hWnd
)
2500 /* Make sure we can't track the context menu if the start
2501 menu is currently being shown */
2502 if (!(StartButton
.SendMessage(BM_GETSTATE
, 0, 0) & BST_PUSHED
))
2504 CComPtr
<IContextMenu
> ctxMenu
;
2505 StartMenuBtnCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2506 TrackCtxMenu(ctxMenu
, ppt
, hWndExclude
, Position
== ABE_BOTTOM
, this);
2511 /* See if the context menu should be handled by the task band site */
2512 if (ppt
!= NULL
&& TrayBandSite
!= NULL
)
2515 POINT ptClient
= *ppt
;
2517 /* Convert the coordinates to client-coordinates */
2518 MapWindowPoints(NULL
, m_hWnd
, &ptClient
, 1);
2520 hWndAtPt
= ChildWindowFromPoint(m_hWnd
, ptClient
);
2521 if (hWndAtPt
!= NULL
&&
2522 (hWndAtPt
== hwndRebar
|| IsChild(hwndRebar
,
2525 /* Check if the user clicked on the task switch window */
2527 MapWindowPoints(NULL
, hwndRebar
, &ptClient
, 1);
2529 hWndAtPt
= ChildWindowFromPointEx(hwndRebar
, ptClient
, CWP_SKIPINVISIBLE
| CWP_SKIPDISABLED
);
2530 if (hWndAtPt
== hwndTaskSwitch
)
2531 goto HandleTrayContextMenu
;
2533 /* Forward the message to the task band site */
2534 TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2537 goto HandleTrayContextMenu
;
2541 HandleTrayContextMenu
:
2542 /* Tray the default tray window context menu */
2543 CComPtr
<IContextMenu
> ctxMenu
;
2544 TrayWindowCtxMenuCreator(this, m_hWnd
, &ctxMenu
);
2545 TrackCtxMenu(ctxMenu
, ppt
, NULL
, FALSE
, this);
2551 LRESULT
OnNotify(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2553 LRESULT Ret
= FALSE
;
2554 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
2555 the rebar control! But we shouldn't forward messages that the band
2556 site doesn't handle, such as other controls (start button, tray window */
2558 HRESULT hr
= E_FAIL
;
2562 hr
= TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
);
2567 if (TrayBandSite
== NULL
|| FAILED(hr
))
2569 const NMHDR
*nmh
= (const NMHDR
*) lParam
;
2571 if (nmh
->hwndFrom
== hwndTrayNotify
)
2576 /* Cause all controls to be aligned */
2577 PostMessage(m_hWnd
, WM_SIZE
, SIZE_RESTORED
, 0);
2585 LRESULT
OnNcLButtonDblClick(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2587 /* We "handle" this message so users can't cause a weird maximize/restore
2588 window animation when double-clicking the tray window! */
2590 /* We should forward mouse messages to child windows here.
2591 Right now, this is only clock double-click */
2593 if (TrayNotify_GetClockRect(&rcClock
))
2596 ptClick
.x
= MAKEPOINTS(lParam
).x
;
2597 ptClick
.y
= MAKEPOINTS(lParam
).y
;
2598 if (PtInRect(&rcClock
, ptClick
))
2600 //FIXME: use SHRunControlPanel
2601 ShellExecuteW(m_hWnd
, NULL
, L
"timedate.cpl", NULL
, NULL
, SW_NORMAL
);
2607 LRESULT
OnAppTrayDestroy(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2613 LRESULT
OnOpenStartMenu(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2616 HRESULT hr
= IUnknown_GetWindow((IUnknown
*) StartMenuPopup
, &hwndStartMenu
);
2617 if (FAILED_UNEXPECTEDLY(hr
))
2620 if (IsWindowVisible(hwndStartMenu
))
2622 StartMenuPopup
->OnSelect(MPOS_CANCELLEVEL
);
2632 LRESULT
DoExitWindows()
2634 ExitWindowsDialog(m_hWnd
);
2638 LRESULT
OnDoExitWindows(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2641 * TWM_DOEXITWINDOWS is send by the CDesktopBrowserr to us to
2642 * show the shutdown dialog
2644 return DoExitWindows();
2647 LRESULT
OnSysCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2649 if (wParam
== SC_CLOSE
)
2651 return DoExitWindows();
2658 HRESULT
ExecResourceCmd(int id
)
2660 WCHAR szCommand
[256];
2661 WCHAR
*pszParameters
;
2663 if (!LoadString(hExplorerInstance
,
2666 sizeof(szCommand
) / sizeof(szCommand
[0])))
2671 pszParameters
= wcschr(szCommand
, L
'>');
2678 ShellExecuteW(m_hWnd
, NULL
, szCommand
, pszParameters
, NULL
, 0);
2682 LRESULT
OnHotkey(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2687 DisplayRunFileDlg();
2690 ExecResourceCmd(IDS_HELP_COMMAND
);
2693 ShellExecuteW(0, L
"explore", NULL
, NULL
, NULL
, 1);
2696 SHFindFiles(NULL
, NULL
);
2698 case IDHK_FIND_COMPUTER
:
2699 SHFindComputer(NULL
, NULL
);
2701 case IDHK_SYS_PROPERTIES
:
2702 //FIXME: Use SHRunControlPanel
2703 ShellExecuteW(m_hWnd
, NULL
, L
"sysdm.cpl", NULL
, NULL
, SW_NORMAL
);
2705 case IDHK_NEXT_TASK
:
2707 case IDHK_PREV_TASK
:
2709 case IDHK_MINIMIZE_ALL
:
2711 case IDHK_RESTORE_ALL
:
2722 LRESULT
OnCommand(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2724 LRESULT Ret
= FALSE
;
2726 if ((HWND
) lParam
== StartButton
.m_hWnd
)
2732 if (TrayBandSite
== NULL
|| FAILED_UNEXPECTEDLY(TrayBandSite
->ProcessMessage(m_hWnd
, uMsg
, wParam
, lParam
, &Ret
)))
2734 switch (LOWORD(wParam
))
2736 /* FIXME: Handle these commands as well */
2737 case IDM_TASKBARANDSTARTMENU
:
2738 DisplayProperties();
2742 SHFindFiles(NULL
, NULL
);
2745 case IDM_HELPANDSUPPORT
:
2746 ExecResourceCmd(IDS_HELP_COMMAND
);
2750 DisplayRunFileDlg();
2753 /* FIXME: Handle these commands as well */
2754 case IDM_SYNCHRONIZE
:
2756 case IDM_DISCONNECT
:
2757 case IDM_UNDOCKCOMPUTER
:
2768 LRESULT
OnMouseMove(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2772 SetTimer(TIMER_ID_MOUSETRACK
, MOUSETRACK_INTERVAL
, NULL
);
2778 LRESULT
OnTimer(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2780 if (wParam
== TIMER_ID_MOUSETRACK
)
2782 ProcessMouseTracking();
2784 else if (wParam
== TIMER_ID_AUTOHIDE
)
2793 LRESULT
OnRebarAutoSize(INT code
, LPNMHDR nmhdr
, BOOL
& bHandled
)
2796 LPNMRBAUTOSIZE as
= (LPNMRBAUTOSIZE
) nmhdr
;
2802 ::GetWindowRect(m_hWnd
, &rc
);
2806 rc
.bottom
- rc
.top
};
2808 as
->rcTarget
.right
- as
->rcTarget
.left
,
2809 as
->rcTarget
.bottom
- as
->rcTarget
.top
};
2811 as
->rcActual
.right
- as
->rcActual
.left
,
2812 as
->rcActual
.bottom
- as
->rcActual
.top
};
2815 szWindow
.cx
- szTarget
.cx
,
2816 szWindow
.cy
- szTarget
.cx
,
2822 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2825 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2828 szWindow
.cx
= szActual
.cx
+ borders
.cx
;
2829 rc
.left
= rc
.right
- szWindow
.cy
;
2832 szWindow
.cy
= szActual
.cy
+ borders
.cy
;
2833 rc
.top
= rc
.bottom
- szWindow
.cy
;
2837 SetWindowPos(NULL
, rc
.left
, rc
.top
, szWindow
.cx
, szWindow
.cy
, SWP_NOACTIVATE
| SWP_NOZORDER
);
2844 DECLARE_WND_CLASS_EX(szTrayWndClass
, CS_DBLCLKS
, COLOR_3DFACE
)
2846 BEGIN_MSG_MAP(CTrayWindow
)
2847 if (StartMenuBand
!= NULL
)
2854 Msg
.wParam
= wParam
;
2855 Msg
.lParam
= lParam
;
2857 if (StartMenuBand
->TranslateMenuMessage(&Msg
, &lRet
) == S_OK
)
2862 wParam
= Msg
.wParam
;
2863 lParam
= Msg
.lParam
;
2865 MESSAGE_HANDLER(WM_THEMECHANGED
, OnThemeChanged
)
2866 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE
, OnRebarAutoSize
) // Doesn't quite work ;P
2867 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2868 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2869 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2870 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
2871 MESSAGE_HANDLER(WM_NCHITTEST
, OnNcHitTest
)
2872 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2873 MESSAGE_HANDLER(WM_SYSCOMMAND
, OnSysCommand
)
2874 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2875 MESSAGE_HANDLER(WM_CONTEXTMENU
, OnContextMenu
)
2876 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
2877 MESSAGE_HANDLER(WM_DISPLAYCHANGE
, OnDisplayChange
)
2878 MESSAGE_HANDLER(WM_COPYDATA
, OnCopyData
)
2879 MESSAGE_HANDLER(WM_NCPAINT
, OnNcPaint
)
2880 MESSAGE_HANDLER(WM_CTLCOLORBTN
, OnCtlColorBtn
)
2881 MESSAGE_HANDLER(WM_MOVING
, OnMoving
)
2882 MESSAGE_HANDLER(WM_SIZING
, OnSizing
)
2883 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING
, OnWindowPosChange
)
2884 MESSAGE_HANDLER(WM_ENTERSIZEMOVE
, OnEnterSizeMove
)
2885 MESSAGE_HANDLER(WM_EXITSIZEMOVE
, OnExitSizeMove
)
2886 MESSAGE_HANDLER(WM_SYSCHAR
, OnSysChar
)
2887 MESSAGE_HANDLER(WM_NCRBUTTONUP
, OnNcRButtonUp
)
2888 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK
, OnNcLButtonDblClick
)
2889 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
2890 MESSAGE_HANDLER(WM_NCMOUSEMOVE
, OnMouseMove
)
2891 MESSAGE_HANDLER(WM_APP_TRAYDESTROY
, OnAppTrayDestroy
)
2892 MESSAGE_HANDLER(TWM_OPENSTARTMENU
, OnOpenStartMenu
)
2893 MESSAGE_HANDLER(TWM_DOEXITWINDOWS
, OnDoExitWindows
)
2894 MESSAGE_HANDLER(WM_HOTKEY
, OnHotkey
)
2898 /*****************************************************************************/
2900 VOID
TrayProcessMessages()
2904 /* FIXME: We should keep a reference here... */
2906 while (PeekMessage(&Msg
,
2912 if (Msg
.message
== WM_QUIT
)
2915 if (StartMenuBand
== NULL
||
2916 StartMenuBand
->IsMenuMessage(
2919 TranslateMessage(&Msg
);
2920 DispatchMessage(&Msg
);
2925 VOID
TrayMessageLoop()
2930 /* FIXME: We should keep a reference here... */
2934 Ret
= GetMessage(&Msg
, NULL
, 0, 0);
2936 if (!Ret
|| Ret
== -1)
2939 if (StartMenuBand
== NULL
||
2940 StartMenuBand
->IsMenuMessage(&Msg
) != S_OK
)
2942 TranslateMessage(&Msg
);
2943 DispatchMessage(&Msg
);
2951 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
2952 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
2953 * The reason we implement it is because we have to use SHCreateDesktop() so
2954 * that the shell provides the desktop window and all the features that come
2955 * with it (especially positioning of desktop icons)
2958 virtual ULONG STDMETHODCALLTYPE
GetState()
2960 /* FIXME: Return ABS_ flags? */
2961 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
2965 virtual HRESULT STDMETHODCALLTYPE
GetTrayWindow(OUT HWND
*phWndTray
)
2967 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray
);
2968 *phWndTray
= m_hWnd
;
2972 virtual HRESULT STDMETHODCALLTYPE
RegisterDesktopWindow(IN HWND hWndDesktop
)
2974 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop
);
2976 this->hWndDesktop
= hWndDesktop
;
2980 virtual HRESULT STDMETHODCALLTYPE
Unknown(IN DWORD dwUnknown1
, IN DWORD dwUnknown2
)
2982 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1
, dwUnknown2
);
2986 virtual HRESULT
RaiseStartButton()
2988 StartButton
.SendMessageW(BM_SETSTATE
, FALSE
, 0);
2994 Position
= (DWORD
) -1;
2997 DECLARE_NOT_AGGREGATABLE(CTrayWindow
)
2999 DECLARE_PROTECT_FINAL_CONSTRUCT()
3000 BEGIN_COM_MAP(CTrayWindow
)
3001 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3002 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray
, IShellDesktopTray
)
3006 class CTrayWindowCtxMenu
:
3007 public CComCoClass
<CTrayWindowCtxMenu
>,
3008 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
3012 CComPtr
<CTrayWindow
> TrayWnd
;
3013 CComPtr
<IContextMenu
> pcm
;
3016 HRESULT
Initialize(ITrayWindow
* pTrayWnd
, IN HWND hWndOwner
)
3018 this->TrayWnd
= (CTrayWindow
*) pTrayWnd
;
3019 this->hWndOwner
= hWndOwner
;
3023 virtual HRESULT STDMETHODCALLTYPE
3024 QueryContextMenu(HMENU hPopup
,
3030 HMENU menubase
= LoadPopupMenu(hExplorerInstance
, MAKEINTRESOURCE(IDM_TRAYWND
));
3033 return HRESULT_FROM_WIN32(GetLastError());
3035 int count
= ::GetMenuItemCount(menubase
);
3037 for (int i
= 0; i
< count
; i
++)
3041 MENUITEMINFOW mii
= { 0 };
3042 mii
.cbSize
= sizeof(mii
);
3043 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_SUBMENU
| MIIM_CHECKMARKS
3044 | MIIM_DATA
| MIIM_STRING
| MIIM_BITMAP
| MIIM_FTYPE
;
3045 mii
.dwTypeData
= label
;
3046 mii
.cch
= _countof(label
);
3047 ::GetMenuItemInfoW(menubase
, i
, TRUE
, &mii
);
3049 TRACE("Adding item %d label %S type %d\n", mii
.wID
, mii
.dwTypeData
, mii
.fType
);
3051 mii
.fType
|= MFT_RADIOCHECK
;
3053 ::InsertMenuItemW(hPopup
, i
+ 1, TRUE
, &mii
);
3056 ::DestroyMenu(menubase
);
3058 if (SHRestricted(REST_CLASSICSHELL
) != 0)
3065 CheckMenuItem(hPopup
,
3067 MF_BYCOMMAND
| (TrayWnd
->Locked
? MF_CHECKED
: MF_UNCHECKED
));
3069 if (TrayWnd
->TrayBandSite
!= NULL
)
3071 if (FAILED(TrayWnd
->TrayBandSite
->AddContextMenus(
3079 WARN("AddContextMenus failed.\n");
3087 virtual HRESULT STDMETHODCALLTYPE
3088 InvokeCommand(LPCMINVOKECOMMANDINFO lpici
)
3090 UINT uiCmdId
= (UINT
) lpici
->lpVerb
;
3093 if (uiCmdId
>= ID_SHELL_CMD_FIRST
&& uiCmdId
<= ID_SHELL_CMD_LAST
)
3095 CMINVOKECOMMANDINFO cmici
= { 0 };
3099 /* Setup and invoke the shell command */
3100 cmici
.cbSize
= sizeof(cmici
);
3101 cmici
.hwnd
= hWndOwner
;
3102 cmici
.lpVerb
= (LPCSTR
) MAKEINTRESOURCE(uiCmdId
- ID_SHELL_CMD_FIRST
);
3103 cmici
.nShow
= SW_NORMAL
;
3105 pcm
->InvokeCommand(&cmici
);
3110 TrayWnd
->ExecContextMenuCmd(uiCmdId
);
3117 virtual HRESULT STDMETHODCALLTYPE
3118 GetCommandString(UINT_PTR idCmd
,
3127 CTrayWindowCtxMenu()
3131 virtual ~CTrayWindowCtxMenu()
3135 BEGIN_COM_MAP(CTrayWindowCtxMenu
)
3136 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
3140 HRESULT
TrayWindowCtxMenuCreator(ITrayWindow
* TrayWnd
, IN HWND hWndOwner
, IContextMenu
** ppCtxMenu
)
3142 CTrayWindowCtxMenu
* mnu
= new CComObject
<CTrayWindowCtxMenu
>();
3143 mnu
->Initialize(TrayWnd
, hWndOwner
);
3148 CTrayWindow
* g_TrayWindow
;
3151 Tray_OnStartMenuDismissed()
3153 return g_TrayWindow
->RaiseStartButton();
3157 HRESULT
CreateTrayWindow(ITrayWindow
** ppTray
)
3159 CComPtr
<CTrayWindow
> Tray
= new CComObject
<CTrayWindow
>();
3161 return E_OUTOFMEMORY
;
3165 g_TrayWindow
= Tray
;
3167 *ppTray
= (ITrayWindow
*) Tray
;
3172 VOID
TrayProcessMessages(ITrayWindow
*)
3174 g_TrayWindow
->TrayProcessMessages();
3177 VOID
TrayMessageLoop(ITrayWindow
*)
3179 g_TrayWindow
->TrayMessageLoop();