ReactOS 0.4.15-dev-7089-gea8a49d
traywnd.cpp
Go to the documentation of this file.
1/*
2 * ReactOS Explorer
3 *
4 * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5 * Copyright 2018-2022 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 *
7 * this library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * this library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "precomp.h"
23#include <commoncontrols.h>
24
25HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu);
27void appbar_notify_all(HMONITOR hMon, UINT uMsg, HWND hwndExclude, LPARAM lParam);
28
29#define WM_APP_TRAYDESTROY (WM_APP + 0x100)
30
31#define TIMER_ID_AUTOHIDE 1
32#define TIMER_ID_MOUSETRACK 2
33#define MOUSETRACK_INTERVAL 100
34#define AUTOHIDE_DELAY_HIDE 2000
35#define AUTOHIDE_DELAY_SHOW 50
36#define AUTOHIDE_INTERVAL_ANIMATING 10
37
38#define AUTOHIDE_SPEED_SHOW 10
39#define AUTOHIDE_SPEED_HIDE 1
40
41#define AUTOHIDE_HIDDEN 0
42#define AUTOHIDE_SHOWING 1
43#define AUTOHIDE_SHOWN 2
44#define AUTOHIDE_HIDING 3
45
46#define IDHK_RUN 0x1f4
47#define IDHK_MINIMIZE_ALL 0x1f5
48#define IDHK_RESTORE_ALL 0x1f6
49#define IDHK_HELP 0x1f7
50#define IDHK_EXPLORE 0x1f8
51#define IDHK_FIND 0x1f9
52#define IDHK_FIND_COMPUTER 0x1fa
53#define IDHK_NEXT_TASK 0x1fb
54#define IDHK_PREV_TASK 0x1fc
55#define IDHK_SYS_PROPERTIES 0x1fd
56#define IDHK_DESKTOP 0x1fe
57#define IDHK_PAGER 0x1ff
58
59static const WCHAR szTrayWndClass[] = L"Shell_TrayWnd";
60
62
64{
67};
69
71{
72 WINDOWPOSBACKUPDATA wposdata;
73 HWND hDesk = GetDesktopWindow();
74 if (IsWindowVisible(hwnd) && !IsIconic(hwnd) && (hwnd != hDesk))
75 {
76 wposdata.hwnd = hwnd;
77 wposdata.wplt.length = sizeof(wposdata.wplt);
78 GetWindowPlacement(hwnd, &(wposdata.wplt));
79 g_WindowPosBackup.Add(wposdata);
80 }
81
82 return TRUE;
83}
84
86{
88}
89
91{
93
94 for (INT i = g_WindowPosBackup.GetSize() - 1; i >= 0; --i)
95 {
97 }
98
99 g_WindowPosBackup.RemoveAll();
100}
101
103{
105 {
107 return TRUE;
108
110 if (!(exstyle & WS_EX_TOPMOST))
111 return TRUE;
112 }
113 return FALSE;
114}
115
117{
123};
124
125static BOOL CALLBACK
127{
129
130 if (!CanBeMinimized(hwnd))
131 return TRUE; // continue
132
133 if (pei->hTrayWnd == hwnd || pei->hwndDesktop == hwnd ||
134 pei->hwndProgman == hwnd)
135 {
136 return TRUE; // continue
137 }
138
139 if (pei->bMustBeInMonitor)
140 {
141 // is the window in the nearest monitor?
142 HMONITOR hMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
143 if (hMon)
144 {
146 ZeroMemory(&info, sizeof(info));
147 info.cbSize = sizeof(info);
148 if (GetMonitorInfoW(hMon, &info))
149 {
150 RECT rcWindow, rcMonitor, rcIntersect;
151 rcMonitor = info.rcMonitor;
152
153 GetWindowRect(hwnd, &rcWindow);
154
155 if (!IntersectRect(&rcIntersect, &rcMonitor, &rcWindow))
156 return TRUE; // continue
157 }
158 }
159 }
160
161 pei->hwndFound = hwnd;
162 return FALSE; // stop if found
163}
164
165static BOOL
167{
169 ei.hwndFound = NULL;
171 ei.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
172 ei.hwndProgman = FindWindowW(L"Progman", NULL);
173 ei.bMustBeInMonitor = bMustBeInMonitor;
174
176 return ei.hwndFound != NULL;
177}
178
179/* Minimized window position info */
181{
184};
186
187/*
188 * ITrayWindow
189 */
190
191const GUID IID_IShellDesktopTray = { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
192
194 : public CWindowImpl<CStartButton>
195{
199
200public:
202 : m_ImageList(NULL),
203 m_Font(NULL)
204 {
205 m_Size.cx = 0;
206 m_Size.cy = 0;
207 }
208
210 {
211 if (m_ImageList != NULL)
213
214 if (m_Font != NULL)
216 }
217
219 {
220 return m_Size;
221 }
222
224 {
225 SIZE Size = { 0, 0 };
226
227 if (m_ImageList == NULL ||
229 {
231 }
232
234
235 /* Save the size of the start button */
236 m_Size = Size;
237 }
238
240 {
241 /* Get the system fonts, we use the caption font, always bold, though. */
242 NONCLIENTMETRICS ncm = {sizeof(ncm)};
243 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
244 return;
245
246 if (m_Font)
248
249 ncm.lfCaptionFont.lfWeight = FW_BOLD;
250 m_Font = CreateFontIndirect(&ncm.lfCaptionFont);
251
253 }
254
256 {
257 // HACK & FIXME: CORE-18016
258 HWND hWnd = m_hWnd;
259 m_hWnd = NULL;
261
262 SetWindowTheme(m_hWnd, L"Start", NULL);
263
266 0, 0, 0,
269
272 UpdateSize();
273 }
274
276 {
277 WCHAR szStartCaption[32];
279 IDS_START,
280 szStartCaption,
281 _countof(szStartCaption)))
282 {
283 wcscpy(szStartCaption, L"Start");
284 }
285
287
288 // HACK & FIXME: CORE-18016
290 0,
291 WC_BUTTON,
292 szStartCaption,
293 dwStyle,
294 0, 0, 0, 0,
298 NULL);
299
300 if (m_hWnd)
301 Initialize();
302
303 return m_hWnd;
304 }
305
307 {
308 if (uMsg == WM_KEYUP && wParam != VK_SPACE)
309 return 0;
310
312 return 0;
313 }
314
318
319};
320
321// This window class name is CONFIRMED on Win10 by WinHier.
322static const WCHAR szTrayShowDesktopButton[] = L"TrayShowDesktopButtonWClass";
323
324// The 'Show Desktop' button at edge of taskbar
326 public CWindowImpl<CTrayShowDesktopButton, CWindow, CControlWinTraits>
327{
331
332public:
334
336 {
337 }
338
340 {
341#define SHOW_DESKTOP_MINIMUM_WIDTH 3
343 return max(cxy, SHOW_DESKTOP_MINIMUM_WIDTH);
344 }
345
347 {
350 if (!m_hWnd)
351 return E_FAIL;
352
353 ::SetWindowTheme(m_hWnd, L"TaskBar", NULL);
354 return S_OK;
355 }
356
358 {
359 // The actual action can be delayed as an expected behaviour.
360 // But a too late action is an unexpected behaviour.
361 LONG nTime0 = m_nClickedTime;
362 LONG nTime1 = ::GetMessageTime();
363 if (nTime1 - nTime0 >= 600) // Ignore after 0.6 sec
364 return 0;
365
366 // Show/Hide Desktop
368 return 0;
369 }
370
371#define TSDB_CLICK (WM_USER + 100)
372
373 // This function is called from OnLButtonDown and parent.
375 {
376 // The actual action can be delayed as an expected behaviour.
378 PostMessage(TSDB_CLICK, 0, 0);
379 }
380
382 {
383 Click(); // Left-click
384 return 0;
385 }
386
388 {
389 if (m_hTheme)
391
392 m_hTheme = ::OpenThemeData(m_hWnd, L"TaskBar");
394 return 0;
395 }
396
397 // This function is called from OnPaint and parent.
399
401 {
402 RECT rc;
403 GetClientRect(&rc);
404
405 PAINTSTRUCT ps;
406 HDC hdc = BeginPaint(&ps);
407 OnDraw(hdc, &rc);
408 EndPaint(&ps);
409 return 0;
410 }
411
413 {
414 if (!IsWindow())
415 return FALSE;
416 RECT rc;
417 GetWindowRect(&rc);
419 ::InflateRect(&rc, max(cxEdge, 1), max(cyEdge, 1));
420 return ::PtInRect(&rc, pt);
421 }
422
423#define SHOW_DESKTOP_TIMER_ID 999
424#define SHOW_DESKTOP_TIMER_INTERVAL 200
425
427 {
428 if (m_bHovering)
429 return;
430
435 }
436
438 {
440 return 0;
441 }
442
444 {
446 return 0;
447
448 POINT pt;
450 if (!PtInButton(pt)) // The end of hovering?
451 {
456 }
457
458 return 0;
459 }
460
462 {
463 if (m_hTheme)
464 {
466 m_hTheme = NULL;
467 }
468 return 0;
469 }
470
474 MESSAGE_HANDLER(WM_THEMECHANGED, OnSettingChanged)
481};
482
484{
485 if (m_hTheme)
486 {
487 if (m_bHovering) // Draw a hot button
488 {
489 HTHEME hButtonTheme = ::OpenThemeData(m_hWnd, L"Button");
491 ::CloseThemeData(hButtonTheme);
492 }
493 else // Draw a taskbar background
494 {
496 }
497 }
498 else
499 {
500 RECT rc = *prc;
501 if (m_bHovering) // Draw a hot button
502 {
504 HBRUSH hbrHot = ::CreateSolidBrush(RGB(255, 255, 191));
505 ::FillRect(hdc, &rc, hbrHot);
506 ::DeleteObject(hbrHot);
507 }
508 else // Draw a flattish button
509 {
511 ::InflateRect(&rc, -1, -1);
513 }
514 }
515}
516
518 public CComCoClass<CTrayWindow>,
519 public CComObjectRootEx<CComMultiThreadModelNoCS>,
520 public CWindowImpl < CTrayWindow, CWindow, CControlWinTraits >,
521 public ITrayWindow,
522 public IShellDesktopTray,
523 public IOleWindow,
524 public IContextMenu
525{
528
531
535
537
542
544
550
553
556
560
562
563public:
565
566 union
567 {
569 struct
570 {
571 /* UI Status */
576 };
577 };
578
579public:
583 m_Theme(NULL),
584 m_Font(NULL),
586 m_Rebar(NULL),
589 m_Position(0),
598 Flags(0)
599 {
605 }
606
607 virtual ~CTrayWindow()
608 {
609 if (m_ShellServices != NULL)
610 {
613 }
614
615 if (m_Font != NULL)
616 {
618 m_Font = NULL;
619 }
620
621 if (m_Theme)
622 {
624 m_Theme = NULL;
625 }
626
628 }
629
630
631
632
633
634 /**********************************************************
635 * ##### command handling #####
636 */
637
639 {
640 WCHAR szCommand[256];
641 WCHAR *pszParameters;
642
644 id,
645 szCommand,
646 _countof(szCommand)))
647 {
648 return E_FAIL;
649 }
650
651 pszParameters = wcschr(szCommand, L'>');
652 if (pszParameters)
653 {
654 *pszParameters = 0;
655 pszParameters++;
656 }
657
658 ShellExecuteW(m_hWnd, NULL, szCommand, pszParameters, NULL, SW_SHOWNORMAL);
659 return S_OK;
660 }
661
663 {
664 /* Display the ReactOS Shutdown Dialog */
666
667 /*
668 * If the user presses CTRL+ALT+SHIFT while exiting
669 * the shutdown dialog, exit the shell cleanly.
670 */
671 if ((GetKeyState(VK_CONTROL) & 0x8000) &&
672 (GetKeyState(VK_SHIFT) & 0x8000) &&
673 (GetKeyState(VK_MENU) & 0x8000))
674 {
675 PostMessage(WM_QUIT, 0, 0);
676 }
677 return 0;
678 }
679
681 {
682 HWND hwnd;
683 RECT posRect;
684
686
688 WC_STATIC,
689 NULL,
691 posRect.left,
692 posRect.top,
693 posRect.right - posRect.left,
694 posRect.bottom - posRect.top,
695 NULL,
696 NULL,
697 NULL,
698 NULL);
699
701
702 // build the default directory from two environment variables
703 CStringW strDefaultDir, strHomePath;
704 strDefaultDir.GetEnvironmentVariable(L"HOMEDRIVE");
705 strHomePath.GetEnvironmentVariable(L"HOMEPATH");
706 strDefaultDir += strHomePath;
707
709
712
713 return 0;
714 }
715
717 {
718 CTrayWindow * This = (CTrayWindow*) pParam;
719 return This->RunFileDlgThread();
720 }
721
723 {
724 HWND hRunDlg;
726 {
728 if (hRunDlg != NULL &&
729 hRunDlg != m_RunFileDlgOwner)
730 {
731 SetForegroundWindow(hRunDlg);
732 return;
733 }
734 }
735
737 }
738
740 {
741 HWND hwnd;
742 RECT posRect;
743
746 WC_STATIC,
747 NULL,
749 posRect.left,
750 posRect.top,
751 posRect.right - posRect.left,
752 posRect.bottom - posRect.top,
753 NULL,
754 NULL,
755 NULL,
756 NULL);
757
759
761
764
765 return 0;
766 }
767
769 {
770 CTrayWindow *This = (CTrayWindow*) pParam;
771
772 return This->TrayPropertiesThread();
773 }
774
776 {
777 HWND hTrayProp;
778
780 {
782 if (hTrayProp != NULL &&
783 hTrayProp != m_TrayPropertiesOwner)
784 {
785 SetForegroundWindow(hTrayProp);
786 return NULL;
787 }
788 }
789
791 return NULL;
792 }
793
795 {
796 WCHAR szDir[MAX_PATH];
797
798 if (SHGetSpecialFolderPath(hWndOwner,
799 szDir,
801 FALSE))
802 {
803 ShellExecute(hWndOwner,
804 lpOperation,
805 szDir,
806 NULL,
807 NULL,
809 }
810 }
811
813 {
814 ShellExecute(hWndOwner,
815 TEXT("open"),
816 TEXT("taskmgr.exe"),
817 NULL,
818 NULL,
820 }
821
823 {
825 {
826 ShowDesktop();
827 }
828 else
829 {
830 RestoreAll();
831 }
832 }
833
835 {
836 switch (uiCmd)
837 {
840 break;
841
844 TEXT("open"));
845 break;
846
849 TEXT("explore"));
850 break;
851
852 case ID_LOCKTASKBAR:
854 break;
855
858 break;
859
862 break;
863
865 ShowDesktop();
866 break;
867
870 if (g_Arrangement == NONE)
871 {
873 }
877 break;
878
881 if (g_Arrangement == NONE)
882 {
884 }
888 break;
889
892 if (g_Arrangement == NONE)
893 {
895 }
899 break;
900
903 break;
904
906 //FIXME: Use SHRunControlPanel
907 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
908 break;
909
911 RestoreAll();
912 break;
913
914 default:
915 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
916 return FALSE;
917 }
918
919 return TRUE;
920 }
921
923 {
924 m_StartMenuPopup->OnSelect(MPOS_CANCELLEVEL);
925 }
926
928 {
929 switch (id)
930 {
931 case IDHK_RUN:
934 break;
935 case IDHK_HELP:
937 break;
938 case IDHK_EXPLORE:
939 //FIXME: We don't support this yet:
940 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1);
941 ShellExecuteW(0, NULL, L"explorer.exe", L"/e ,", NULL, 1);
942 break;
943 case IDHK_FIND:
945 break;
948 break;
950 //FIXME: Use SHRunControlPanel
951 ShellExecuteW(m_hWnd, NULL, L"sysdm.cpl", NULL, NULL, SW_NORMAL);
952 break;
953 case IDHK_NEXT_TASK:
954 break;
955 case IDHK_PREV_TASK:
956 break;
958 MinimizeAll();
959 break;
960 case IDHK_RESTORE_ALL:
961 RestoreAll();
962 break;
963 case IDHK_DESKTOP:
965 break;
966 case IDHK_PAGER:
967 break;
968 }
969
970 return 0;
971 }
972
974 {
975 switch (uCommand)
976 {
978 // TODO:
979 break;
983 break;
985 LogoffWindowsDialog(m_hWnd); // FIXME: Maybe handle it in a similar way as DoExitWindows?
986 break;
987 case TRAYCMD_CASCADE:
989 break;
990 case TRAYCMD_TILE_H:
992 break;
993 case TRAYCMD_TILE_V:
995 break;
998 break;
1000 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL);
1001 break;
1004 break;
1006 MinimizeAll();
1007 break;
1009 RestoreAll();
1010 break;
1012 ShowDesktop();
1013 break;
1016 break;
1018 break;
1021 {
1024 }
1025 break;
1028 break;
1030 // TODO:
1031 break;
1033 DoExitWindows();
1034 break;
1036 // TODO:
1037 break;
1039 // TODO:
1040 break;
1042 // TODO:
1043 break;
1044 case IDM_SEARCH:
1047 break;
1050 break;
1051
1052 default:
1053 break;
1054 }
1055
1056 return FALSE;
1057 }
1058
1059
1061 IN HMENU hMenu,
1062 IN POINT *ppt OPTIONAL,
1063 IN HWND hwndExclude OPTIONAL,
1064 IN BOOL TrackUp,
1065 IN BOOL IsContextMenu)
1066 {
1067 TPMPARAMS tmp, *ptmp = NULL;
1068 POINT pt;
1069 UINT cmdId;
1070 UINT fuFlags;
1071
1072 if (hwndExclude != NULL)
1073 {
1074 /* Get the client rectangle and map it to screen coordinates */
1075 if (::GetClientRect(hwndExclude,
1076 &tmp.rcExclude) &&
1077 ::MapWindowPoints(hwndExclude,
1078 NULL,
1079 (LPPOINT) &tmp.rcExclude,
1080 2) != 0)
1081 {
1082 ptmp = &tmp;
1083 }
1084 }
1085
1086 if (ppt == NULL)
1087 {
1088 if (ptmp == NULL &&
1089 GetClientRect(&tmp.rcExclude) &&
1091 NULL,
1092 (LPPOINT) &tmp.rcExclude,
1093 2) != 0)
1094 {
1095 ptmp = &tmp;
1096 }
1097
1098 if (ptmp != NULL)
1099 {
1100 /* NOTE: TrackPopupMenuEx will eventually align the track position
1101 for us, no need to take care of it here as long as the
1102 coordinates are somewhere within the exclusion rectangle */
1103 pt.x = ptmp->rcExclude.left;
1104 pt.y = ptmp->rcExclude.top;
1105 }
1106 else
1107 pt.x = pt.y = 0;
1108 }
1109 else
1110 pt = *ppt;
1111
1112 tmp.cbSize = sizeof(tmp);
1113
1114 fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
1115 fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
1116 if (IsContextMenu)
1117 fuFlags |= TPM_RIGHTBUTTON;
1118 else
1119 fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
1120
1121 cmdId = TrackPopupMenuEx(hMenu,
1122 fuFlags,
1123 pt.x,
1124 pt.y,
1125 m_hWnd,
1126 ptmp);
1127
1128 return cmdId;
1129 }
1130
1132 IN IContextMenu * contextMenu,
1133 IN POINT *ppt OPTIONAL,
1134 IN HWND hwndExclude OPTIONAL,
1135 IN BOOL TrackUp,
1137 {
1138 POINT pt;
1140 RECT rc;
1141 HRESULT hr;
1142 UINT uCommand;
1143 HMENU popup = CreatePopupMenu();
1144
1145 if (popup == NULL)
1146 return E_FAIL;
1147
1148 if (ppt)
1149 {
1150 pt = *ppt;
1151 }
1152 else
1153 {
1154 ::GetWindowRect(m_hWnd, &rc);
1155 pt.x = rc.left;
1156 pt.y = rc.top;
1157 }
1158
1159 TRACE("Before Query\n");
1160 hr = contextMenu->QueryContextMenu(popup, 0, 0, UINT_MAX, CMF_NORMAL);
1162 {
1163 TRACE("Query failed\n");
1164 DestroyMenu(popup);
1165 return hr;
1166 }
1167
1168 TRACE("Before Tracking\n");
1170 if (hwndExclude)
1171 {
1172 ::GetWindowRect(hwndExclude, &rc);
1173 ZeroMemory(&params, sizeof(params));
1174 params.cbSize = sizeof(params);
1175 params.rcExclude = rc;
1176 uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, pt.x, pt.y, m_hWnd, &params);
1177 }
1178 else
1179 {
1180 uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, pt.x, pt.y, m_hWnd, NULL);
1181 }
1183
1184 if (uCommand != 0)
1185 {
1186 TRACE("Before InvokeCommand\n");
1187 CMINVOKECOMMANDINFO cmi = { 0 };
1188 cmi.cbSize = sizeof(cmi);
1189 cmi.lpVerb = MAKEINTRESOURCEA(uCommand);
1190 cmi.hwnd = m_hWnd;
1191 hr = contextMenu->InvokeCommand(&cmi);
1192 }
1193 else
1194 {
1195 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand, GetLastError());
1196 hr = S_FALSE;
1197 }
1198
1199 DestroyMenu(popup);
1200 return hr;
1201 }
1202
1203
1204
1205
1206
1207 /**********************************************************
1208 * ##### moving and sizing handling #####
1209 */
1210
1212 {
1213 /* There is nothing to do if themes are enabled */
1214 if (m_Theme)
1215 return;
1216
1218
1219 NONCLIENTMETRICS ncm = {sizeof(ncm)};
1220 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE))
1221 {
1222 ERR("SPI_GETNONCLIENTMETRICS failed\n");
1223 return;
1224 }
1225
1226 if (m_Font != NULL)
1228
1229 ncm.lfCaptionFont.lfWeight = FW_NORMAL;
1230 m_Font = CreateFontIndirect(&ncm.lfCaptionFont);
1231 if (!m_Font)
1232 {
1233 ERR("CreateFontIndirect failed\n");
1234 return;
1235 }
1236
1240 }
1241
1243 IN OUT RECT *pRect,
1245 {
1247 HMONITOR hMon;
1248
1249 mi.cbSize = sizeof(mi);
1250 hMon = MonitorFromRect(pRect, dwFlags);
1251 if (hMon != NULL &&
1252 GetMonitorInfo(hMon, &mi))
1253 {
1254 *pRect = mi.rcMonitor;
1255 }
1256 else
1257 {
1258 pRect->left = 0;
1259 pRect->top = 0;
1260 pRect->right = GetSystemMetrics(SM_CXSCREEN);
1261 pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
1262
1263 hMon = NULL;
1264 }
1265
1266 return hMon;
1267 }
1268
1270 IN const RECT *pRect)
1271 {
1272 HMONITOR hMon;
1273
1274 /* In case the monitor sizes or saved sizes differ a bit (probably
1275 not a lot, only so the tray window overlaps into another monitor
1276 now), minimize the risk that we determine a wrong monitor by
1277 using the center point of the tray window if we can't determine
1278 it using the rectangle. */
1279 hMon = MonitorFromRect(pRect, MONITOR_DEFAULTTONULL);
1280 if (hMon == NULL)
1281 {
1282 POINT pt;
1283
1284 pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
1285 pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
1286
1287 /* be less error-prone, find the nearest monitor */
1288 hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
1289 }
1290
1291 return hMon;
1292 }
1293
1295 IN HMONITOR hMonitor,
1296 IN OUT RECT *pRect)
1297 {
1298 HMONITOR hMon = NULL;
1299
1300 if (hMonitor != NULL)
1301 {
1303
1304 mi.cbSize = sizeof(mi);
1305 if (!GetMonitorInfo(hMonitor, &mi))
1306 {
1307 /* Hm, the monitor is gone? Try to find a monitor where it
1308 could be located now */
1309 hMon = GetMonitorFromRect(pRect);
1310 if (hMon == NULL ||
1311 !GetMonitorInfo(hMon, &mi))
1312 {
1313 hMon = NULL;
1314 goto GetPrimaryRect;
1315 }
1316 }
1317
1318 *pRect = mi.rcMonitor;
1319 }
1320 else
1321 {
1322GetPrimaryRect:
1323 pRect->left = 0;
1324 pRect->top = 0;
1325 pRect->right = GetSystemMetrics(SM_CXSCREEN);
1326 pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
1327 }
1328
1329 return hMon;
1330 }
1331
1333 {
1335 SIZE size;
1336
1337 if (pos > ABE_BOTTOM)
1338 pos = ABE_BOTTOM;
1339
1340 HRESULT hr = GetThemePartSize(m_Theme, NULL, iSizerPart[pos], 0, NULL, TS_TRUE, &size);
1342 return;
1343
1344 switch (pos)
1345 {
1346 case ABE_TOP:
1347 rc->bottom -= size.cy;
1348 break;
1349 case ABE_BOTTOM:
1350 rc->top += size.cy;
1351 break;
1352 case ABE_LEFT:
1353 rc->right -= size.cx;
1354 break;
1355 case ABE_RIGHT:
1356 rc->left += size.cx;
1357 break;
1358 }
1359 }
1360
1362 IN const SIZE *pTraySize,
1363 IN OUT RECT *pRect)
1364 {
1365 switch (Position)
1366 {
1367 case ABE_LEFT:
1368 pRect->right = pRect->left + pTraySize->cx;
1369 break;
1370
1371 case ABE_TOP:
1372 pRect->bottom = pRect->top + pTraySize->cy;
1373 break;
1374
1375 case ABE_RIGHT:
1376 pRect->left = pRect->right - pTraySize->cx;
1377 break;
1378
1379 case ABE_BOTTOM:
1380 default:
1381 pRect->top = pRect->bottom - pTraySize->cy;
1382 break;
1383 }
1384 }
1385
1387 IN const RECT *pScreen,
1388 IN const SIZE *pTraySize OPTIONAL,
1389 OUT RECT *pRect)
1390 {
1391 if (pTraySize == NULL)
1392 pTraySize = &m_TraySize;
1393
1394 *pRect = *pScreen;
1395
1396 if(!m_Theme)
1397 {
1398 /* Move the border outside of the screen */
1399 InflateRect(pRect,
1402 }
1403
1404 MakeTrayRectWithSize(Position, pTraySize, pRect);
1405 }
1406
1408 {
1409 return m_Position == ABE_TOP || m_Position == ABE_BOTTOM;
1410 }
1411
1414 IN OUT RECT *pRect)
1415 {
1416 RECT rcScreen;
1417 //BOOL Horizontal;
1418 HMONITOR hMon;
1419 SIZE szMax, szWnd;
1420
1421 //Horizontal = IsPosHorizontal();
1422
1423 szWnd.cx = pRect->right - pRect->left;
1424 szWnd.cy = pRect->bottom - pRect->top;
1425
1426 rcScreen = *pRect;
1427 hMon = GetScreenRectFromRect(
1428 &rcScreen,
1429 MONITOR_DEFAULTTONEAREST);
1430
1431 /* Calculate the maximum size of the tray window and limit the window
1432 size to half of the screen's size. */
1433 szMax.cx = (rcScreen.right - rcScreen.left) / 2;
1434 szMax.cy = (rcScreen.bottom - rcScreen.top) / 2;
1435 if (szWnd.cx > szMax.cx)
1436 szWnd.cx = szMax.cx;
1437 if (szWnd.cy > szMax.cy)
1438 szWnd.cy = szMax.cy;
1439
1440 /* FIXME - calculate */
1441
1443 &rcScreen,
1444 &szWnd,
1445 pRect);
1446
1447 return hMon;
1448 }
1449
1450#if 0
1451 VOID
1452 GetMinimumWindowSize(
1453 OUT RECT *pRect)
1454 {
1455 RECT rcMin = {0};
1456
1457 AdjustWindowRectEx(&rcMin,
1459 GWL_STYLE),
1460 FALSE,
1462 GWL_EXSTYLE));
1463
1464 *pRect = rcMin;
1465 }
1466#endif
1467
1468
1470 IN POINT pt,
1471 OUT RECT *pRect,
1472 OUT HMONITOR *phMonitor)
1473 {
1474 HMONITOR hMon, hMonNew;
1475 DWORD PosH, PosV, Pos;
1476 SIZE DeltaPt, ScreenOffset;
1477 RECT rcScreen;
1478
1479 rcScreen.left = 0;
1480 rcScreen.top = 0;
1481
1482 /* Determine the screen rectangle */
1483 hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL);
1484 if (hMon != NULL)
1485 {
1487
1488 mi.cbSize = sizeof(mi);
1489 if (!GetMonitorInfo(hMon, &mi))
1490 {
1491 hMon = NULL;
1492 goto GetPrimaryScreenRect;
1493 }
1494
1495 /* make left top corner of the screen zero based to
1496 make calculations easier */
1497 pt.x -= mi.rcMonitor.left;
1498 pt.y -= mi.rcMonitor.top;
1499
1500 ScreenOffset.cx = mi.rcMonitor.left;
1501 ScreenOffset.cy = mi.rcMonitor.top;
1502 rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left;
1503 rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top;
1504 }
1505 else
1506 {
1507GetPrimaryScreenRect:
1508 ScreenOffset.cx = 0;
1509 ScreenOffset.cy = 0;
1512 }
1513
1514 /* Calculate the nearest screen border */
1515 if (pt.x < rcScreen.right / 2)
1516 {
1517 DeltaPt.cx = pt.x;
1518 PosH = ABE_LEFT;
1519 }
1520 else
1521 {
1522 DeltaPt.cx = rcScreen.right - pt.x;
1523 PosH = ABE_RIGHT;
1524 }
1525
1526 if (pt.y < rcScreen.bottom / 2)
1527 {
1528 DeltaPt.cy = pt.y;
1529 PosV = ABE_TOP;
1530 }
1531 else
1532 {
1533 DeltaPt.cy = rcScreen.bottom - pt.y;
1534 PosV = ABE_BOTTOM;
1535 }
1536
1537 Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
1538
1539 /* Fix the screen origin to be relative to the primary monitor again */
1540 OffsetRect(&rcScreen,
1541 ScreenOffset.cx,
1542 ScreenOffset.cy);
1543
1544 RECT rcPos = m_TrayRects[Pos];
1545
1546 hMonNew = GetMonitorFromRect(&rcPos);
1547 if (hMon != hMonNew)
1548 {
1549 SIZE szTray;
1550
1551 /* Recalculate the rectangle, we're dragging to another monitor.
1552 We don't need to recalculate the rect on single monitor systems. */
1553 szTray.cx = rcPos.right - rcPos.left;
1554 szTray.cy = rcPos.bottom - rcPos.top;
1555
1556 GetTrayRectFromScreenRect(Pos, &rcScreen, &szTray, pRect);
1557 hMon = hMonNew;
1558 }
1559 else
1560 {
1561 /* The user is dragging the tray window on the same monitor. We don't need
1562 to recalculate the rectangle */
1563 *pRect = rcPos;
1564 }
1565
1566 *phMonitor = hMon;
1567
1568 return Pos;
1569 }
1570
1572 IN OUT RECT *pRect,
1573 OUT HMONITOR *phMonitor)
1574 {
1575 POINT pt;
1576
1577 /* Calculate the center of the rectangle. We call
1578 GetDraggingRectFromPt to calculate a valid
1579 dragging rectangle */
1580 pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
1581 pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
1582
1583 return GetDraggingRectFromPt(
1584 pt,
1585 pRect,
1586 phMonitor);
1587 }
1588
1590 {
1591 RECT rcTray;
1592
1593 if (IsDragging)
1594 {
1595 rcTray.left = pwp->x;
1596 rcTray.top = pwp->y;
1597 rcTray.right = rcTray.left + pwp->cx;
1598 rcTray.bottom = rcTray.top + pwp->cy;
1599
1600 if (!EqualRect(&rcTray,
1602 {
1603 /* Recalculate the rectangle, the user dragged the tray
1604 window to another monitor or the window was somehow else
1605 moved or resized */
1607 &rcTray,
1609 //m_TrayRects[DraggingPosition] = rcTray;
1610 }
1611
1612 //Monitor = CalculateValidSize(DraggingPosition,
1613 // &rcTray);
1614
1619 IsDragging = FALSE;
1620
1621 m_TrayRects[m_Position] = rcTray;
1622 goto ChangePos;
1623 }
1624 else if (GetWindowRect(&rcTray))
1625 {
1626 if (InSizeMove)
1627 {
1628 if (!(pwp->flags & SWP_NOMOVE))
1629 {
1630 rcTray.left = pwp->x;
1631 rcTray.top = pwp->y;
1632 }
1633
1634 if (!(pwp->flags & SWP_NOSIZE))
1635 {
1636 rcTray.right = rcTray.left + pwp->cx;
1637 rcTray.bottom = rcTray.top + pwp->cy;
1638 }
1639
1641
1642 if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
1643 {
1644 SIZE szWnd;
1645
1646 szWnd.cx = pwp->cx;
1647 szWnd.cy = pwp->cy;
1648
1649 MakeTrayRectWithSize(m_Position, &szWnd, &rcTray);
1650 }
1651
1652 m_TrayRects[m_Position] = rcTray;
1653 }
1654 else if (m_Position != (DWORD)-1)
1655 {
1656 /* If the user isn't resizing the tray window we need to make sure the
1657 new size or position is valid. this is to prevent changes to the window
1658 without user interaction. */
1659 rcTray = m_TrayRects[m_Position];
1660
1662 {
1663 rcTray.left += m_AutoHideOffset.cx;
1664 rcTray.right += m_AutoHideOffset.cx;
1665 rcTray.top += m_AutoHideOffset.cy;
1666 rcTray.bottom += m_AutoHideOffset.cy;
1667 }
1668
1669 }
1670
1671ChangePos:
1672 m_TraySize.cx = rcTray.right - rcTray.left;
1673 m_TraySize.cy = rcTray.bottom - rcTray.top;
1674
1675 pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
1676 pwp->x = rcTray.left;
1677 pwp->y = rcTray.top;
1678 pwp->cx = m_TraySize.cx;
1679 pwp->cy = m_TraySize.cy;
1680 }
1681 }
1682
1684 {
1685 RECT rcClip, rcWindow;
1686 HRGN hClipRgn;
1687
1688 if (GetWindowRect(&rcWindow))
1689 {
1690 /* Disable clipping on systems with only one monitor */
1692 Clip = FALSE;
1693
1694 if (Clip)
1695 {
1696 rcClip = rcWindow;
1697
1698 GetScreenRect(m_Monitor, &rcClip);
1699
1700 if (!IntersectRect(&rcClip, &rcClip, &rcWindow))
1701 {
1702 rcClip = rcWindow;
1703 }
1704
1705 OffsetRect(&rcClip,
1706 -rcWindow.left,
1707 -rcWindow.top);
1708
1709 hClipRgn = CreateRectRgnIndirect(&rcClip);
1710 }
1711 else
1712 hClipRgn = NULL;
1713
1714 /* Set the clipping region or make sure the window isn't clipped
1715 by disabling it explicitly. */
1716 SetWindowRgn(hClipRgn, TRUE);
1717 }
1718 }
1719
1721 {
1722#if !WIN7_DEBUG_MODE
1723 RECT rcTray, rcWorkArea;
1724
1725 /* If monitor has changed then fix the previous monitors work area */
1727 {
1728 GetScreenRect(m_PreviousMonitor, &rcWorkArea);
1729 SystemParametersInfoW(SPI_SETWORKAREA,
1730 1,
1731 &rcWorkArea,
1733 }
1734
1735 rcTray = m_TrayRects[m_Position];
1736
1737 GetScreenRect(m_Monitor, &rcWorkArea);
1739
1740 /* If AutoHide is false then change the workarea to exclude
1741 the area that the taskbar covers. */
1743 {
1744 switch (m_Position)
1745 {
1746 case ABE_TOP:
1747 rcWorkArea.top = rcTray.bottom;
1748 break;
1749 case ABE_LEFT:
1750 rcWorkArea.left = rcTray.right;
1751 break;
1752 case ABE_RIGHT:
1753 rcWorkArea.right = rcTray.left;
1754 break;
1755 case ABE_BOTTOM:
1756 rcWorkArea.bottom = rcTray.top;
1757 break;
1758 }
1759 }
1760
1761 /*
1762 * Resize the current monitor work area. Win32k will also send
1763 * a WM_SIZE message to automatically resize the desktop.
1764 */
1765 SystemParametersInfoW(SPI_SETWORKAREA,
1766 1,
1767 &rcWorkArea,
1769#endif
1770 }
1771
1773 {
1774 /* Force the rebar bands to resize */
1776 IID_IDeskBand,
1778 0,
1779 NULL,
1780 NULL);
1781
1782 /* Calculate the size of the taskbar based on the rebar */
1784
1785 /* Move the tray window */
1786 /* The handler of WM_WINDOWPOSCHANGING will override whatever size
1787 * and position we use here with m_TrayRects */
1791 }
1792
1794 {
1795 DWORD Pos;
1796 RECT rcScreen;
1797 SIZE WndSize, EdgeSize, DlgFrameSize;
1798 SIZE StartBtnSize = m_StartButton.GetSize();
1799
1800 EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
1801 EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
1802 DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
1803 DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
1804
1806 rcScreen = g_TaskbarSettings.sr.Rect;
1807 GetScreenRectFromRect(&rcScreen, MONITOR_DEFAULTTONEAREST);
1808
1810 {
1811 /* Use the minimum size of the taskbar, we'll use the start
1812 button as a minimum for now. Make sure we calculate the
1813 entire window size, not just the client size. However, we
1814 use a thinner border than a standard thick border, so that
1815 the start button and bands are not stuck to the screen border. */
1816 if(!m_Theme)
1817 {
1818 g_TaskbarSettings.sr.Size.cx = StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
1819 g_TaskbarSettings.sr.Size.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
1820 }
1821 else
1822 {
1823 g_TaskbarSettings.sr.Size.cx = StartBtnSize.cx - EdgeSize.cx;
1824 g_TaskbarSettings.sr.Size.cy = StartBtnSize.cy - EdgeSize.cy;
1827 }
1828 }
1829 /* Determine a minimum tray window rectangle. The "client" height is
1830 zero here since we cannot determine an optimal minimum width when
1831 loaded as a vertical tray window. We just need to make sure the values
1832 loaded from the registry are at least. The windows explorer behaves
1833 the same way, it allows the user to save a zero width vertical tray
1834 window, but not a zero height horizontal tray window. */
1835 if(!m_Theme)
1836 {
1837 WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
1838 WndSize.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
1839 }
1840 else
1841 {
1842 WndSize.cx = StartBtnSize.cx;
1843 WndSize.cy = StartBtnSize.cy - EdgeSize.cy;
1844 }
1845
1846 if (WndSize.cx < g_TaskbarSettings.sr.Size.cx)
1847 WndSize.cx = g_TaskbarSettings.sr.Size.cx;
1848 if (WndSize.cy < g_TaskbarSettings.sr.Size.cy)
1849 WndSize.cy = g_TaskbarSettings.sr.Size.cy;
1850
1851 /* Save the calculated size */
1852 m_TraySize = WndSize;
1853
1854 /* Calculate all docking rectangles. We need to do this here so they're
1855 initialized and dragging the tray window to another position gives
1856 usable results */
1857 for (Pos = ABE_LEFT; Pos <= ABE_BOTTOM; Pos++)
1858 {
1860 &rcScreen,
1861 &m_TraySize,
1862 &m_TrayRects[Pos]);
1863 // 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);
1864 }
1865
1866 /* Determine which monitor we are on. It shouldn't matter which docked
1867 position rectangle we use */
1869 }
1870
1872 {
1873 RECT rcClient;
1874 SIZE TraySize, StartSize;
1875 POINT ptTrayNotify = { 0, 0 };
1876 BOOL Horizontal;
1877 HDWP dwp;
1878
1880 if (prcClient != NULL)
1881 {
1882 rcClient = *prcClient;
1883 }
1884 else
1885 {
1886 if (!GetClientRect(&rcClient))
1887 {
1888 ERR("Could not get client rect lastErr=%d\n", GetLastError());
1889 return;
1890 }
1891 }
1892
1893 Horizontal = IsPosHorizontal();
1894
1895 /* We're about to resize/move the start button, the rebar control and
1896 the tray notification control */
1897 dwp = BeginDeferWindowPos(4);
1898 if (dwp == NULL)
1899 {
1900 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError());
1901 return;
1902 }
1903
1904 /* Limit the Start button width to the client width, if necessary */
1905 StartSize = m_StartButton.GetSize();
1906 if (StartSize.cx > rcClient.right)
1907 StartSize.cx = rcClient.right;
1908
1909 HWND hwndTaskToolbar = ::GetWindow(m_TaskSwitch, GW_CHILD);
1910 if (hwndTaskToolbar)
1911 {
1912 DWORD size = SendMessageW(hwndTaskToolbar, TB_GETBUTTONSIZE, 0, 0);
1913
1914 /* Themed button covers Edge area as well */
1915 StartSize.cy = HIWORD(size) + (m_Theme ? GetSystemMetrics(SM_CYEDGE) : 0);
1916 }
1917
1918 if (m_StartButton.m_hWnd != NULL)
1919 {
1920 /* Resize and reposition the button */
1921 dwp = m_StartButton.DeferWindowPos(dwp,
1922 NULL,
1923 0,
1924 0,
1925 StartSize.cx,
1926 StartSize.cy,
1928 if (dwp == NULL)
1929 {
1930 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError());
1931 return;
1932 }
1933 }
1934
1936 {
1937 // Get rectangle from rcClient
1938 RECT rc = rcClient;
1939 INT cxyShowDesktop = m_ShowDesktopButton.WidthOrHeight();
1940 if (Horizontal)
1941 {
1942 rc.left = rc.right - cxyShowDesktop;
1943 rc.right += 5; // excessive
1944 }
1945 else
1946 {
1947 rc.top = rc.bottom - cxyShowDesktop;
1948 rc.bottom += 5; // excessive
1949 }
1950
1951 /* Resize and reposition the button */
1953 rc.left, rc.top,
1954 rc.right - rc.left, rc.bottom - rc.top,
1956
1957 // Adjust rcClient
1958 if (Horizontal)
1959 rcClient.right -= cxyShowDesktop + ::GetSystemMetrics(SM_CXEDGE);
1960 else
1961 rcClient.bottom -= cxyShowDesktop + ::GetSystemMetrics(SM_CYEDGE);
1962 }
1963
1964 /* Determine the size that the tray notification window needs */
1965 if (Horizontal)
1966 {
1967 TraySize.cx = 0;
1968 TraySize.cy = rcClient.bottom;
1969 }
1970 else
1971 {
1972 TraySize.cx = rcClient.right;
1973 TraySize.cy = 0;
1974 }
1975
1976 if (m_TrayNotify != NULL &&
1979 (WPARAM)Horizontal,
1980 (LPARAM)&TraySize))
1981 {
1982 /* Move the tray notification window to the desired location */
1983 if (Horizontal)
1984 ptTrayNotify.x = rcClient.right - TraySize.cx;
1985 else
1986 ptTrayNotify.y = rcClient.bottom - TraySize.cy;
1987
1988 dwp = ::DeferWindowPos(dwp,
1990 NULL,
1991 ptTrayNotify.x,
1992 ptTrayNotify.y,
1993 TraySize.cx,
1994 TraySize.cy,
1996 if (dwp == NULL)
1997 {
1998 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError());
1999 return;
2000 }
2001 }
2002
2003 /* Resize/Move the rebar control */
2004 if (m_Rebar != NULL)
2005 {
2006 POINT ptRebar = { 0, 0 };
2007 SIZE szRebar;
2008
2009 SetWindowStyle(m_Rebar, CCS_VERT, Horizontal ? 0 : CCS_VERT);
2010
2011 if (Horizontal)
2012 {
2013 ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME);
2014 szRebar.cx = ptTrayNotify.x - ptRebar.x;
2015 szRebar.cy = rcClient.bottom;
2016 }
2017 else
2018 {
2019 ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME);
2020 szRebar.cx = rcClient.right;
2021 szRebar.cy = ptTrayNotify.y - ptRebar.y;
2022 }
2023
2024 dwp = ::DeferWindowPos(dwp,
2025 m_Rebar,
2026 NULL,
2027 ptRebar.x,
2028 ptRebar.y,
2029 szRebar.cx,
2030 szRebar.cy,
2032 }
2033
2034 if (dwp != NULL)
2035 EndDeferWindowPos(dwp);
2036
2037 if (m_TaskSwitch != NULL)
2038 {
2039 /* Update the task switch window configuration */
2041 }
2042 }
2043
2044 void FitToRebar(PRECT pRect)
2045 {
2046 /* Get the rect of the rebar */
2047 RECT rebarRect, taskbarRect, clientRect;
2048 ::GetWindowRect(m_Rebar, &rebarRect);
2049 ::GetWindowRect(m_hWnd, &taskbarRect);
2050 ::GetClientRect(m_hWnd, &clientRect);
2051 OffsetRect(&rebarRect, -taskbarRect.left, -taskbarRect.top);
2052
2053 /* Calculate the difference of size of the taskbar and the rebar */
2054 SIZE margins;
2055 margins.cx = taskbarRect.right - taskbarRect.left - clientRect.right + clientRect.left;
2056 margins.cy = taskbarRect.bottom - taskbarRect.top - clientRect.bottom + clientRect.top;
2057
2058 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */
2059 switch (m_Position)
2060 {
2061 case ABE_TOP:
2062 rebarRect.bottom = rebarRect.top + pRect->bottom - pRect->top - margins.cy;
2064 pRect->bottom = pRect->top + rebarRect.bottom - rebarRect.top + margins.cy;
2065 break;
2066 case ABE_BOTTOM:
2067 rebarRect.top = rebarRect.bottom - (pRect->bottom - pRect->top - margins.cy);
2069 pRect->top = pRect->bottom - (rebarRect.bottom - rebarRect.top + margins.cy);
2070 break;
2071 case ABE_LEFT:
2072 rebarRect.right = rebarRect.left + (pRect->right - pRect->left - margins.cx);
2074 pRect->right = pRect->left + (rebarRect.right - rebarRect.left + margins.cx);
2075 break;
2076 case ABE_RIGHT:
2077 rebarRect.left = rebarRect.right - (pRect->right - pRect->left - margins.cx);
2079 pRect->left = pRect->right - (rebarRect.right - rebarRect.left + margins.cx);
2080 break;
2081 }
2082
2084 }
2085
2087 {
2088 if (m_StartMenuPopup != NULL)
2089 {
2090 POINTL pt;
2091 RECTL rcExclude;
2092 DWORD dwFlags = 0;
2093
2094 if (m_StartButton.GetWindowRect((RECT*) &rcExclude))
2095 {
2096 switch (m_Position)
2097 {
2098 case ABE_BOTTOM:
2099 pt.x = rcExclude.left;
2100 pt.y = rcExclude.top;
2101 dwFlags |= MPPF_TOP;
2102 break;
2103 case ABE_TOP:
2104 pt.x = rcExclude.left;
2105 pt.y = rcExclude.bottom;
2106 dwFlags |= MPPF_BOTTOM;
2107 break;
2108 case ABE_LEFT:
2109 pt.x = rcExclude.right;
2110 pt.y = rcExclude.top;
2111 dwFlags |= MPPF_RIGHT;
2112 break;
2113 case ABE_RIGHT:
2114 pt.x = rcExclude.left;
2115 pt.y = rcExclude.top;
2116 dwFlags |= MPPF_LEFT;
2117 break;
2118 }
2119
2120 m_StartMenuPopup->Popup(&pt, &rcExclude, dwFlags);
2121
2122 m_StartButton.SendMessageW(BM_SETSTATE, TRUE, 0);
2123 }
2124 }
2125 }
2126
2128 {
2129 RECT rcCurrent;
2130 POINT pt;
2131 BOOL over;
2133
2134 GetCursorPos(&pt);
2135 GetWindowRect(&rcCurrent);
2136 over = PtInRect(&rcCurrent, pt);
2137
2139 {
2140 over = TRUE;
2141 }
2142
2143 if (over)
2144 {
2145 if (state == AUTOHIDE_HIDING)
2146 {
2147 TRACE("AutoHide cancelling hide.\n");
2150 }
2151 else if (state == AUTOHIDE_HIDDEN)
2152 {
2153 TRACE("AutoHide starting show.\n");
2156 }
2157 }
2158 else
2159 {
2160 if (state == AUTOHIDE_SHOWING)
2161 {
2162 TRACE("AutoHide cancelling show.\n");
2165 }
2166 else if (state == AUTOHIDE_SHOWN)
2167 {
2168 TRACE("AutoHide starting hide.\n");
2171 }
2172
2174 }
2175 }
2176
2178 {
2181
2182 switch (m_AutoHideState)
2183 {
2184 case AUTOHIDE_HIDING:
2185 switch (m_Position)
2186 {
2187 case ABE_LEFT:
2188 m_AutoHideOffset.cy = 0;
2190 if (m_AutoHideOffset.cx < -w)
2192 break;
2193 case ABE_TOP:
2194 m_AutoHideOffset.cx = 0;
2196 if (m_AutoHideOffset.cy < -h)
2198 break;
2199 case ABE_RIGHT:
2200 m_AutoHideOffset.cy = 0;
2202 if (m_AutoHideOffset.cx > w)
2204 break;
2205 case ABE_BOTTOM:
2206 m_AutoHideOffset.cx = 0;
2208 if (m_AutoHideOffset.cy > h)
2210 break;
2211 }
2212
2214 {
2216 break;
2217 }
2218
2219 /* fallthrough */
2220 case AUTOHIDE_HIDDEN:
2221
2222 switch (m_Position)
2223 {
2224 case ABE_LEFT:
2226 m_AutoHideOffset.cy = 0;
2227 break;
2228 case ABE_TOP:
2229 m_AutoHideOffset.cx = 0;
2231 break;
2232 case ABE_RIGHT:
2234 m_AutoHideOffset.cy = 0;
2235 break;
2236 case ABE_BOTTOM:
2237 m_AutoHideOffset.cx = 0;
2239 break;
2240 }
2241
2244 break;
2245
2246 case AUTOHIDE_SHOWING:
2248 {
2250 }
2252 {
2254 }
2255 else
2256 {
2257 m_AutoHideOffset.cx = 0;
2258 }
2259
2261 {
2263 }
2265 {
2267 }
2268 else
2269 {
2270 m_AutoHideOffset.cy = 0;
2271 }
2272
2273 if (m_AutoHideOffset.cx != 0 || m_AutoHideOffset.cy != 0)
2274 {
2276 break;
2277 }
2278
2279 /* fallthrough */
2280 case AUTOHIDE_SHOWN:
2281
2284 break;
2285 }
2286
2288 }
2289
2290
2291
2292
2293
2294 /**********************************************************
2295 * ##### taskbar drawing #####
2296 */
2297
2299 {
2300 RECT rect;
2302
2304
2305 if (m_Theme)
2306 {
2308 DrawThemeBackground(m_Theme, hdc, iSBkgndPart[m_Position], 0, &rect, 0);
2309 }
2310
2311 return 0;
2312 }
2313
2315 {
2316 HDC hdc;
2317 RECT rect;
2319 SIZE size;
2320
2322
2325 return 0;
2326
2328 OffsetRect(&rect, -rect.left, -rect.top);
2329
2330 hdc = GetWindowDC();
2331
2332 switch (m_Position)
2333 {
2334 case ABE_LEFT:
2335 rect.left = rect.right - size.cx;
2336 break;
2337 case ABE_TOP:
2338 rect.top = rect.bottom - size.cy;
2339 break;
2340 case ABE_RIGHT:
2341 rect.right = rect.left + size.cx;
2342 break;
2343 case ABE_BOTTOM:
2344 default:
2345 rect.bottom = rect.top + size.cy;
2346 break;
2347 }
2348
2349 DrawThemeBackground(m_Theme, hdc, iSizerPart[m_Position], 0, &rect, 0);
2350
2351 ReleaseDC(hdc);
2352 return 0;
2353 }
2354
2355
2356
2357
2358
2359 /*
2360 * ITrayWindow
2361 */
2363 {
2364 RECT rcWnd;
2365
2366 /* Check if there's already a window created and try to show it.
2367 If it was somehow destroyed just create a new tray window. */
2368 if (m_hWnd != NULL && IsWindow())
2369 {
2370 return S_OK;
2371 }
2372
2375 dwExStyle |= WS_EX_TOPMOST;
2376
2378 if(!m_Theme)
2379 {
2380 dwStyle |= WS_THICKFRAME | WS_BORDER;
2381 }
2382
2383 ZeroMemory(&rcWnd, sizeof(rcWnd));
2384 if (m_Position != (DWORD) -1)
2385 rcWnd = m_TrayRects[m_Position];
2386
2387 if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle))
2388 return E_FAIL;
2389
2390 /* Align all controls on the tray window */
2392
2393 /* Move the tray window to the right position and resize it if necessary */
2395
2396 return S_OK;
2397 }
2398
2400 {
2401 if (m_hWnd != NULL)
2402 {
2405 0,
2406 0);
2407 }
2408
2409 return S_OK;
2410 }
2411
2413 {
2414 return m_hWnd;
2415 }
2416
2418 {
2419 return (m_hWnd == hWnd ||
2421 }
2422
2424 {
2425 return IsPosHorizontal();
2426 }
2427
2429 {
2430 BOOL bPrevLock = g_TaskbarSettings.bLock;
2431
2432 if (g_TaskbarSettings.bLock != bLock)
2433 {
2434 g_TaskbarSettings.bLock = bLock;
2435
2436 if (m_TrayBandSite != NULL)
2437 {
2438 if (!SUCCEEDED(m_TrayBandSite->Lock(bLock)))
2439 {
2440 /* Reset?? */
2441 g_TaskbarSettings.bLock = bPrevLock;
2442 return bPrevLock;
2443 }
2444 }
2445
2446 if (m_Theme)
2447 {
2448 /* Update cached tray sizes */
2449 for(DWORD Pos = ABE_LEFT; Pos <= ABE_BOTTOM; Pos++)
2450 {
2451 RECT rcGripper = {0};
2452 AdjustSizerRect(&rcGripper, Pos);
2453
2455 {
2456 m_TrayRects[Pos].top += rcGripper.top;
2457 m_TrayRects[Pos].left += rcGripper.left;
2458 m_TrayRects[Pos].bottom += rcGripper.bottom;
2459 m_TrayRects[Pos].right += rcGripper.right;
2460 }
2461 else
2462 {
2463 m_TrayRects[Pos].top -= rcGripper.top;
2464 m_TrayRects[Pos].left -= rcGripper.left;
2465 m_TrayRects[Pos].bottom -= rcGripper.bottom;
2466 m_TrayRects[Pos].right -= rcGripper.right;
2467 }
2468 }
2469 }
2473 }
2474
2475 return bPrevLock;
2476 }
2477
2478 /* The task window is visible and non-WS_EX_TOOLWINDOW and
2479 { has WS_EX_APPWINDOW style or has no owner } and is none of explorer's
2480 special windows (such as the desktop or the tray window) */
2482 {
2484 {
2486 if (((exStyle & WS_EX_APPWINDOW) || ::GetWindow(hWnd, GW_OWNER) == NULL) &&
2487 !(exStyle & WS_EX_TOOLWINDOW))
2488 {
2489 return TRUE;
2490 }
2491 }
2492 return FALSE;
2493 }
2494
2495 /*
2496 * IContextMenu
2497 */
2499 UINT indexMenu,
2500 UINT idCmdFirst,
2501 UINT idCmdLast,
2502 UINT uFlags)
2503 {
2504 if (!m_ContextMenu)
2505 {
2508 return hr;
2509 }
2510
2511 return m_ContextMenu->QueryContextMenu(hPopup, indexMenu, idCmdFirst, idCmdLast, uFlags);
2512 }
2513
2515 {
2516 if (!m_ContextMenu)
2517 return E_INVALIDARG;
2518
2519 return m_ContextMenu->InvokeCommand(lpici);
2520 }
2521
2523 UINT uType,
2524 UINT *pwReserved,
2525 LPSTR pszName,
2526 UINT cchMax)
2527 {
2528 if (!m_ContextMenu)
2529 return E_INVALIDARG;
2530
2531 return m_ContextMenu->GetCommandString(idCmd, uType, pwReserved, pszName, cchMax);
2532 }
2533
2534 /**********************************************************
2535 * ##### message handling #####
2536 */
2537
2539 {
2540 HRESULT hRet;
2541
2542 ((ITrayWindow*)this)->AddRef();
2543
2544 SetWindowTheme(m_hWnd, L"TaskBar", NULL);
2545
2546 /* Create the Start button */
2548
2549 /* Create the 'Show Desktop' button if necessary */
2552
2553 /* Load the saved tray window settings */
2555
2556 /* Create and initialize the start menu */
2558 m_StartMenuPopup = CreateStartMenu(this, &m_StartMenuBand, hbmBanner, 0);
2559
2560 /* Create the task band */
2562 if (FAILED_UNEXPECTEDLY(hRet))
2563 return FALSE;
2564
2565 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2567 if (FAILED_UNEXPECTEDLY(hRet))
2568 return FALSE;
2569
2570 /* Create the tray notification window */
2572 if (FAILED_UNEXPECTEDLY(hRet))
2573 return FALSE;
2574
2575 /* Get the hwnd of the rebar */
2577 if (FAILED_UNEXPECTEDLY(hRet))
2578 return FALSE;
2579
2580 /* Get the hwnd of the tasks toolbar */
2582 if (FAILED_UNEXPECTEDLY(hRet))
2583 return FALSE;
2584
2585 /* Get the hwnd of the tray notification window */
2587 if (FAILED_UNEXPECTEDLY(hRet))
2588 return FALSE;
2589
2590 SetWindowTheme(m_Rebar, L"TaskBar", NULL);
2591
2592 UpdateFonts();
2593
2595
2597 {
2600 }
2601
2602 /* Set the initial lock state in the band site */
2604
2617
2618 return TRUE;
2619 }
2620
2621#define TIMER_ID_IGNOREPULSERESET 888
2622#define TIMER_IGNOREPULSERESET_TIMEOUT 200
2623
2625 {
2627 return 0;
2628 }
2629
2631 {
2632 if (m_Theme)
2634
2635 m_Theme = OpenThemeData(m_hWnd, L"TaskBar");
2636
2637 if (m_Theme)
2638 {
2640 }
2641 else
2642 {
2644 }
2646
2647 return TRUE;
2648 }
2649
2651 {
2652 if (wParam == SPI_SETNONCLIENTMETRICS)
2653 {
2656 UpdateFonts();
2659 }
2660
2661 return 0;
2662 }
2663
2665 {
2666 HDC hdc = (HDC) wParam;
2667
2668 if (!m_Theme)
2669 {
2670 bHandled = FALSE;
2671 return 0;
2672 }
2673
2675 }
2676
2678 {
2679 /* Load the saved tray window settings */
2681
2682 /* Move the tray window to the right position and resize it if necessary */
2684
2685 return TRUE;
2686 }
2687
2689 {
2690 COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT *)lParam;
2691 switch (pCopyData->dwData)
2692 {
2693 case TABDMC_APPBAR:
2694 return appbar_message(pCopyData);
2695 case TABDMC_NOTIFY:
2696 case TABDMC_LOADINPROC:
2697 return ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam);
2698 }
2699 return FALSE;
2700 }
2701
2702 // We have to draw non-client area because the 'Show Desktop' button is beyond client area.
2704 {
2706 return;
2707 // Get the rectangle in window coordinates
2708 RECT rcButton, rcWnd;
2709 GetWindowRect(&rcWnd);
2711 ::OffsetRect(&rcButton, -rcWnd.left, -rcWnd.top);
2712
2714 m_ShowDesktopButton.OnDraw(hdc, &rcButton); // Draw the button
2715 ReleaseDC(hdc);
2716 }
2717
2719 {
2720 DefWindowProc(uMsg, wParam, lParam);
2721 bHandled = TRUE;
2722
2724 {
2725 DrawShowDesktopButton(); // We have to draw non-client area
2726 return 0;
2727 }
2728
2729 DrawSizerWithTheme((HRGN) wParam);
2730 DrawShowDesktopButton(); // We have to draw non-client area
2731 return 0;
2732 }
2733
2735 {
2738 }
2739
2741 {
2742 RECT rcClient;
2743 POINT pt;
2744
2746 {
2747 /* The user may not be able to resize the tray window.
2748 Pretend like the window is not sizeable when the user
2749 clicks on the border. */
2750 return HTBORDER;
2751 }
2752
2754 if (GetClientRect(&rcClient) &&
2755 (MapWindowPoints(NULL, (LPPOINT) &rcClient, 2) != 0 || GetLastError() == ERROR_SUCCESS))
2756 {
2757 pt.x = (SHORT) LOWORD(lParam);
2758 pt.y = (SHORT) HIWORD(lParam);
2759
2760 if (PtInRect(&rcClient, pt))
2761 {
2762 /* The user is trying to drag the tray window */
2763 return HTCAPTION;
2764 }
2765
2766 /* Depending on the position of the tray window, allow only
2767 changing the border next to the monitor working area */
2768 switch (m_Position)
2769 {
2770 case ABE_TOP:
2771 if (pt.y > rcClient.bottom)
2772 return HTBOTTOM;
2773 break;
2774 case ABE_LEFT:
2775 if (pt.x > rcClient.right)
2776 return HTRIGHT;
2777 break;
2778 case ABE_RIGHT:
2779 if (pt.x < rcClient.left)
2780 return HTLEFT;
2781 break;
2782 case ABE_BOTTOM:
2783 default:
2784 if (pt.y < rcClient.top)
2785 return HTTOP;
2786 break;
2787 }
2788 }
2789 return HTBORDER;
2790 }
2791
2793 {
2794 POINT ptCursor;
2795 PRECT pRect = (PRECT) lParam;
2796
2797 /* We need to ensure that an application can not accidently
2798 move the tray window (using SetWindowPos). However, we still
2799 need to be able to move the window in case the user wants to
2800 drag the tray window to another position or in case the user
2801 wants to resize the tray window. */
2802 if (!g_TaskbarSettings.bLock && GetCursorPos(&ptCursor))
2803 {
2804 IsDragging = TRUE;
2806 }
2807 else
2808 {
2809 *pRect = m_TrayRects[m_Position];
2810 }
2811 return TRUE;
2812 }
2813
2815 {
2816 PRECT pRect = (PRECT) lParam;
2817
2819 {
2820 FitToRebar(pRect);
2821 }
2822 else
2823 {
2824 *pRect = m_TrayRects[m_Position];
2825 }
2826 return TRUE;
2827 }
2828
2830 {
2832 return TRUE;
2833 }
2834
2836 {
2837 RECT rcClient;
2838 if (wParam == SIZE_RESTORED && lParam == 0)
2839 {
2841 /* Clip the tray window on multi monitor systems so the edges can't
2842 overlap into another monitor */
2844
2845 if (!GetClientRect(&rcClient))
2846 {
2847 return FALSE;
2848 }
2849 }
2850 else
2851 {
2852 rcClient.left = rcClient.top = 0;
2853 rcClient.right = LOWORD(lParam);
2854 rcClient.bottom = HIWORD(lParam);
2855 }
2856
2857 AlignControls(&rcClient);
2858 return TRUE;
2859 }
2860
2862 {
2863 InSizeMove = TRUE;
2864 IsDragging = FALSE;
2866 {
2867 /* Remove the clipping on multi monitor systems while dragging around */
2869 }
2870 return TRUE;
2871 }
2872
2874 {
2875 InSizeMove = FALSE;
2877 {
2879
2880 /* Apply clipping */
2882 }
2883 return TRUE;
2884 }
2885
2887 {
2888 switch (wParam)
2889 {
2890 case TEXT(' '):
2891 {
2892 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2893 The tray window needs to handle this specially, since it normally doesn't have
2894 a system menu. */
2895
2896 static const UINT uidDisableItem [] = {
2897 SC_RESTORE,
2898 SC_MOVE,
2899 SC_SIZE,
2902 };
2903 HMENU hSysMenu;
2904 UINT i, uId;
2905
2906 /* temporarily enable the system menu */
2908
2909 hSysMenu = GetSystemMenu(FALSE);
2910 if (hSysMenu != NULL)
2911 {
2912 /* Disable all items that are not relevant */
2913 for (i = 0; i < _countof(uidDisableItem); i++)
2914 {
2915 EnableMenuItem(hSysMenu,
2916 uidDisableItem[i],
2918 }
2919
2920 EnableMenuItem(hSysMenu,
2921 SC_CLOSE,
2922 MF_BYCOMMAND |
2924
2925 /* Display the system menu */
2926 uId = TrackMenu(
2927 hSysMenu,
2928 NULL,
2931 FALSE);
2932 if (uId != 0)
2933 {
2935 }
2936 }
2937
2938 /* revert the system menu window style */
2940 break;
2941 }
2942
2943 default:
2944 bHandled = FALSE;
2945 }
2946 return TRUE;
2947 }
2948
2950 {
2951 /* This handler implements the trick that makes the start button to
2952 get pressed when the user clicked left or below the button */
2953
2955 WINDOWINFO wi = {sizeof(WINDOWINFO)};
2956
2957 bHandled = FALSE;
2958
2959 RECT rcStartBtn;
2960 m_StartButton.GetWindowRect(&rcStartBtn);
2961
2962 GetWindowInfo(m_hWnd, &wi);
2963
2964 switch (m_Position)
2965 {
2966 case ABE_TOP:
2967 case ABE_LEFT:
2968 {
2969 if (pt.x > rcStartBtn.right || pt.y > rcStartBtn.bottom)
2970 return 0;
2971 break;
2972 }
2973 case ABE_RIGHT:
2974 {
2975 if (pt.x < rcStartBtn.left || pt.y > rcStartBtn.bottom)
2976 return 0;
2977
2978 if (rcStartBtn.right + (int)wi.cxWindowBorders * 2 + 1 < wi.rcWindow.right &&
2979 pt.x > rcStartBtn.right)
2980 {
2981 return 0;
2982 }
2983 break;
2984 }
2985 case ABE_BOTTOM:
2986 {
2987 if (pt.x > rcStartBtn.right || pt.y < rcStartBtn.top)
2988 return 0;
2989
2990 if (rcStartBtn.bottom + (int)wi.cyWindowBorders * 2 + 1 < wi.rcWindow.bottom &&
2991 pt.y > rcStartBtn.bottom)
2992 {
2993 return 0;
2994 }
2995
2996 break;
2997 }
2998 }
2999
3000 bHandled = TRUE;
3002 return 0;
3003 }
3004
3006 {
3007 /* We want the user to be able to get a context menu even on the nonclient
3008 area (including the sizing border)! */
3009 uMsg = WM_CONTEXTMENU;
3010 wParam = (WPARAM) m_hWnd;
3011
3012 return OnContextMenu(uMsg, wParam, lParam, bHandled);
3013 }
3014
3016 {
3017 LRESULT Ret = FALSE;
3018 POINT pt, *ppt = NULL;
3019 HWND hWndExclude = NULL;
3020
3021 /* Check if the administrator has forbidden access to context menus */
3023 return FALSE;
3024
3025 pt.x = (SHORT) LOWORD(lParam);
3026 pt.y = (SHORT) HIWORD(lParam);
3027
3028 if (pt.x != -1 || pt.y != -1)
3029 ppt = &pt;
3030 else
3031 hWndExclude = m_StartButton.m_hWnd;
3032
3034 {
3035 /* Make sure we can't track the context menu if the start
3036 menu is currently being shown */
3038 {
3039 CComPtr<IContextMenu> ctxMenu;
3041 TrackCtxMenu(ctxMenu, ppt, hWndExclude, m_Position == ABE_BOTTOM, this);
3042 }
3043 }
3044 else
3045 {
3046 /* See if the context menu should be handled by the task band site */
3047 if (ppt != NULL && m_TrayBandSite != NULL)
3048 {
3049 HWND hWndAtPt;
3050 POINT ptClient = *ppt;
3051
3052 /* Convert the coordinates to client-coordinates */
3053 ::MapWindowPoints(NULL, m_hWnd, &ptClient, 1);
3054
3055 hWndAtPt = ChildWindowFromPoint(ptClient);
3056 if (hWndAtPt != NULL &&
3057 (hWndAtPt == m_Rebar || ::IsChild(m_Rebar, hWndAtPt)))
3058 {
3059 /* Check if the user clicked on the task switch window */
3060 ptClient = *ppt;
3061 ::MapWindowPoints(NULL, m_Rebar, &ptClient, 1);
3062
3064 if (hWndAtPt == m_TaskSwitch)
3065 goto HandleTrayContextMenu;
3066
3067 /* Forward the message to the task band site */
3068 m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
3069 }
3070 else
3071 goto HandleTrayContextMenu;
3072 }
3073 else
3074 {
3075HandleTrayContextMenu:
3076 /* Tray the default tray window context menu */
3077 TrackCtxMenu(this, ppt, NULL, FALSE, this);
3078 }
3079 }
3080 return Ret;
3081 }
3082
3084 {
3085 LRESULT Ret = FALSE;
3086 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
3087 the rebar control! But we shouldn't forward messages that the band
3088 site doesn't handle, such as other controls (start button, tray window */
3089
3090 HRESULT hr = E_FAIL;
3091
3092 if (m_TrayBandSite)
3093 {
3094 hr = m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
3095 if (SUCCEEDED(hr))
3096 return Ret;
3097 }
3098
3099 if (m_TrayBandSite == NULL || FAILED(hr))
3100 {
3101 const NMHDR *nmh = (const NMHDR *) lParam;
3102
3103 if (nmh->hwndFrom == m_TrayNotify)
3104 {
3105 switch (nmh->code)
3106 {
3107 case NTNWM_REALIGN:
3108 /* Cause all controls to be aligned */
3110 break;
3111 }
3112 }
3113 }
3114 return Ret;
3115 }
3116
3118 {
3120 if (m_ShowDesktopButton.PtInButton(pt)) // Did you click the button?
3121 {
3123 bHandled = TRUE;
3124 return TRUE;
3125 }
3126
3127 return FALSE;
3128 }
3129
3131 {
3132 /* Let the clock handle the double-click */
3134
3135 /* We "handle" this message so users can't cause a weird maximize/restore
3136 window animation when double-clicking the tray window! */
3137 return TRUE;
3138 }
3139
3141 {
3143 return FALSE;
3144 }
3145
3147 {
3148 DestroyWindow();
3149 return TRUE;
3150 }
3151
3153 {
3154 HWND hwndStartMenu;
3155 HRESULT hr = IUnknown_GetWindow(m_StartMenuPopup, &hwndStartMenu);
3157 return FALSE;
3158
3159 if (::IsWindowVisible(hwndStartMenu))
3160 HideStartMenu();
3161 else
3163
3164 return TRUE;
3165 }
3166
3168 {
3169 /*
3170 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
3171 * to show the shutdown dialog. Also a WM_CLOSE message sent
3172 * by apps should show the dialog.
3173 */
3174 return DoExitWindows();
3175 }
3176
3178 {
3179 if (wParam == SC_CLOSE)
3180 {
3181 return DoExitWindows();
3182 }
3183
3184 bHandled = FALSE;
3185 return TRUE;
3186 }
3187
3189 {
3190 bHandled = TRUE;
3191 return (LRESULT)m_TaskSwitch;
3192 }
3193
3194 void RestoreMinimizedNonTaskWnds(BOOL bDestroyed, HWND hwndActive)
3195 {
3196 for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i)
3197 {
3198 HWND hwnd = g_MinimizedAll[i].hwnd;
3199 if (!hwnd || hwndActive == hwnd)
3200 continue;
3201
3204 {
3205 ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl); // Restore
3206 }
3207 }
3208
3210
3211 if (!bDestroyed)
3212 ::SetForegroundWindow(hwndActive);
3213 }
3214
3216 {
3217 if (IgnorePulse)
3218 return 0;
3219
3221 IgnorePulse = TRUE;
3224 return 0;
3225 }
3226
3228 {
3229 return HandleHotKey(wParam);
3230 }
3231
3233 {
3239 };
3240
3242 {
3243 WCHAR szClass[32];
3244 GetClassNameW(hwnd, szClass, _countof(szClass));
3245 return wcscmp(szClass, L"#32770") == 0;
3246 }
3247
3249 {
3251 if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd || hwnd == info->hwndProgman)
3252 return TRUE; // Ignore special windows
3253
3254 if (!info->bShowDesktop)
3255 {
3257 return TRUE;
3258 HWND hwndOwner = ::GetWindow(hwnd, GW_OWNER);
3259 if (hwndOwner && !::IsWindowEnabled(hwndOwner))
3260 return TRUE;
3261 }
3262
3263 if (CanBeMinimized(hwnd))
3264 {
3265 MINWNDPOS mwp = { hwnd, { sizeof(mwp.wndpl) } };
3266 if (::GetWindowPlacement(hwnd, &mwp.wndpl) && // Save the position and status
3268 {
3269 info->pMinimizedAll->Add(mwp);
3270 }
3271 }
3272
3273 return TRUE;
3274 }
3275
3276 VOID MinimizeAll(BOOL bShowDesktop = FALSE)
3277 {
3278 IgnorePulse = TRUE;
3280
3282 info.hwndDesktop = GetDesktopWindow();;
3283 info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
3284 info.hwndProgman = FindWindowW(L"Progman", NULL);
3285 info.pMinimizedAll = &g_MinimizedAll;
3286 info.bShowDesktop = bShowDesktop;
3288
3292 }
3293
3295 {
3297 }
3298
3300 {
3301 IgnorePulse = TRUE;
3303
3304 for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i)
3305 {
3306 HWND hwnd = g_MinimizedAll[i].hwnd;
3309 }
3310
3313 }
3314
3316 {
3317 LRESULT Ret = FALSE;
3318
3320 {
3321 return FALSE;
3322 }
3323
3324 if (m_TrayBandSite == NULL || FAILED_UNEXPECTEDLY(m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret)))
3325 {
3326 return HandleCommand(LOWORD(wParam));
3327 }
3328 return Ret;
3329 }
3330
3332 {
3333 POINT pt;
3337
3339 {
3341 }
3342
3343 return TRUE;
3344 }
3345
3347 {
3349 {
3351 }
3352 else if (wParam == TIMER_ID_AUTOHIDE)
3353 {
3355 }
3357 {
3360 }
3361 return 0;
3362 }
3363
3365 {
3367 DrawShowDesktopButton(); // We have to draw non-client area
3368 bHandled = TRUE;
3369 return ret;
3370 }
3371
3373 {
3374 RECT *rc = NULL;
3375 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
3377 {
3378 bHandled = FALSE;
3379 return 0;
3380 }
3381 if(!wParam)
3382 {
3383 rc = (RECT*)wParam;
3384 }
3385 else
3386 {
3388 if(prms->lppos->flags & SWP_NOSENDCHANGING)
3389 {
3390 bHandled = FALSE;
3391 return 0;
3392 }
3393 rc = &prms->rgrc[0];
3394 }
3395
3397
3398 return 0;
3399 }
3400
3402 {
3403 HMENU hMenu = (HMENU)wParam;
3405 {
3409 if (g_Arrangement != NONE)
3410 {
3413 MENUITEMINFOW mii = { sizeof(mii) };
3415 mii.fMask = MIIM_TYPE;
3416 mii.fType = MFT_STRING;
3417 mii.dwTypeData = const_cast<LPWSTR>(&strCaption[0]);
3419 }
3420 else
3421 {
3423 }
3424 }
3425 else
3426 {
3432 g_WindowPosBackup.RemoveAll();
3433 }
3434 return 0;
3435 }
3436
3438 {
3439#if 0
3440 LPNMRBAUTOSIZE as = (LPNMRBAUTOSIZE) nmhdr;
3441
3442 if (!as->fChanged)
3443 return 0;
3444
3445 RECT rc;
3446 ::GetWindowRect(m_hWnd, &rc);
3447
3448 SIZE szWindow = {
3449 rc.right - rc.left,
3450 rc.bottom - rc.top };
3451 SIZE szTarget = {
3452 as->rcTarget.right - as->rcTarget.left,
3453 as->rcTarget.bottom - as->rcTarget.top };
3454 SIZE szActual = {
3455 as->rcActual.right - as->rcActual.left,
3456 as->rcActual.bottom - as->rcActual.top };
3457
3458 SIZE borders = {
3459 szWindow.cx - szTarget.cx,
3460 szWindow.cy - szTarget.cx,
3461 };
3462
3463 switch (m_Position)
3464 {
3465 case ABE_LEFT:
3466 szWindow.cx = szActual.cx + borders.cx;
3467 break;
3468 case ABE_TOP:
3469 szWindow.cy = szActual.cy + borders.cy;
3470 break;
3471 case ABE_RIGHT:
3472 szWindow.cx = szActual.cx + borders.cx;
3473 rc.left = rc.right - szWindow.cy;
3474 break;
3475 case ABE_BOTTOM:
3476 szWindow.cy = szActual.cy + borders.cy;
3477 rc.top = rc.bottom - szWindow.cy;
3478 break;
3479 }
3480
3481 SetWindowPos(NULL, rc.left, rc.top, szWindow.cx, szWindow.cy, SWP_NOACTIVATE | SWP_NOZORDER);
3482#else
3483 bHandled = FALSE;
3484#endif
3485 return 0;
3486 }
3487
3489 {
3490 TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
3491
3492 /* Propagate the new settings to the children */
3495
3496 /* Toggle autohide */
3497 if (newSettings->sr.AutoHide != g_TaskbarSettings.sr.AutoHide)
3498 {
3499 g_TaskbarSettings.sr.AutoHide = newSettings->sr.AutoHide;
3502 if (!newSettings->sr.AutoHide)
3504 else
3506 }
3507
3508 /* Toggle lock state */
3509 Lock(newSettings->bLock);
3510
3511 /* Toggle OnTop state */
3512 if (newSettings->sr.AlwaysOnTop != g_TaskbarSettings.sr.AlwaysOnTop)
3513 {
3515 HWND hWndInsertAfter = newSettings->sr.AlwaysOnTop ? HWND_TOPMOST : HWND_BOTTOM;
3516 SetWindowPos(hWndInsertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
3517 }
3518
3519 /* Toggle show desktop button */
3521 {
3525 else if (!m_ShowDesktopButton.IsWindow())
3528 }
3529
3530 /* Adjust taskbar size */
3532
3534 return 0;
3535 }
3536
3538
3541 {
3542 MSG Msg;
3543 LRESULT lRet;
3544
3545 Msg.hwnd = m_hWnd;
3546 Msg.message = uMsg;
3547 Msg.wParam = wParam;
3548 Msg.lParam = lParam;
3549
3550 if (m_StartMenuBand->TranslateMenuMessage(&Msg, &lRet) == S_OK)
3551 {
3552 return lRet;
3553 }
3554
3555 wParam = Msg.wParam;
3556 lParam = Msg.lParam;
3557 }
3558 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
3560 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnRebarAutoSize) // Doesn't quite work ;P
3571 MESSAGE_HANDLER(WM_DISPLAYCHANGE, OnDisplayChange)
3598 ALT_MSG_MAP(1)
3599 END_MSG_MAP()
3600
3601 /*****************************************************************************/
3602
3604 {
3605 MSG Msg;
3606
3607 /* FIXME: We should keep a reference here... */
3608
3609 while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
3610 {
3611 if (Msg.message == WM_QUIT)
3612 break;
3613
3614 if (m_StartMenuBand == NULL ||
3615 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK)
3616 {
3619 }
3620 }
3621 }
3622
3624 {
3625 MSG Msg;
3626 BOOL Ret;
3627
3628 /* FIXME: We should keep a reference here... */
3629
3630 while (true)
3631 {
3632 Ret = GetMessage(&Msg, NULL, 0, 0);
3633
3634 if (!Ret || Ret == -1)
3635 break;
3636
3637 if (m_StartMenuBand == NULL ||
3638 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK)
3639 {
3642 }
3643 }
3644 }
3645
3646 /*
3647 * IShellDesktopTray
3648 *
3649 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
3650 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
3651 * The reason we implement it is because we have to use SHCreateDesktop() so
3652 * that the shell provides the desktop window and all the features that come
3653 * with it (especially positioning of desktop icons)
3654 */
3655
3657 {
3658 /* FIXME: Return ABS_ flags? */
3659 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3660 return 0;
3661 }
3662
3664 {
3665 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
3666 *phWndTray = m_hWnd;
3667 return S_OK;
3668 }
3669
3671 {
3672 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
3673
3674 m_DesktopWnd = hWndDesktop;
3675 return S_OK;
3676 }
3677
3678 virtual HRESULT STDMETHODCALLTYPE Unknown(IN DWORD dwUnknown1, IN DWORD dwUnknown2)
3679 {
3680 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
3681 return S_OK;
3682 }
3683
3685 {
3686 m_StartButton.SendMessageW(BM_SETSTATE, FALSE, 0);
3687 return S_OK;
3688 }
3689
3691 {
3692 if (!phwnd)
3693 return E_INVALIDARG;
3694 *phwnd = m_hWnd;
3695 return S_OK;
3696 }
3697
3699 {
3700 return E_NOTIMPL;
3701 }
3702
3703 void _Init()
3704 {
3705 m_Position = (DWORD) -1;
3706 }
3707
3709
3712 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3715 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
3716 END_COM_MAP()
3717};
3718
3722 public IContextMenu
3723{
3728
3729public:
3730 HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner)
3731 {
3732 this->TrayWnd = (CTrayWindow *) pTrayWnd;
3733 this->hWndOwner = hWndOwner;
3734 this->m_idCmdCmFirst = 0;
3735 return S_OK;
3736 }
3737
3740 UINT indexMenu,
3741 UINT idCmdFirst,
3742 UINT idCmdLast,
3743 UINT uFlags)
3744 {
3745 HMENU hMenuBase;
3746
3748
3750 {
3752 MENUITEMINFOW mii = { sizeof(mii) };
3753 mii.fMask = MIIM_ID | MIIM_TYPE;
3755 mii.fType = MFT_STRING;
3756 mii.dwTypeData = const_cast<LPWSTR>(&strRestoreAll[0]);
3758 }
3759
3760 if (!hMenuBase)
3762
3764 {
3765 DeleteMenu(hPopup,
3767 MF_BYCOMMAND);
3768 }
3769
3770 CheckMenuItem(hMenuBase,
3773
3774 UINT idCmdNext;
3775 idCmdNext = Shell_MergeMenus(hPopup, hMenuBase, indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS | MM_ADDSEPARATOR);
3776 m_idCmdCmFirst = idCmdNext - idCmdFirst;
3777
3778 ::DestroyMenu(hMenuBase);
3779
3780 if (TrayWnd->m_TrayBandSite != NULL)
3781 {
3782 pcm.Release();
3783 if (FAILED(TrayWnd->m_TrayBandSite->AddContextMenus(
3784 hPopup,
3785 indexMenu,
3786 idCmdNext,
3787 idCmdLast,
3788 CMF_NORMAL,
3789 &pcm)))
3790 {
3791 WARN("AddContextMenus failed.\n");
3792 pcm.Release();
3793 }
3794 }
3795
3796 return S_OK;
3797 }
3798
3801 {
3802 UINT uiCmdId = PtrToUlong(lpici->lpVerb);
3803 if (uiCmdId != 0)
3804 {
3805 if (uiCmdId >= m_idCmdCmFirst)
3806 {
3807 CMINVOKECOMMANDINFO cmici = { 0 };
3808
3809 if (pcm != NULL)
3810 {
3811 /* Setup and invoke the shell command */
3812 cmici.cbSize = sizeof(cmici);
3813 cmici.hwnd = hWndOwner;
3814 cmici.lpVerb = (LPCSTR) MAKEINTRESOURCEW(uiCmdId - m_idCmdCmFirst);
3815 cmici.nShow = SW_NORMAL;
3816
3817 pcm->InvokeCommand(&cmici);
3818 }
3819 }
3820 else
3821 {
3822 TrayWnd->ExecContextMenuCmd(uiCmdId);
3823 }
3824 }
3825
3826 return S_OK;
3827 }
3828
3831 UINT uType,
3832 UINT *pwReserved,
3833 LPSTR pszName,
3834 UINT cchMax)
3835 {
3836 return E_NOTIMPL;
3837 }
3838
3840 {
3841 }
3842
3844 {
3845 }
3846
3848 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
3849 END_COM_MAP()
3850};
3851
3852HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu)
3853{
3855 mnu->Initialize(TrayWnd, hWndOwner);
3856 *ppCtxMenu = mnu;
3857 return S_OK;
3858}
3859
3860HRESULT CreateTrayWindow(ITrayWindow ** ppTray)
3861{
3863 if (Tray == NULL)
3864 return E_OUTOFMEMORY;
3865
3866 Tray->_Init();
3867 Tray->Open();
3868
3869 *ppTray = (ITrayWindow *) Tray;
3870
3871 return S_OK;
3872}
3873
3874HRESULT
3876{
3877 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
3878 return TrayWindow->RaiseStartButton();
3879}
3880
3881VOID TrayProcessMessages(ITrayWindow *Tray)
3882{
3883 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
3884 TrayWindow->TrayProcessMessages();
3885}
3886
3887VOID TrayMessageLoop(ITrayWindow *Tray)
3888{
3889 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
3890 TrayWindow->TrayMessageLoop();
3891}
@ TS_TRUE
UINT cchMax
Arabic default style
Definition: afstyles.h:94
static int state
Definition: maze.c:121
HWND hWnd
Definition: settings.c:17
const WCHAR * class
Definition: main.c:68
#define IDB_START
Definition: resource.h:75
#define IDS_START
Definition: resource.h:23
static RECT margins
Definition: print.c:55
@ Create
Definition: registry.c:563
HINSTANCE hExplorerInstance
Definition: explorer.cpp:24
VOID DisplayTrayProperties(IN HWND hwndOwner, IN HWND hwndTaskbar)
Definition: trayprop.cpp:344
#define TWM_OPENSTARTMENU
Definition: precomp.h:132
#define TSWM_UPDATETASKBARPOS
Definition: precomp.h:355
#define TNWM_GETMINIMUMSIZE
Definition: precomp.h:341
HRESULT CStartMenuBtnCtxMenu_CreateInstance(ITrayWindow *TrayWnd, IN HWND hWndOwner, IContextMenu **ppCtxMenu)
HMENU LoadPopupMenu(IN HINSTANCE hInstance, IN LPCWSTR lpMenuName)
Definition: util.cpp:33
#define TWM_GETTASKSWITCH
Definition: precomp.h:131
IMenuPopup * CreateStartMenu(IN ITrayWindow *Tray, OUT IMenuBand **ppMenuBand, IN HBITMAP hbmBanner OPTIONAL, IN BOOL bSmallIcons)
Definition: startmnu.cpp:44
TaskbarSettings g_TaskbarSettings
Definition: settings.cpp:23
#define TWM_PULSE
Definition: precomp.h:134
HRESULT CTrayNotifyWnd_CreateInstance(HWND hwndParent, REFIID riid, void **ppv)
Definition: trayntfy.cpp:372
HRESULT CTrayBandSite_CreateInstance(IN ITrayWindow *tray, IN IDeskBand *pTaskBand, OUT ITrayBandSite **pBandSite)
Definition: tbsite.cpp:715
#define TWM_SETTINGSCHANGED
Definition: precomp.h:133
#define NTNWM_REALIGN
Definition: precomp.h:344
HRESULT InitShellServices(HDPA *phdpa)
HRESULT CTaskBand_CreateInstance(IN ITrayWindow *Tray, HWND hWndStartButton, REFIID riid, void **ppv)
Definition: taskband.cpp:346
HRESULT ShutdownShellServices(HDPA hdpa)
#define IDM_SEARCH
Definition: resource.h:71
#define ID_SHELL_CMD_OPEN_TASKMGR
Definition: resource.h:198
#define ID_SHELL_CMD_CUST_NOTIF
Definition: resource.h:204
#define ID_SHELL_CMD_UNDO_ACTION
Definition: resource.h:199
#define IDS_RESTORE_ALL
Definition: resource.h:105
#define IDM_TRAYWND
Definition: resource.h:57
#define ID_SHELL_CMD_PROPERTIES
Definition: resource.h:194
#define IDB_STARTMENU
Definition: resource.h:44
#define ID_SHELL_CMD_TILE_WND_H
Definition: resource.h:202
#define IDS_TRAYWND_UNDO_TILE
Definition: resource.h:107
#define IDC_STARTBTN
Definition: resource.h:132
#define ID_SHELL_CMD_CASCADE_WND
Definition: resource.h:203
#define ID_SHELL_CMD_RESTORE_ALL
Definition: resource.h:206
#define ID_SHELL_CMD_TILE_WND_V
Definition: resource.h:201
#define ID_LOCKTASKBAR
Definition: resource.h:197
#define ID_SHELL_CMD_SHOW_DESKTOP
Definition: resource.h:200
#define IDS_TRAYWND_UNDO_CASCADE
Definition: resource.h:106
#define ID_SHELL_CMD_EXPLORE_ALL_USERS
Definition: resource.h:196
#define ID_SHELL_CMD_ADJUST_DAT
Definition: resource.h:205
#define IDS_HELP_COMMAND
Definition: resource.h:103
#define ID_SHELL_CMD_OPEN_ALL_USERS
Definition: resource.h:195
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
void Release()
Definition: atlcomcli.h:170
int GetSize() const
Definition: atlsimpcoll.h:104
BOOL GetEnvironmentVariable(_In_z_ PCXSTR pszVar)
Definition: cstringt.h:658
BOOL IsIconic() const
Definition: atlwin.h:932
HWND GetLastActivePopup() const
Definition: atlwin.h:676
HWND SetFocus()
Definition: atlwin.h:1198
BOOL DestroyWindow()
Definition: atlwin.h:462
LRESULT SendMessage(UINT message, WPARAM wParam=0, LPARAM lParam=0)
Definition: atlwin.h:1116
HDC GetWindowDC()
Definition: atlwin.h:784
HDWP DeferWindowPos(HDWP hWinPosInfo, HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT uFlags)
Definition: atlwin.h:456
BOOL GetWindowRect(LPRECT lpRect) const
Definition: atlwin.h:816
CWindow GetParent() const
Definition: atlwin.h:700
BOOL IsWindowVisible() const
Definition: atlwin.h:958
HWND m_hWnd
Definition: atlwin.h:273
BOOL IsWindow() const
Definition: atlwin.h:947
BOOL IsWindowEnabled() const
Definition: atlwin.h:952
BOOL PostMessage(UINT message, WPARAM wParam=0, LPARAM lParam=0)
Definition: atlwin.h:1044
HIMAGELIST m_ImageList
Definition: traywnd.cpp:196
VOID Initialize()
Definition: traywnd.cpp:255
VOID UpdateFont()
Definition: traywnd.cpp:239
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
Definition: traywnd.cpp:306
SIZE GetSize()
Definition: traywnd.cpp:218
VOID UpdateSize()
Definition: traywnd.cpp:223
HWND Create(HWND hwndParent)
Definition: traywnd.cpp:275
HFONT m_Font
Definition: traywnd.cpp:198
virtual ~CStartButton()
Definition: traywnd.cpp:209
LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
Definition: traywnd.cpp:381
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
Definition: traywnd.cpp:400
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
Definition: traywnd.cpp:461
LRESULT OnClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
Definition: traywnd.cpp:357
BOOL PtInButton(POINT pt)
Definition: traywnd.cpp:412
HRESULT DoCreate(HWND hwndParent)
Definition: traywnd.cpp:346
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
Definition: traywnd.cpp:443