ReactOS 0.4.15-dev-8131-g4988de4
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 */
2560
2561 /* Create the task band */
2563 if (FAILED_UNEXPECTEDLY(hRet))
2564 return FALSE;
2565
2566 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */
2568 if (FAILED_UNEXPECTEDLY(hRet))
2569 return FALSE;
2570
2571 /* Create the tray notification window */
2573 if (FAILED_UNEXPECTEDLY(hRet))
2574 return FALSE;
2575
2576 /* Get the hwnd of the rebar */
2578 if (FAILED_UNEXPECTEDLY(hRet))
2579 return FALSE;
2580
2581 /* Get the hwnd of the tasks toolbar */
2583 if (FAILED_UNEXPECTEDLY(hRet))
2584 return FALSE;
2585
2586 /* Get the hwnd of the tray notification window */
2588 if (FAILED_UNEXPECTEDLY(hRet))
2589 return FALSE;
2590
2591 SetWindowTheme(m_Rebar, L"TaskBar", NULL);
2592
2593 UpdateFonts();
2594
2596
2598 {
2601 }
2602
2603 /* Set the initial lock state in the band site */
2605
2618
2619 return TRUE;
2620 }
2621
2622#define TIMER_ID_IGNOREPULSERESET 888
2623#define TIMER_IGNOREPULSERESET_TIMEOUT 200
2624
2626 {
2628 return 0;
2629 }
2630
2632 {
2633 if (m_Theme)
2635
2636 m_Theme = OpenThemeData(m_hWnd, L"TaskBar");
2637
2638 if (m_Theme)
2639 {
2641 }
2642 else
2643 {
2645 }
2647
2648 return TRUE;
2649 }
2650
2652 {
2653 if (wParam == SPI_SETNONCLIENTMETRICS)
2654 {
2657 UpdateFonts();
2660 }
2661
2662 if (m_StartMenuPopup && lstrcmpiW((LPCWSTR)lParam, L"TraySettings") == 0)
2663 {
2664 HideStartMenu();
2665
2667#if 1 // FIXME: Please re-use the start menu
2668 /* Re-create the start menu */
2672 FIXME("Use UpdateStartMenu\n");
2673#else
2674 // Update the start menu
2676#endif
2677 }
2678
2679 return 0;
2680 }
2681
2683 {
2684 HDC hdc = (HDC) wParam;
2685
2686 if (!m_Theme)
2687 {
2688 bHandled = FALSE;
2689 return 0;
2690 }
2691
2693 }
2694
2696 {
2697 /* Load the saved tray window settings */
2699
2700 /* Move the tray window to the right position and resize it if necessary */
2702
2703 return TRUE;
2704 }
2705
2707 {
2708 COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT *)lParam;
2709 switch (pCopyData->dwData)
2710 {
2711 case TABDMC_APPBAR:
2712 return appbar_message(pCopyData);
2713 case TABDMC_NOTIFY:
2714 case TABDMC_LOADINPROC:
2715 return ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam);
2716 }
2717 return FALSE;
2718 }
2719
2720 // We have to draw non-client area because the 'Show Desktop' button is beyond client area.
2722 {
2724 return;
2725 // Get the rectangle in window coordinates
2726 RECT rcButton, rcWnd;
2727 GetWindowRect(&rcWnd);
2729 ::OffsetRect(&rcButton, -rcWnd.left, -rcWnd.top);
2730
2732 m_ShowDesktopButton.OnDraw(hdc, &rcButton); // Draw the button
2733 ReleaseDC(hdc);
2734 }
2735
2737 {
2738 DefWindowProc(uMsg, wParam, lParam);
2739 bHandled = TRUE;
2740
2742 {
2743 DrawShowDesktopButton(); // We have to draw non-client area
2744 return 0;
2745 }
2746
2747 DrawSizerWithTheme((HRGN) wParam);
2748 DrawShowDesktopButton(); // We have to draw non-client area
2749 return 0;
2750 }
2751
2753 {
2756 }
2757
2759 {
2760 RECT rcClient;
2761 POINT pt;
2762
2764 {
2765 /* The user may not be able to resize the tray window.
2766 Pretend like the window is not sizeable when the user
2767 clicks on the border. */
2768 return HTBORDER;
2769 }
2770
2772 if (GetClientRect(&rcClient) &&
2773 (MapWindowPoints(NULL, (LPPOINT) &rcClient, 2) != 0 || GetLastError() == ERROR_SUCCESS))
2774 {
2775 pt.x = (SHORT) LOWORD(lParam);
2776 pt.y = (SHORT) HIWORD(lParam);
2777
2778 if (PtInRect(&rcClient, pt))
2779 {
2780 /* The user is trying to drag the tray window */
2781 return HTCAPTION;
2782 }
2783
2784 /* Depending on the position of the tray window, allow only
2785 changing the border next to the monitor working area */
2786 switch (m_Position)
2787 {
2788 case ABE_TOP:
2789 if (pt.y > rcClient.bottom)
2790 return HTBOTTOM;
2791 break;
2792 case ABE_LEFT:
2793 if (pt.x > rcClient.right)
2794 return HTRIGHT;
2795 break;
2796 case ABE_RIGHT:
2797 if (pt.x < rcClient.left)
2798 return HTLEFT;
2799 break;
2800 case ABE_BOTTOM:
2801 default:
2802 if (pt.y < rcClient.top)
2803 return HTTOP;
2804 break;
2805 }
2806 }
2807 return HTBORDER;
2808 }
2809
2811 {
2812 POINT ptCursor;
2813 PRECT pRect = (PRECT) lParam;
2814
2815 /* We need to ensure that an application can not accidently
2816 move the tray window (using SetWindowPos). However, we still
2817 need to be able to move the window in case the user wants to
2818 drag the tray window to another position or in case the user
2819 wants to resize the tray window. */
2820 if (!g_TaskbarSettings.bLock && GetCursorPos(&ptCursor))
2821 {
2822 IsDragging = TRUE;
2824 }
2825 else
2826 {
2827 *pRect = m_TrayRects[m_Position];
2828 }
2829 return TRUE;
2830 }
2831
2833 {
2834 PRECT pRect = (PRECT) lParam;
2835
2837 {
2838 FitToRebar(pRect);
2839 }
2840 else
2841 {
2842 *pRect = m_TrayRects[m_Position];
2843 }
2844 return TRUE;
2845 }
2846
2848 {
2850 return TRUE;
2851 }
2852
2854 {
2855 RECT rcClient;
2856 if (wParam == SIZE_RESTORED && lParam == 0)
2857 {
2859 /* Clip the tray window on multi monitor systems so the edges can't
2860 overlap into another monitor */
2862
2863 if (!GetClientRect(&rcClient))
2864 {
2865 return FALSE;
2866 }
2867 }
2868 else
2869 {
2870 rcClient.left = rcClient.top = 0;
2871 rcClient.right = LOWORD(lParam);
2872 rcClient.bottom = HIWORD(lParam);
2873 }
2874
2875 AlignControls(&rcClient);
2876 return TRUE;
2877 }
2878
2880 {
2881 InSizeMove = TRUE;
2882 IsDragging = FALSE;
2884 {
2885 /* Remove the clipping on multi monitor systems while dragging around */
2887 }
2888 return TRUE;
2889 }
2890
2892 {
2893 InSizeMove = FALSE;
2895 {
2897
2898 /* Apply clipping */
2900 }
2901 return TRUE;
2902 }
2903
2905 {
2906 switch (wParam)
2907 {
2908 case TEXT(' '):
2909 {
2910 /* The user pressed Alt+Space, this usually brings up the system menu of a window.
2911 The tray window needs to handle this specially, since it normally doesn't have
2912 a system menu. */
2913
2914 static const UINT uidDisableItem [] = {
2915 SC_RESTORE,
2916 SC_MOVE,
2917 SC_SIZE,
2920 };
2921 HMENU hSysMenu;
2922 UINT i, uId;
2923
2924 /* temporarily enable the system menu */
2926
2927 hSysMenu = GetSystemMenu(FALSE);
2928 if (hSysMenu != NULL)
2929 {
2930 /* Disable all items that are not relevant */
2931 for (i = 0; i < _countof(uidDisableItem); i++)
2932 {
2933 EnableMenuItem(hSysMenu,
2934 uidDisableItem[i],
2936 }
2937
2938 EnableMenuItem(hSysMenu,
2939 SC_CLOSE,
2940 MF_BYCOMMAND |
2942
2943 /* Display the system menu */
2944 uId = TrackMenu(
2945 hSysMenu,
2946 NULL,
2949 FALSE);
2950 if (uId != 0)
2951 {
2953 }
2954 }
2955
2956 /* revert the system menu window style */
2958 break;
2959 }
2960
2961 default:
2962 bHandled = FALSE;
2963 }
2964 return TRUE;
2965 }
2966
2968 {
2969 /* This handler implements the trick that makes the start button to
2970 get pressed when the user clicked left or below the button */
2971
2973 WINDOWINFO wi = {sizeof(WINDOWINFO)};
2974
2975 bHandled = FALSE;
2976
2977 RECT rcStartBtn;
2978 m_StartButton.GetWindowRect(&rcStartBtn);
2979
2980 GetWindowInfo(m_hWnd, &wi);
2981
2982 switch (m_Position)
2983 {
2984 case ABE_TOP:
2985 case ABE_LEFT:
2986 {
2987 if (pt.x > rcStartBtn.right || pt.y > rcStartBtn.bottom)
2988 return 0;
2989 break;
2990 }
2991 case ABE_RIGHT:
2992 {
2993 if (pt.x < rcStartBtn.left || pt.y > rcStartBtn.bottom)
2994 return 0;
2995
2996 if (rcStartBtn.right + (int)wi.cxWindowBorders * 2 + 1 < wi.rcWindow.right &&
2997 pt.x > rcStartBtn.right)
2998 {
2999 return 0;
3000 }
3001 break;
3002 }
3003 case ABE_BOTTOM:
3004 {
3005 if (pt.x > rcStartBtn.right || pt.y < rcStartBtn.top)
3006 return 0;
3007
3008 if (rcStartBtn.bottom + (int)wi.cyWindowBorders * 2 + 1 < wi.rcWindow.bottom &&
3009 pt.y > rcStartBtn.bottom)
3010 {
3011 return 0;
3012 }
3013
3014 break;
3015 }
3016 }
3017
3018 bHandled = TRUE;
3020 return 0;
3021 }
3022
3024 {
3025 /* We want the user to be able to get a context menu even on the nonclient
3026 area (including the sizing border)! */
3027 uMsg = WM_CONTEXTMENU;
3028 wParam = (WPARAM) m_hWnd;
3029
3030 return OnContextMenu(uMsg, wParam, lParam, bHandled);
3031 }
3032
3034 {
3035 LRESULT Ret = FALSE;
3036 POINT pt, *ppt = NULL;
3037 HWND hWndExclude = NULL;
3038
3039 /* Check if the administrator has forbidden access to context menus */
3041 return FALSE;
3042
3043 pt.x = (SHORT) LOWORD(lParam);
3044 pt.y = (SHORT) HIWORD(lParam);
3045
3046 if (pt.x != -1 || pt.y != -1)
3047 ppt = &pt;
3048 else
3049 hWndExclude = m_StartButton.m_hWnd;
3050
3052 {
3053 /* Make sure we can't track the context menu if the start
3054 menu is currently being shown */
3056 {
3057 CComPtr<IContextMenu> ctxMenu;
3059 TrackCtxMenu(ctxMenu, ppt, hWndExclude, m_Position == ABE_BOTTOM, this);
3060 }
3061 }
3062 else
3063 {
3064 /* See if the context menu should be handled by the task band site */
3065 if (ppt != NULL && m_TrayBandSite != NULL)
3066 {
3067 HWND hWndAtPt;
3068 POINT ptClient = *ppt;
3069
3070 /* Convert the coordinates to client-coordinates */
3071 ::MapWindowPoints(NULL, m_hWnd, &ptClient, 1);
3072
3073 hWndAtPt = ChildWindowFromPoint(ptClient);
3074 if (hWndAtPt != NULL &&
3075 (hWndAtPt == m_Rebar || ::IsChild(m_Rebar, hWndAtPt)))
3076 {
3077 /* Check if the user clicked on the task switch window */
3078 ptClient = *ppt;
3079 ::MapWindowPoints(NULL, m_Rebar, &ptClient, 1);
3080
3082 if (hWndAtPt == m_TaskSwitch)
3083 goto HandleTrayContextMenu;
3084
3085 /* Forward the message to the task band site */
3086 m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
3087 }
3088 else
3089 goto HandleTrayContextMenu;
3090 }
3091 else
3092 {
3093HandleTrayContextMenu:
3094 /* Tray the default tray window context menu */
3095 TrackCtxMenu(this, ppt, NULL, FALSE, this);
3096 }
3097 }
3098 return Ret;
3099 }
3100
3102 {
3103 LRESULT Ret = FALSE;
3104 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
3105 the rebar control! But we shouldn't forward messages that the band
3106 site doesn't handle, such as other controls (start button, tray window */
3107
3108 HRESULT hr = E_FAIL;
3109
3110 if (m_TrayBandSite)
3111 {
3112 hr = m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
3113 if (SUCCEEDED(hr))
3114 return Ret;
3115 }
3116
3117 if (m_TrayBandSite == NULL || FAILED(hr))
3118 {
3119 const NMHDR *nmh = (const NMHDR *) lParam;
3120
3121 if (nmh->hwndFrom == m_TrayNotify)
3122 {
3123 switch (nmh->code)
3124 {
3125 case NTNWM_REALIGN:
3126 /* Cause all controls to be aligned */
3128 break;
3129 }
3130 }
3131 }
3132 return Ret;
3133 }
3134
3136 {
3138 if (m_ShowDesktopButton.PtInButton(pt)) // Did you click the button?
3139 {
3141 bHandled = TRUE;
3142 return TRUE;
3143 }
3144
3145 return FALSE;
3146 }
3147
3149 {
3150 /* Let the clock handle the double-click */
3152
3153 /* We "handle" this message so users can't cause a weird maximize/restore
3154 window animation when double-clicking the tray window! */
3155 return TRUE;
3156 }
3157
3159 {
3161 return FALSE;
3162 }
3163
3165 {
3166 DestroyWindow();
3167 return TRUE;
3168 }
3169
3171 {
3172 HWND hwndStartMenu;
3173 HRESULT hr = IUnknown_GetWindow(m_StartMenuPopup, &hwndStartMenu);
3175 return FALSE;
3176
3177 if (::IsWindowVisible(hwndStartMenu))
3178 HideStartMenu();
3179 else
3181
3182 return TRUE;
3183 }
3184
3186 {
3187 /*
3188 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us
3189 * to show the shutdown dialog. Also a WM_CLOSE message sent
3190 * by apps should show the dialog.
3191 */
3192 return DoExitWindows();
3193 }
3194
3196 {
3197 if (wParam == SC_CLOSE)
3198 {
3199 return DoExitWindows();
3200 }
3201
3202 bHandled = FALSE;
3203 return TRUE;
3204 }
3205
3207 {
3208 bHandled = TRUE;
3209 return (LRESULT)m_TaskSwitch;
3210 }
3211
3212 void RestoreMinimizedNonTaskWnds(BOOL bDestroyed, HWND hwndActive)
3213 {
3214 for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i)
3215 {
3216 HWND hwnd = g_MinimizedAll[i].hwnd;
3217 if (!hwnd || hwndActive == hwnd)
3218 continue;
3219
3222 {
3223 ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl); // Restore
3224 }
3225 }
3226
3228
3229 if (!bDestroyed)
3230 ::SetForegroundWindow(hwndActive);
3231 }
3232
3234 {
3235 if (IgnorePulse)
3236 return 0;
3237
3239 IgnorePulse = TRUE;
3242 return 0;
3243 }
3244
3246 {
3247 return HandleHotKey(wParam);
3248 }
3249
3251 {
3257 };
3258
3260 {
3261 WCHAR szClass[32];
3262 GetClassNameW(hwnd, szClass, _countof(szClass));
3263 return wcscmp(szClass, L"#32770") == 0;
3264 }
3265
3267 {
3269 if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd || hwnd == info->hwndProgman)
3270 return TRUE; // Ignore special windows
3271
3272 if (!info->bShowDesktop)
3273 {
3275 return TRUE;
3276 HWND hwndOwner = ::GetWindow(hwnd, GW_OWNER);
3277 if (hwndOwner && !::IsWindowEnabled(hwndOwner))
3278 return TRUE;
3279 }
3280
3281 if (CanBeMinimized(hwnd))
3282 {
3283 MINWNDPOS mwp = { hwnd, { sizeof(mwp.wndpl) } };
3284 if (::GetWindowPlacement(hwnd, &mwp.wndpl) && // Save the position and status
3286 {
3287 info->pMinimizedAll->Add(mwp);
3288 }
3289 }
3290
3291 return TRUE;
3292 }
3293
3294 VOID MinimizeAll(BOOL bShowDesktop = FALSE)
3295 {
3296 IgnorePulse = TRUE;
3298
3300 info.hwndDesktop = GetDesktopWindow();;
3301 info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL);
3302 info.hwndProgman = FindWindowW(L"Progman", NULL);
3303 info.pMinimizedAll = &g_MinimizedAll;
3304 info.bShowDesktop = bShowDesktop;
3306
3310 }
3311
3313 {
3315 }
3316
3318 {
3319 IgnorePulse = TRUE;
3321
3322 for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i)
3323 {
3324 HWND hwnd = g_MinimizedAll[i].hwnd;
3327 }
3328
3331 }
3332
3334 {
3335 LRESULT Ret = FALSE;
3336
3338 {
3339 return FALSE;
3340 }
3341
3342 if (m_TrayBandSite == NULL || FAILED_UNEXPECTEDLY(m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret)))
3343 {
3344 return HandleCommand(LOWORD(wParam));
3345 }
3346 return Ret;
3347 }
3348
3350 {
3351 POINT pt;
3355
3357 {
3359 }
3360
3361 return TRUE;
3362 }
3363
3365 {
3367 {
3369 }
3370 else if (wParam == TIMER_ID_AUTOHIDE)
3371 {
3373 }
3375 {
3378 }
3379 return 0;
3380 }
3381
3383 {
3385 DrawShowDesktopButton(); // We have to draw non-client area
3386 bHandled = TRUE;
3387 return ret;
3388 }
3389
3391 {
3392 RECT *rc = NULL;
3393 /* Ignore WM_NCCALCSIZE if we are not themed or locked */
3395 {
3396 bHandled = FALSE;
3397 return 0;
3398 }
3399 if(!wParam)
3400 {
3401 rc = (RECT*)wParam;
3402 }
3403 else
3404 {
3406 if(prms->lppos->flags & SWP_NOSENDCHANGING)
3407 {
3408 bHandled = FALSE;
3409 return 0;
3410 }
3411 rc = &prms->rgrc[0];
3412 }
3413
3415
3416 return 0;
3417 }
3418
3420 {
3421 HMENU hMenu = (HMENU)wParam;
3423 {
3427 if (g_Arrangement != NONE)
3428 {
3431 MENUITEMINFOW mii = { sizeof(mii) };
3433 mii.fMask = MIIM_TYPE;
3434 mii.fType = MFT_STRING;
3435 mii.dwTypeData = const_cast<LPWSTR>(&strCaption[0]);
3437 }
3438 else
3439 {
3441 }
3442 }
3443 else
3444 {
3450 g_WindowPosBackup.RemoveAll();
3451 }
3452 return 0;
3453 }
3454
3456 {
3457#if 0
3458 LPNMRBAUTOSIZE as = (LPNMRBAUTOSIZE) nmhdr;
3459
3460 if (!as->fChanged)
3461 return 0;
3462
3463 RECT rc;
3464 ::GetWindowRect(m_hWnd, &rc);
3465
3466 SIZE szWindow = {
3467 rc.right - rc.left,
3468 rc.bottom - rc.top };
3469 SIZE szTarget = {
3470 as->rcTarget.right - as->rcTarget.left,
3471 as->rcTarget.bottom - as->rcTarget.top };
3472 SIZE szActual = {
3473 as->rcActual.right - as->rcActual.left,
3474 as->rcActual.bottom - as->rcActual.top };
3475
3476 SIZE borders = {
3477 szWindow.cx - szTarget.cx,
3478 szWindow.cy - szTarget.cx,
3479 };
3480
3481 switch (m_Position)
3482 {
3483 case ABE_LEFT:
3484 szWindow.cx = szActual.cx + borders.cx;
3485 break;
3486 case ABE_TOP:
3487 szWindow.cy = szActual.cy + borders.cy;
3488 break;
3489 case ABE_RIGHT:
3490 szWindow.cx = szActual.cx + borders.cx;
3491 rc.left = rc.right - szWindow.cy;
3492 break;
3493 case ABE_BOTTOM:
3494 szWindow.cy = szActual.cy + borders.cy;
3495 rc.top = rc.bottom - szWindow.cy;
3496 break;
3497 }
3498
3499 SetWindowPos(NULL, rc.left, rc.top, szWindow.cx, szWindow.cy, SWP_NOACTIVATE | SWP_NOZORDER);
3500#else
3501 bHandled = FALSE;
3502#endif
3503 return 0;
3504 }
3505
3507 {
3508 TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
3509
3510 /* Propagate the new settings to the children */
3513
3514 /* Toggle autohide */
3515 if (newSettings->sr.AutoHide != g_TaskbarSettings.sr.AutoHide)
3516 {
3517 g_TaskbarSettings.sr.AutoHide = newSettings->sr.AutoHide;
3520 if (!newSettings->sr.AutoHide)
3522 else
3524 }
3525
3526 /* Toggle lock state */
3527 Lock(newSettings->bLock);
3528
3529 /* Toggle OnTop state */
3530 if (newSettings->sr.AlwaysOnTop != g_TaskbarSettings.sr.AlwaysOnTop)
3531 {
3533 HWND hWndInsertAfter = newSettings->sr.AlwaysOnTop ? HWND_TOPMOST : HWND_BOTTOM;
3534 SetWindowPos(hWndInsertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
3535 }
3536
3537 /* Toggle show desktop button */
3539 {
3543 else if (!m_ShowDesktopButton.IsWindow())
3546 }
3547
3548 /* Adjust taskbar size */
3550
3552 return 0;
3553 }
3554
3556
3559 {
3560 MSG Msg;
3561 LRESULT lRet;
3562
3563 Msg.hwnd = m_hWnd;
3564 Msg.message = uMsg;
3565 Msg.wParam = wParam;
3566 Msg.lParam = lParam;
3567
3568 if (m_StartMenuBand->TranslateMenuMessage(&Msg, &lRet) == S_OK)
3569 {
3570 return lRet;
3571 }
3572
3573 wParam = Msg.wParam;
3574 lParam = Msg.lParam;
3575 }
3576 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
3578 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnRebarAutoSize) // Doesn't quite work ;P
3589 MESSAGE_HANDLER(WM_DISPLAYCHANGE, OnDisplayChange)
3616 ALT_MSG_MAP(1)
3617 END_MSG_MAP()
3618
3619 /*****************************************************************************/
3620
3622 {
3623 MSG Msg;
3624
3625 /* FIXME: We should keep a reference here... */
3626
3627 while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
3628 {
3629 if (Msg.message == WM_QUIT)
3630 break;
3631
3632 if (m_StartMenuBand == NULL ||
3633 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK)
3634 {
3637 }
3638 }
3639 }
3640
3642 {
3643 MSG Msg;
3644 BOOL Ret;
3645
3646 /* FIXME: We should keep a reference here... */
3647
3648 while (true)
3649 {
3650 Ret = GetMessage(&Msg, NULL, 0, 0);
3651
3652 if (!Ret || Ret == -1)
3653 break;
3654
3655 if (m_StartMenuBand == NULL ||
3656 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK)
3657 {
3660 }
3661 }
3662 }
3663
3664 /*
3665 * IShellDesktopTray
3666 *
3667 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
3668 * These are the calls I observed, it may be wrong/incomplete/buggy!!!
3669 * The reason we implement it is because we have to use SHCreateDesktop() so
3670 * that the shell provides the desktop window and all the features that come
3671 * with it (especially positioning of desktop icons)
3672 */
3673
3675 {
3676 /* FIXME: Return ABS_ flags? */
3677 TRACE("IShellDesktopTray::GetState() unimplemented!\n");
3678 return 0;
3679 }
3680
3682 {
3683 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
3684 *phWndTray = m_hWnd;
3685 return S_OK;
3686 }
3687
3689 {
3690 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
3691
3692 m_DesktopWnd = hWndDesktop;
3693 return S_OK;
3694 }
3695
3696 virtual HRESULT STDMETHODCALLTYPE Unknown(IN DWORD dwUnknown1, IN DWORD dwUnknown2)
3697 {
3698 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
3699 return S_OK;
3700 }
3701
3703 {
3704 m_StartButton.SendMessageW(BM_SETSTATE, FALSE, 0);
3705 return S_OK;
3706 }
3707
3709 {
3710 if (!phwnd)
3711 return E_INVALIDARG;
3712 *phwnd = m_hWnd;
3713 return S_OK;
3714 }
3715
3717 {
3718 return E_NOTIMPL;
3719 }
3720
3721 void _Init()
3722 {
3723 m_Position = (DWORD) -1;
3724 }
3725
3727
3730 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
3733 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
3734 END_COM_MAP()
3735};
3736
3740 public IContextMenu
3741{
3746
3747public:
3748 HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner)
3749 {
3750 this->TrayWnd = (CTrayWindow *) pTrayWnd;
3751 this->hWndOwner = hWndOwner;
3752 this->m_idCmdCmFirst = 0;
3753 return S_OK;
3754 }
3755
3758 UINT indexMenu,
3759 UINT idCmdFirst,
3760 UINT idCmdLast,
3761 UINT uFlags)
3762 {
3763 HMENU hMenuBase;
3764
3766 if (!hMenuBase)
3768
3770 {
3772 MENUITEMINFOW mii = { sizeof(mii) };
3773 mii.fMask = MIIM_ID | MIIM_TYPE;
3775 mii.fType = MFT_STRING;
3776 mii.dwTypeData = const_cast<LPWSTR>(&strRestoreAll[0]);
3778 }
3779
3781 {
3782 DeleteMenu(hPopup,
3784 MF_BYCOMMAND);
3785 }
3786
3787 CheckMenuItem(hMenuBase,
3790
3791 UINT idCmdNext;
3792 idCmdNext = Shell_MergeMenus(hPopup, hMenuBase, indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS | MM_ADDSEPARATOR);
3793 m_idCmdCmFirst = idCmdNext - idCmdFirst;
3794
3795 ::DestroyMenu(hMenuBase);
3796
3797 if (TrayWnd->m_TrayBandSite != NULL)
3798 {
3799 pcm.Release();
3800 if (FAILED(TrayWnd->m_TrayBandSite->AddContextMenus(
3801 hPopup,
3802 indexMenu,
3803 idCmdNext,
3804 idCmdLast,
3805 CMF_NORMAL,
3806 &pcm)))
3807 {
3808 WARN("AddContextMenus failed.\n");
3809 pcm.Release();
3810 }
3811 }
3812
3813 return S_OK;
3814 }
3815
3818 {
3819 UINT uiCmdId = PtrToUlong(lpici->lpVerb);
3820 if (uiCmdId != 0)
3821 {
3822 if (uiCmdId >= m_idCmdCmFirst)
3823 {
3824 CMINVOKECOMMANDINFO cmici = { 0 };
3825
3826 if (pcm != NULL)
3827 {
3828 /* Setup and invoke the shell command */
3829 cmici.cbSize = sizeof(cmici);
3830 cmici.hwnd = hWndOwner;
3831 cmici.lpVerb = (LPCSTR) MAKEINTRESOURCEW(uiCmdId - m_idCmdCmFirst);
3832 cmici.nShow = SW_NORMAL;
3833
3834 pcm->InvokeCommand(&cmici);
3835 }
3836 }
3837 else
3838 {
3839 TrayWnd->ExecContextMenuCmd(uiCmdId);
3840 }
3841 }
3842
3843 return S_OK;
3844 }
3845
3848 UINT uType,
3849 UINT *pwReserved,
3850 LPSTR pszName,
3851 UINT cchMax)
3852 {
3853 return E_NOTIMPL;
3854 }
3855
3857 {
3858 }
3859
3861 {
3862 }
3863
3865 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
3866 END_COM_MAP()
3867};
3868
3869HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu)
3870{
3872 mnu->Initialize(TrayWnd, hWndOwner);
3873 *ppCtxMenu = mnu;
3874 return S_OK;
3875}
3876
3877HRESULT CreateTrayWindow(ITrayWindow ** ppTray)
3878{
3880 if (Tray == NULL)
3881 return E_OUTOFMEMORY;
3882
3883 Tray->_Init();
3884 Tray->Open();
3885
3886 *ppTray = (ITrayWindow *) Tray;
3887
3888 return S_OK;
3889}
3890
3891HRESULT
3893{
3894 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
3895 return TrayWindow->RaiseStartButton();
3896}
3897
3898VOID TrayProcessMessages(ITrayWindow *Tray)
3899{
3900 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
3901 TrayWindow->TrayProcessMessages();
3902}
3903
3904VOID TrayMessageLoop(ITrayWindow *Tray)
3905{
3906 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray);
3907 TrayWindow->TrayMessageLoop();
3908}
@ 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
HRESULT UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup, IN HBITMAP hbmBanner OPTIONAL, IN BOOL bSmallIcons, IN BOOL bRefresh)
Definition: startmnu.cpp:24
#define TSWM_UPDATETASKBARPOS
Definition: precomp.h:381
#define TNWM_GETMINIMUMSIZE
Definition: precomp.h:367
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:50
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:370
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:208
#define ID_SHELL_CMD_CUST_NOTIF
Definition: resource.h:214
#define ID_SHELL_CMD_UNDO_ACTION
Definition: resource.h:209
#define IDS_RESTORE_ALL
Definition: resource.h:105
#define IDM_TRAYWND
Definition: resource.h:57
#define ID_SHELL_CMD_PROPERTIES
Definition: resource.h:204
#define IDB_STARTMENU
Definition: resource.h:44
#define ID_SHELL_CMD_TILE_WND_H
Definition: resource.h:212
#define IDS_TRAYWND_UNDO_TILE
Definition: resource.h:107
#define IDC_STARTBTN
Definition: resource.h:144
#define ID_SHELL_CMD_CASCADE_WND
Definition: resource.h:213
#define ID_SHELL_CMD_RESTORE_ALL
Definition: resource.h:216
#define ID_SHELL_CMD_TILE_WND_V
Definition: resource.h:211
#define ID_LOCKTASKBAR
Definition: resource.h:207
#define ID_SHELL_CMD_SHOW_DESKTOP
Definition: resource.h:210
#define IDS_TRAYWND_UNDO_CASCADE
Definition: resource.h:106
#define ID_SHELL_CMD_EXPLORE_ALL_USERS
Definition: resource.h:206
#define ID_SHELL_CMD_ADJUST_DAT
Definition: resource.h:215
#define IDS_HELP_COMMAND
Definition: resource.h:103
#define ID_SHELL_CMD_OPEN_ALL_USERS
Definition: resource.h:205
#define STDMETHODCALLTYPE
Definition: bdasup.h:9
#define FIXME(fmt,...)
Definition: debug.h:114
#define WARN(fmt,...)
Definition: debug.h:115
#define ERR(fmt,...)
Definition: debug.h:113
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()
D