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 25 HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu); 26 LRESULT appbar_message(COPYDATASTRUCT* cds); 27 void 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 59 static const WCHAR szTrayWndClass[] = L"Shell_TrayWnd"; 60 61 enum { NONE, TILED, CASCADED } g_Arrangement = NONE; 62 63 struct WINDOWPOSBACKUPDATA 64 { 65 HWND hwnd; 66 WINDOWPLACEMENT wplt; 67 }; 68 CSimpleArray<WINDOWPOSBACKUPDATA> g_WindowPosBackup; 69 70 static BOOL CALLBACK BackupWindowsPosProc(HWND hwnd, LPARAM lParam) 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 85 VOID BackupWindowPos() 86 { 87 EnumWindows(BackupWindowsPosProc, NULL); 88 } 89 90 VOID RestoreWindowPos() 91 { 92 g_Arrangement = NONE; 93 94 for (INT i = g_WindowPosBackup.GetSize() - 1; i >= 0; --i) 95 { 96 SetWindowPlacement(g_WindowPosBackup[i].hwnd, &(g_WindowPosBackup[i].wplt)); 97 } 98 99 g_WindowPosBackup.RemoveAll(); 100 } 101 102 BOOL CanBeMinimized(HWND hwnd) 103 { 104 if (::IsWindowVisible(hwnd) && !::IsIconic(hwnd) && ::IsWindowEnabled(hwnd) && 105 !::IsHungAppWindow(hwnd)) 106 { 107 if (::GetClassLongPtrW(hwnd, GCW_ATOM) == (ULONG_PTR)WC_DIALOG) 108 return TRUE; 109 110 DWORD exstyle = (DWORD)::GetWindowLongPtrW(hwnd, GWL_EXSTYLE); 111 if (!(exstyle & WS_EX_TOPMOST)) 112 return TRUE; 113 } 114 return FALSE; 115 } 116 117 struct EFFECTIVE_INFO 118 { 119 HWND hwndFound; 120 HWND hwndDesktop; 121 HWND hwndProgman; 122 HWND hTrayWnd; 123 BOOL bMustBeInMonitor; 124 }; 125 126 static BOOL CALLBACK 127 FindEffectiveProc(HWND hwnd, LPARAM lParam) 128 { 129 EFFECTIVE_INFO *pei = (EFFECTIVE_INFO *)lParam; 130 131 if (!CanBeMinimized(hwnd)) 132 return TRUE; // continue 133 134 if (pei->hTrayWnd == hwnd || pei->hwndDesktop == hwnd || 135 pei->hwndProgman == hwnd) 136 { 137 return TRUE; // continue 138 } 139 140 if (pei->bMustBeInMonitor) 141 { 142 // is the window in the nearest monitor? 143 HMONITOR hMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); 144 if (hMon) 145 { 146 MONITORINFO info; 147 ZeroMemory(&info, sizeof(info)); 148 info.cbSize = sizeof(info); 149 if (GetMonitorInfoW(hMon, &info)) 150 { 151 RECT rcWindow, rcMonitor, rcIntersect; 152 rcMonitor = info.rcMonitor; 153 154 GetWindowRect(hwnd, &rcWindow); 155 156 if (!IntersectRect(&rcIntersect, &rcMonitor, &rcWindow)) 157 return TRUE; // continue 158 } 159 } 160 } 161 162 pei->hwndFound = hwnd; 163 return FALSE; // stop if found 164 } 165 166 static BOOL 167 IsThereAnyEffectiveWindow(BOOL bMustBeInMonitor) 168 { 169 EFFECTIVE_INFO ei; 170 ei.hwndFound = NULL; 171 ei.hwndDesktop = GetDesktopWindow(); 172 ei.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL); 173 ei.hwndProgman = FindWindowW(L"Progman", NULL); 174 ei.bMustBeInMonitor = bMustBeInMonitor; 175 176 EnumWindows(FindEffectiveProc, (LPARAM)&ei); 177 return ei.hwndFound != NULL; 178 } 179 180 /* Minimized window position info */ 181 struct MINWNDPOS 182 { 183 HWND hwnd; 184 WINDOWPLACEMENT wndpl; 185 }; 186 CSimpleArray<MINWNDPOS> g_MinimizedAll; 187 188 /* 189 * ITrayWindow 190 */ 191 192 const GUID IID_IShellDesktopTray = { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } }; 193 194 class CStartButton 195 : public CWindowImpl<CStartButton> 196 { 197 HIMAGELIST m_ImageList; 198 SIZE m_Size; 199 HFONT m_Font; 200 201 public: 202 CStartButton() 203 : m_ImageList(NULL), 204 m_Font(NULL) 205 { 206 m_Size.cx = 0; 207 m_Size.cy = 0; 208 } 209 210 virtual ~CStartButton() 211 { 212 if (m_ImageList != NULL) 213 ImageList_Destroy(m_ImageList); 214 215 if (m_Font != NULL) 216 DeleteObject(m_Font); 217 } 218 219 SIZE GetSize() 220 { 221 return m_Size; 222 } 223 224 VOID UpdateSize() 225 { 226 SIZE Size = { 0, 0 }; 227 228 if (m_ImageList == NULL || 229 !SendMessageW(BCM_GETIDEALSIZE, 0, (LPARAM) &Size)) 230 { 231 Size.cx = 2 * GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CYCAPTION) * 3; 232 } 233 234 Size.cy = max(Size.cy, GetSystemMetrics(SM_CYCAPTION)); 235 236 /* Save the size of the start button */ 237 m_Size = Size; 238 } 239 240 VOID UpdateFont() 241 { 242 /* Get the system fonts, we use the caption font, always bold, though. */ 243 NONCLIENTMETRICS ncm = {sizeof(ncm)}; 244 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE)) 245 return; 246 247 if (m_Font) 248 DeleteObject(m_Font); 249 250 ncm.lfCaptionFont.lfWeight = FW_BOLD; 251 m_Font = CreateFontIndirect(&ncm.lfCaptionFont); 252 253 SetFont(m_Font, FALSE); 254 } 255 256 VOID Initialize() 257 { 258 // HACK & FIXME: CORE-18016 259 HWND hWnd = m_hWnd; 260 m_hWnd = NULL; 261 SubclassWindow(hWnd); 262 263 SetWindowTheme(m_hWnd, L"Start", NULL); 264 265 m_ImageList = ImageList_LoadImageW(hExplorerInstance, 266 MAKEINTRESOURCEW(IDB_START), 267 0, 0, 0, 268 IMAGE_BITMAP, 269 LR_LOADTRANSPARENT | LR_CREATEDIBSECTION); 270 271 BUTTON_IMAGELIST bil = {m_ImageList, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT}; 272 SendMessageW(BCM_SETIMAGELIST, 0, (LPARAM) &bil); 273 UpdateSize(); 274 } 275 276 HWND Create(HWND hwndParent) 277 { 278 WCHAR szStartCaption[32]; 279 if (!LoadStringW(hExplorerInstance, 280 IDS_START, 281 szStartCaption, 282 _countof(szStartCaption))) 283 { 284 wcscpy(szStartCaption, L"Start"); 285 } 286 287 DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_PUSHBUTTON | BS_LEFT | BS_VCENTER; 288 289 // HACK & FIXME: CORE-18016 290 m_hWnd = CreateWindowEx( 291 0, 292 WC_BUTTON, 293 szStartCaption, 294 dwStyle, 295 0, 0, 0, 0, 296 hwndParent, 297 (HMENU) IDC_STARTBTN, 298 hExplorerInstance, 299 NULL); 300 301 if (m_hWnd) 302 Initialize(); 303 304 return m_hWnd; 305 } 306 307 LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 308 { 309 if (uMsg == WM_KEYUP && wParam != VK_SPACE) 310 return 0; 311 312 GetParent().PostMessage(TWM_OPENSTARTMENU); 313 return 0; 314 } 315 316 BEGIN_MSG_MAP(CStartButton) 317 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) 318 END_MSG_MAP() 319 320 }; 321 322 // This window class name is CONFIRMED on Win10 by WinHier. 323 static const WCHAR szTrayShowDesktopButton[] = L"TrayShowDesktopButtonWClass"; 324 325 // The 'Show Desktop' button at edge of taskbar 326 class CTrayShowDesktopButton : 327 public CWindowImpl<CTrayShowDesktopButton, CWindow, CControlWinTraits> 328 { 329 LONG m_nClickedTime; 330 BOOL m_bHovering; 331 HTHEME m_hTheme; 332 333 public: 334 DECLARE_WND_CLASS_EX(szTrayShowDesktopButton, CS_HREDRAW | CS_VREDRAW, COLOR_3DFACE) 335 336 CTrayShowDesktopButton() : m_nClickedTime(0), m_bHovering(FALSE) 337 { 338 } 339 340 INT WidthOrHeight() const 341 { 342 #define SHOW_DESKTOP_MINIMUM_WIDTH 3 343 INT cxy = 2 * ::GetSystemMetrics(SM_CXEDGE); 344 return max(cxy, SHOW_DESKTOP_MINIMUM_WIDTH); 345 } 346 347 HRESULT DoCreate(HWND hwndParent) 348 { 349 DWORD style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS; 350 Create(hwndParent, NULL, NULL, style); 351 if (!m_hWnd) 352 return E_FAIL; 353 354 ::SetWindowTheme(m_hWnd, L"TaskBar", NULL); 355 return S_OK; 356 } 357 358 LRESULT OnClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 359 { 360 // The actual action can be delayed as an expected behaviour. 361 // But a too late action is an unexpected behaviour. 362 LONG nTime0 = m_nClickedTime; 363 LONG nTime1 = ::GetMessageTime(); 364 if (nTime1 - nTime0 >= 600) // Ignore after 0.6 sec 365 return 0; 366 367 // Show/Hide Desktop 368 GetParent().SendMessage(WM_COMMAND, TRAYCMD_TOGGLE_DESKTOP, 0); 369 return 0; 370 } 371 372 #define TSDB_CLICK (WM_USER + 100) 373 374 // This function is called from OnLButtonDown and parent. 375 VOID Click() 376 { 377 // The actual action can be delayed as an expected behaviour. 378 m_nClickedTime = ::GetMessageTime(); 379 PostMessage(TSDB_CLICK, 0, 0); 380 } 381 382 LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 383 { 384 Click(); // Left-click 385 return 0; 386 } 387 388 LRESULT OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 389 { 390 if (m_hTheme) 391 ::CloseThemeData(m_hTheme); 392 393 m_hTheme = ::OpenThemeData(m_hWnd, L"TaskBar"); 394 InvalidateRect(NULL, TRUE); 395 return 0; 396 } 397 398 // This function is called from OnPaint and parent. 399 VOID OnDraw(HDC hdc, LPRECT prc); 400 401 LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 402 { 403 RECT rc; 404 GetClientRect(&rc); 405 406 PAINTSTRUCT ps; 407 HDC hdc = BeginPaint(&ps); 408 OnDraw(hdc, &rc); 409 EndPaint(&ps); 410 return 0; 411 } 412 413 BOOL PtInButton(POINT pt) 414 { 415 if (!IsWindow()) 416 return FALSE; 417 RECT rc; 418 GetWindowRect(&rc); 419 INT cxEdge = ::GetSystemMetrics(SM_CXEDGE), cyEdge = ::GetSystemMetrics(SM_CYEDGE); 420 ::InflateRect(&rc, max(cxEdge, 1), max(cyEdge, 1)); 421 return ::PtInRect(&rc, pt); 422 } 423 424 #define SHOW_DESKTOP_TIMER_ID 999 425 #define SHOW_DESKTOP_TIMER_INTERVAL 200 426 427 VOID StartHovering() 428 { 429 if (m_bHovering) 430 return; 431 432 m_bHovering = TRUE; 433 SetTimer(SHOW_DESKTOP_TIMER_ID, SHOW_DESKTOP_TIMER_INTERVAL, NULL); 434 InvalidateRect(NULL, TRUE); 435 GetParent().PostMessage(WM_NCPAINT, 0, 0); 436 } 437 438 LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 439 { 440 StartHovering(); 441 return 0; 442 } 443 444 LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 445 { 446 if (wParam != SHOW_DESKTOP_TIMER_ID || !m_bHovering) 447 return 0; 448 449 POINT pt; 450 ::GetCursorPos(&pt); 451 if (!PtInButton(pt)) // The end of hovering? 452 { 453 m_bHovering = FALSE; 454 KillTimer(SHOW_DESKTOP_TIMER_ID); 455 InvalidateRect(NULL, TRUE); 456 GetParent().PostMessage(WM_NCPAINT, 0, 0); 457 } 458 459 return 0; 460 } 461 462 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 463 { 464 if (m_hTheme) 465 { 466 CloseThemeData(m_hTheme); 467 m_hTheme = NULL; 468 } 469 return 0; 470 } 471 472 BEGIN_MSG_MAP(CTrayShowDesktopButton) 473 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) 474 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChanged) 475 MESSAGE_HANDLER(WM_THEMECHANGED, OnSettingChanged) 476 MESSAGE_HANDLER(WM_PAINT, OnPaint) 477 MESSAGE_HANDLER(WM_TIMER, OnTimer) 478 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) 479 MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 480 MESSAGE_HANDLER(TSDB_CLICK, OnClick) 481 END_MSG_MAP() 482 }; 483 484 VOID CTrayShowDesktopButton::OnDraw(HDC hdc, LPRECT prc) 485 { 486 if (m_hTheme) 487 { 488 if (m_bHovering) // Draw a hot button 489 { 490 HTHEME hButtonTheme = ::OpenThemeData(m_hWnd, L"Button"); 491 ::DrawThemeBackground(hButtonTheme, hdc, BP_PUSHBUTTON, PBS_NORMAL, prc, prc); 492 ::CloseThemeData(hButtonTheme); 493 } 494 else // Draw a taskbar background 495 { 496 ::DrawThemeBackground(m_hTheme, hdc, TBP_BACKGROUNDTOP, 0, prc, prc); 497 } 498 } 499 else 500 { 501 RECT rc = *prc; 502 if (m_bHovering) // Draw a hot button 503 { 504 ::DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_ADJUSTRECT); 505 HBRUSH hbrHot = ::CreateSolidBrush(RGB(255, 255, 191)); 506 ::FillRect(hdc, &rc, hbrHot); 507 ::DeleteObject(hbrHot); 508 } 509 else // Draw a flattish button 510 { 511 ::DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONPUSH); 512 ::InflateRect(&rc, -1, -1); 513 ::FillRect(hdc, &rc, ::GetSysColorBrush(COLOR_3DFACE)); 514 } 515 } 516 } 517 518 class CTrayWindow : 519 public CComCoClass<CTrayWindow>, 520 public CComObjectRootEx<CComMultiThreadModelNoCS>, 521 public CWindowImpl < CTrayWindow, CWindow, CControlWinTraits >, 522 public ITrayWindow, 523 public IShellDesktopTray, 524 public IOleWindow, 525 public IContextMenu 526 { 527 CStartButton m_StartButton; 528 CTrayShowDesktopButton m_ShowDesktopButton; 529 530 CComPtr<IMenuBand> m_StartMenuBand; 531 CComPtr<IMenuPopup> m_StartMenuPopup; 532 533 CComPtr<IDeskBand> m_TaskBand; 534 CComPtr<IContextMenu> m_ContextMenu; 535 HTHEME m_Theme; 536 537 HFONT m_Font; 538 539 HWND m_DesktopWnd; 540 HWND m_Rebar; 541 HWND m_TaskSwitch; 542 HWND m_TrayNotify; 543 544 CComPtr<IUnknown> m_TrayNotifyInstance; 545 546 DWORD m_Position; 547 HMONITOR m_Monitor; 548 HMONITOR m_PreviousMonitor; 549 DWORD m_DraggingPosition; 550 HMONITOR m_DraggingMonitor; 551 552 RECT m_TrayRects[4]; 553 SIZE m_TraySize; 554 555 HWND m_TrayPropertiesOwner; 556 HWND m_RunFileDlgOwner; 557 558 UINT m_AutoHideState; 559 SIZE m_AutoHideOffset; 560 TRACKMOUSEEVENT m_MouseTrackingInfo; 561 562 HDPA m_ShellServices; 563 564 public: 565 CComPtr<ITrayBandSite> m_TrayBandSite; 566 567 union 568 { 569 DWORD Flags; 570 struct 571 { 572 /* UI Status */ 573 DWORD InSizeMove : 1; 574 DWORD IsDragging : 1; 575 DWORD NewPosSize : 1; 576 DWORD IgnorePulse : 1; 577 }; 578 }; 579 580 public: 581 CTrayWindow() : 582 m_StartButton(), 583 m_ShowDesktopButton(), 584 m_Theme(NULL), 585 m_Font(NULL), 586 m_DesktopWnd(NULL), 587 m_Rebar(NULL), 588 m_TaskSwitch(NULL), 589 m_TrayNotify(NULL), 590 m_Position(0), 591 m_Monitor(NULL), 592 m_PreviousMonitor(NULL), 593 m_DraggingPosition(0), 594 m_DraggingMonitor(NULL), 595 m_TrayPropertiesOwner(NULL), 596 m_RunFileDlgOwner(NULL), 597 m_AutoHideState(NULL), 598 m_ShellServices(NULL), 599 Flags(0) 600 { 601 ZeroMemory(&m_TrayRects, sizeof(m_TrayRects)); 602 ZeroMemory(&m_TraySize, sizeof(m_TraySize)); 603 ZeroMemory(&m_AutoHideOffset, sizeof(m_AutoHideOffset)); 604 ZeroMemory(&m_MouseTrackingInfo, sizeof(m_MouseTrackingInfo)); 605 IgnorePulse = TRUE; 606 } 607 608 virtual ~CTrayWindow() 609 { 610 if (m_ShellServices != NULL) 611 { 612 ShutdownShellServices(m_ShellServices); 613 m_ShellServices = NULL; 614 } 615 616 if (m_Font != NULL) 617 { 618 DeleteObject(m_Font); 619 m_Font = NULL; 620 } 621 622 if (m_Theme) 623 { 624 CloseThemeData(m_Theme); 625 m_Theme = NULL; 626 } 627 628 PostQuitMessage(0); 629 } 630 631 632 633 634 635 /********************************************************** 636 * ##### command handling ##### 637 */ 638 639 HRESULT ExecResourceCmd(int id) 640 { 641 WCHAR szCommand[256]; 642 WCHAR *pszParameters; 643 644 if (!LoadStringW(hExplorerInstance, 645 id, 646 szCommand, 647 _countof(szCommand))) 648 { 649 return E_FAIL; 650 } 651 652 pszParameters = wcschr(szCommand, L'>'); 653 if (pszParameters) 654 { 655 *pszParameters = 0; 656 pszParameters++; 657 } 658 659 ShellExecuteW(m_hWnd, NULL, szCommand, pszParameters, NULL, SW_SHOWNORMAL); 660 return S_OK; 661 } 662 663 LRESULT DoExitWindows() 664 { 665 /* Display the ReactOS Shutdown Dialog */ 666 ExitWindowsDialog(m_hWnd); 667 668 /* 669 * If the user presses CTRL+ALT+SHIFT while exiting 670 * the shutdown dialog, exit the shell cleanly. 671 */ 672 if ((GetKeyState(VK_CONTROL) & 0x8000) && 673 (GetKeyState(VK_SHIFT) & 0x8000) && 674 (GetKeyState(VK_MENU) & 0x8000)) 675 { 676 PostMessage(WM_QUIT, 0, 0); 677 } 678 return 0; 679 } 680 681 DWORD WINAPI RunFileDlgThread() 682 { 683 HWND hwnd; 684 RECT posRect; 685 686 m_StartButton.GetWindowRect(&posRect); 687 688 hwnd = CreateWindowEx(0, 689 WC_STATIC, 690 NULL, 691 WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, 692 posRect.left, 693 posRect.top, 694 posRect.right - posRect.left, 695 posRect.bottom - posRect.top, 696 NULL, 697 NULL, 698 NULL, 699 NULL); 700 701 m_RunFileDlgOwner = hwnd; 702 703 // build the default directory from two environment variables 704 CStringW strDefaultDir, strHomePath; 705 strDefaultDir.GetEnvironmentVariable(L"HOMEDRIVE"); 706 strHomePath.GetEnvironmentVariable(L"HOMEPATH"); 707 strDefaultDir += strHomePath; 708 709 RunFileDlg(hwnd, NULL, (LPCWSTR)strDefaultDir, NULL, NULL, RFF_CALCDIRECTORY); 710 711 m_RunFileDlgOwner = NULL; 712 ::DestroyWindow(hwnd); 713 714 return 0; 715 } 716 717 static DWORD WINAPI s_RunFileDlgThread(IN OUT PVOID pParam) 718 { 719 CTrayWindow * This = (CTrayWindow*) pParam; 720 return This->RunFileDlgThread(); 721 } 722 723 void DisplayRunFileDlg() 724 { 725 HWND hRunDlg; 726 if (m_RunFileDlgOwner) 727 { 728 hRunDlg = ::GetLastActivePopup(m_RunFileDlgOwner); 729 if (hRunDlg != NULL && 730 hRunDlg != m_RunFileDlgOwner) 731 { 732 SetForegroundWindow(hRunDlg); 733 return; 734 } 735 } 736 737 CloseHandle(CreateThread(NULL, 0, s_RunFileDlgThread, this, 0, NULL)); 738 } 739 740 DWORD WINAPI TrayPropertiesThread() 741 { 742 HWND hwnd; 743 RECT posRect; 744 745 m_StartButton.GetWindowRect(&posRect); 746 hwnd = CreateWindowEx(0, 747 WC_STATIC, 748 NULL, 749 WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, 750 posRect.left, 751 posRect.top, 752 posRect.right - posRect.left, 753 posRect.bottom - posRect.top, 754 NULL, 755 NULL, 756 NULL, 757 NULL); 758 759 m_TrayPropertiesOwner = hwnd; 760 761 DisplayTrayProperties(hwnd, m_hWnd); 762 763 m_TrayPropertiesOwner = NULL; 764 ::DestroyWindow(hwnd); 765 766 return 0; 767 } 768 769 static DWORD WINAPI s_TrayPropertiesThread(IN OUT PVOID pParam) 770 { 771 CTrayWindow *This = (CTrayWindow*) pParam; 772 773 return This->TrayPropertiesThread(); 774 } 775 776 HWND STDMETHODCALLTYPE DisplayProperties() 777 { 778 HWND hTrayProp; 779 780 if (m_TrayPropertiesOwner) 781 { 782 hTrayProp = ::GetLastActivePopup(m_TrayPropertiesOwner); 783 if (hTrayProp != NULL && 784 hTrayProp != m_TrayPropertiesOwner) 785 { 786 SetForegroundWindow(hTrayProp); 787 return NULL; 788 } 789 } 790 791 CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL)); 792 return NULL; 793 } 794 795 VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation) 796 { 797 WCHAR szDir[MAX_PATH]; 798 799 if (SHGetSpecialFolderPath(hWndOwner, 800 szDir, 801 CSIDL_COMMON_STARTMENU, 802 FALSE)) 803 { 804 ShellExecute(hWndOwner, 805 lpOperation, 806 szDir, 807 NULL, 808 NULL, 809 SW_SHOWNORMAL); 810 } 811 } 812 813 VOID OpenTaskManager(IN HWND hWndOwner) 814 { 815 ShellExecute(hWndOwner, 816 TEXT("open"), 817 TEXT("taskmgr.exe"), 818 NULL, 819 NULL, 820 SW_SHOWNORMAL); 821 } 822 823 VOID ToggleDesktop() 824 { 825 if (::IsThereAnyEffectiveWindow(TRUE)) 826 { 827 ShowDesktop(); 828 } 829 else 830 { 831 RestoreAll(); 832 } 833 } 834 835 BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd) 836 { 837 switch (uiCmd) 838 { 839 case ID_SHELL_CMD_PROPERTIES: 840 DisplayProperties(); 841 break; 842 843 case ID_SHELL_CMD_OPEN_ALL_USERS: 844 OpenCommonStartMenuDirectory(m_hWnd, 845 TEXT("open")); 846 break; 847 848 case ID_SHELL_CMD_EXPLORE_ALL_USERS: 849 OpenCommonStartMenuDirectory(m_hWnd, 850 TEXT("explore")); 851 break; 852 853 case ID_LOCKTASKBAR: 854 HandleCommand(TRAYCMD_LOCK_TASKBAR); 855 break; 856 857 case ID_SHELL_CMD_OPEN_TASKMGR: 858 OpenTaskManager(m_hWnd); 859 break; 860 861 case ID_SHELL_CMD_UNDO_ACTION: 862 RestoreWindowPos(); 863 break; 864 865 case ID_SHELL_CMD_SHOW_DESKTOP: 866 ShowDesktop(); 867 break; 868 869 case ID_SHELL_CMD_TILE_WND_H: 870 appbar_notify_all(NULL, ABN_WINDOWARRANGE, NULL, TRUE); 871 if (g_Arrangement == NONE) 872 { 873 BackupWindowPos(); 874 } 875 TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL); 876 appbar_notify_all(NULL, ABN_WINDOWARRANGE, NULL, FALSE); 877 g_Arrangement = TILED; 878 break; 879 880 case ID_SHELL_CMD_TILE_WND_V: 881 appbar_notify_all(NULL, ABN_WINDOWARRANGE, NULL, TRUE); 882 if (g_Arrangement == NONE) 883 { 884 BackupWindowPos(); 885 } 886 TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL); 887 appbar_notify_all(NULL, ABN_WINDOWARRANGE, NULL, FALSE); 888 g_Arrangement = TILED; 889 break; 890 891 case ID_SHELL_CMD_CASCADE_WND: 892 appbar_notify_all(NULL, ABN_WINDOWARRANGE, NULL, TRUE); 893 if (g_Arrangement == NONE) 894 { 895 BackupWindowPos(); 896 } 897 CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL); 898 appbar_notify_all(NULL, ABN_WINDOWARRANGE, NULL, FALSE); 899 g_Arrangement = CASCADED; 900 break; 901 902 case ID_SHELL_CMD_CUST_NOTIF: 903 ShowCustomizeNotifyIcons(hExplorerInstance, m_hWnd); 904 break; 905 906 case ID_SHELL_CMD_ADJUST_DAT: 907 //FIXME: Use SHRunControlPanel 908 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL); 909 break; 910 911 case ID_SHELL_CMD_RESTORE_ALL: 912 RestoreAll(); 913 break; 914 915 default: 916 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd); 917 return FALSE; 918 } 919 920 return TRUE; 921 } 922 923 VOID HideStartMenu() 924 { 925 m_StartMenuPopup->OnSelect(MPOS_CANCELLEVEL); 926 } 927 928 LRESULT HandleHotKey(DWORD id) 929 { 930 switch (id) 931 { 932 case IDHK_RUN: 933 HideStartMenu(); 934 DisplayRunFileDlg(); 935 break; 936 case IDHK_HELP: 937 ExecResourceCmd(IDS_HELP_COMMAND); 938 break; 939 case IDHK_EXPLORE: 940 //FIXME: We don't support this yet: 941 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1); 942 ShellExecuteW(0, NULL, L"explorer.exe", L"/e ,", NULL, 1); 943 break; 944 case IDHK_FIND: 945 SHFindFiles(NULL, NULL); 946 break; 947 case IDHK_FIND_COMPUTER: 948 SHFindComputer(NULL, NULL); 949 break; 950 case IDHK_SYS_PROPERTIES: 951 //FIXME: Use SHRunControlPanel 952 ShellExecuteW(m_hWnd, NULL, L"sysdm.cpl", NULL, NULL, SW_NORMAL); 953 break; 954 case IDHK_NEXT_TASK: 955 break; 956 case IDHK_PREV_TASK: 957 break; 958 case IDHK_MINIMIZE_ALL: 959 MinimizeAll(); 960 break; 961 case IDHK_RESTORE_ALL: 962 RestoreAll(); 963 break; 964 case IDHK_DESKTOP: 965 ToggleDesktop(); 966 break; 967 case IDHK_PAGER: 968 break; 969 } 970 971 return 0; 972 } 973 974 LRESULT HandleCommand(UINT uCommand) 975 { 976 switch (uCommand) 977 { 978 case TRAYCMD_STARTMENU: 979 // TODO: 980 break; 981 case TRAYCMD_RUN_DIALOG: 982 HideStartMenu(); 983 DisplayRunFileDlg(); 984 break; 985 case TRAYCMD_LOGOFF_DIALOG: 986 LogoffWindowsDialog(m_hWnd); // FIXME: Maybe handle it in a similar way as DoExitWindows? 987 break; 988 case TRAYCMD_CASCADE: 989 CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL); 990 break; 991 case TRAYCMD_TILE_H: 992 TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL); 993 break; 994 case TRAYCMD_TILE_V: 995 TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL); 996 break; 997 case TRAYCMD_TOGGLE_DESKTOP: 998 ToggleDesktop(); 999 break; 1000 case TRAYCMD_DATE_AND_TIME: 1001 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL); 1002 break; 1003 case TRAYCMD_TASKBAR_PROPERTIES: 1004 DisplayProperties(); 1005 break; 1006 case TRAYCMD_MINIMIZE_ALL: 1007 MinimizeAll(); 1008 break; 1009 case TRAYCMD_RESTORE_ALL: 1010 RestoreAll(); 1011 break; 1012 case TRAYCMD_SHOW_DESKTOP: 1013 ShowDesktop(); 1014 break; 1015 case TRAYCMD_SHOW_TASK_MGR: 1016 OpenTaskManager(m_hWnd); 1017 break; 1018 case TRAYCMD_CUSTOMIZE_TASKBAR: 1019 break; 1020 case TRAYCMD_LOCK_TASKBAR: 1021 if (SHRestricted(REST_CLASSICSHELL) == 0) 1022 { 1023 Lock(!g_TaskbarSettings.bLock); 1024 g_TaskbarSettings.Save(); 1025 } 1026 break; 1027 case TRAYCMD_HELP_AND_SUPPORT: 1028 ExecResourceCmd(IDS_HELP_COMMAND); 1029 break; 1030 case TRAYCMD_CONTROL_PANEL: 1031 // TODO: 1032 break; 1033 case TRAYCMD_SHUTDOWN_DIALOG: 1034 DoExitWindows(); 1035 break; 1036 case TRAYCMD_PRINTERS_AND_FAXES: 1037 // TODO: 1038 break; 1039 case TRAYCMD_LOCK_DESKTOP: 1040 // TODO: 1041 break; 1042 case TRAYCMD_SWITCH_USER_DIALOG: 1043 // TODO: 1044 break; 1045 case IDM_SEARCH: 1046 case TRAYCMD_SEARCH_FILES: 1047 SHFindFiles(NULL, NULL); 1048 break; 1049 case TRAYCMD_SEARCH_COMPUTERS: 1050 SHFindComputer(NULL, NULL); 1051 break; 1052 1053 default: 1054 break; 1055 } 1056 1057 return FALSE; 1058 } 1059 1060 1061 UINT TrackMenu( 1062 IN HMENU hMenu, 1063 IN POINT *ppt OPTIONAL, 1064 IN HWND hwndExclude OPTIONAL, 1065 IN BOOL TrackUp, 1066 IN BOOL IsContextMenu) 1067 { 1068 TPMPARAMS tmp, *ptmp = NULL; 1069 POINT pt; 1070 UINT cmdId; 1071 UINT fuFlags; 1072 1073 if (hwndExclude != NULL) 1074 { 1075 /* Get the client rectangle and map it to screen coordinates */ 1076 if (::GetClientRect(hwndExclude, 1077 &tmp.rcExclude) && 1078 ::MapWindowPoints(hwndExclude, 1079 NULL, 1080 (LPPOINT) &tmp.rcExclude, 1081 2) != 0) 1082 { 1083 ptmp = &tmp; 1084 } 1085 } 1086 1087 if (ppt == NULL) 1088 { 1089 if (ptmp == NULL && 1090 GetClientRect(&tmp.rcExclude) && 1091 MapWindowPoints( 1092 NULL, 1093 (LPPOINT) &tmp.rcExclude, 1094 2) != 0) 1095 { 1096 ptmp = &tmp; 1097 } 1098 1099 if (ptmp != NULL) 1100 { 1101 /* NOTE: TrackPopupMenuEx will eventually align the track position 1102 for us, no need to take care of it here as long as the 1103 coordinates are somewhere within the exclusion rectangle */ 1104 pt.x = ptmp->rcExclude.left; 1105 pt.y = ptmp->rcExclude.top; 1106 } 1107 else 1108 pt.x = pt.y = 0; 1109 } 1110 else 1111 pt = *ppt; 1112 1113 tmp.cbSize = sizeof(tmp); 1114 1115 fuFlags = TPM_RETURNCMD | TPM_VERTICAL; 1116 fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN); 1117 if (IsContextMenu) 1118 fuFlags |= TPM_RIGHTBUTTON; 1119 else 1120 fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION); 1121 1122 cmdId = TrackPopupMenuEx(hMenu, 1123 fuFlags, 1124 pt.x, 1125 pt.y, 1126 m_hWnd, 1127 ptmp); 1128 1129 return cmdId; 1130 } 1131 1132 HRESULT TrackCtxMenu( 1133 IN IContextMenu * contextMenu, 1134 IN POINT *ppt OPTIONAL, 1135 IN HWND hwndExclude OPTIONAL, 1136 IN BOOL TrackUp, 1137 IN PVOID Context OPTIONAL) 1138 { 1139 POINT pt; 1140 TPMPARAMS params; 1141 RECT rc; 1142 HRESULT hr; 1143 UINT uCommand; 1144 HMENU popup = CreatePopupMenu(); 1145 1146 if (popup == NULL) 1147 return E_FAIL; 1148 1149 if (ppt) 1150 { 1151 pt = *ppt; 1152 } 1153 else 1154 { 1155 ::GetWindowRect(m_hWnd, &rc); 1156 pt.x = rc.left; 1157 pt.y = rc.top; 1158 } 1159 1160 TRACE("Before Query\n"); 1161 hr = contextMenu->QueryContextMenu(popup, 0, 0, UINT_MAX, CMF_NORMAL); 1162 if (FAILED_UNEXPECTEDLY(hr)) 1163 { 1164 TRACE("Query failed\n"); 1165 DestroyMenu(popup); 1166 return hr; 1167 } 1168 1169 TRACE("Before Tracking\n"); 1170 ::SetForegroundWindow(m_hWnd); 1171 if (hwndExclude) 1172 { 1173 ::GetWindowRect(hwndExclude, &rc); 1174 ZeroMemory(¶ms, sizeof(params)); 1175 params.cbSize = sizeof(params); 1176 params.rcExclude = rc; 1177 uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, pt.x, pt.y, m_hWnd, ¶ms); 1178 } 1179 else 1180 { 1181 uCommand = ::TrackPopupMenuEx(popup, TPM_RETURNCMD, pt.x, pt.y, m_hWnd, NULL); 1182 } 1183 ::PostMessage(m_hWnd, WM_NULL, 0, 0); 1184 1185 if (uCommand != 0) 1186 { 1187 TRACE("Before InvokeCommand\n"); 1188 CMINVOKECOMMANDINFO cmi = { 0 }; 1189 cmi.cbSize = sizeof(cmi); 1190 cmi.lpVerb = MAKEINTRESOURCEA(uCommand); 1191 cmi.hwnd = m_hWnd; 1192 hr = contextMenu->InvokeCommand(&cmi); 1193 } 1194 else 1195 { 1196 TRACE("TrackPopupMenu failed. Code=%d, LastError=%d\n", uCommand, GetLastError()); 1197 hr = S_FALSE; 1198 } 1199 1200 DestroyMenu(popup); 1201 return hr; 1202 } 1203 1204 1205 1206 1207 1208 /********************************************************** 1209 * ##### moving and sizing handling ##### 1210 */ 1211 1212 void UpdateFonts() 1213 { 1214 /* There is nothing to do if themes are enabled */ 1215 if (m_Theme) 1216 return; 1217 1218 m_StartButton.UpdateFont(); 1219 1220 NONCLIENTMETRICS ncm = {sizeof(ncm)}; 1221 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE)) 1222 { 1223 ERR("SPI_GETNONCLIENTMETRICS failed\n"); 1224 return; 1225 } 1226 1227 if (m_Font != NULL) 1228 DeleteObject(m_Font); 1229 1230 ncm.lfCaptionFont.lfWeight = FW_NORMAL; 1231 m_Font = CreateFontIndirect(&ncm.lfCaptionFont); 1232 if (!m_Font) 1233 { 1234 ERR("CreateFontIndirect failed\n"); 1235 return; 1236 } 1237 1238 SendMessage(m_Rebar, WM_SETFONT, (WPARAM) m_Font, TRUE); 1239 SendMessage(m_TaskSwitch, WM_SETFONT, (WPARAM) m_Font, TRUE); 1240 SendMessage(m_TrayNotify, WM_SETFONT, (WPARAM) m_Font, TRUE); 1241 } 1242 1243 HMONITOR GetScreenRectFromRect( 1244 IN OUT RECT *pRect, 1245 IN DWORD dwFlags) 1246 { 1247 MONITORINFO mi; 1248 HMONITOR hMon; 1249 1250 mi.cbSize = sizeof(mi); 1251 hMon = MonitorFromRect(pRect, dwFlags); 1252 if (hMon != NULL && 1253 GetMonitorInfo(hMon, &mi)) 1254 { 1255 *pRect = mi.rcMonitor; 1256 } 1257 else 1258 { 1259 pRect->left = 0; 1260 pRect->top = 0; 1261 pRect->right = GetSystemMetrics(SM_CXSCREEN); 1262 pRect->bottom = GetSystemMetrics(SM_CYSCREEN); 1263 1264 hMon = NULL; 1265 } 1266 1267 return hMon; 1268 } 1269 1270 HMONITOR GetMonitorFromRect( 1271 IN const RECT *pRect) 1272 { 1273 HMONITOR hMon; 1274 1275 /* In case the monitor sizes or saved sizes differ a bit (probably 1276 not a lot, only so the tray window overlaps into another monitor 1277 now), minimize the risk that we determine a wrong monitor by 1278 using the center point of the tray window if we can't determine 1279 it using the rectangle. */ 1280 hMon = MonitorFromRect(pRect, MONITOR_DEFAULTTONULL); 1281 if (hMon == NULL) 1282 { 1283 POINT pt; 1284 1285 pt.x = pRect->left + ((pRect->right - pRect->left) / 2); 1286 pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2); 1287 1288 /* be less error-prone, find the nearest monitor */ 1289 hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); 1290 } 1291 1292 return hMon; 1293 } 1294 1295 HMONITOR GetScreenRect( 1296 IN HMONITOR hMonitor, 1297 IN OUT RECT *pRect) 1298 { 1299 HMONITOR hMon = NULL; 1300 1301 if (hMonitor != NULL) 1302 { 1303 MONITORINFO mi; 1304 1305 mi.cbSize = sizeof(mi); 1306 if (!GetMonitorInfo(hMonitor, &mi)) 1307 { 1308 /* Hm, the monitor is gone? Try to find a monitor where it 1309 could be located now */ 1310 hMon = GetMonitorFromRect(pRect); 1311 if (hMon == NULL || 1312 !GetMonitorInfo(hMon, &mi)) 1313 { 1314 hMon = NULL; 1315 goto GetPrimaryRect; 1316 } 1317 } 1318 1319 *pRect = mi.rcMonitor; 1320 } 1321 else 1322 { 1323 GetPrimaryRect: 1324 pRect->left = 0; 1325 pRect->top = 0; 1326 pRect->right = GetSystemMetrics(SM_CXSCREEN); 1327 pRect->bottom = GetSystemMetrics(SM_CYSCREEN); 1328 } 1329 1330 return hMon; 1331 } 1332 1333 VOID AdjustSizerRect(RECT *rc, DWORD pos) 1334 { 1335 int iSizerPart[4] = {TBP_SIZINGBARLEFT, TBP_SIZINGBARTOP, TBP_SIZINGBARRIGHT, TBP_SIZINGBARBOTTOM}; 1336 SIZE size; 1337 1338 if (pos > ABE_BOTTOM) 1339 pos = ABE_BOTTOM; 1340 1341 HRESULT hr = GetThemePartSize(m_Theme, NULL, iSizerPart[pos], 0, NULL, TS_TRUE, &size); 1342 if (FAILED_UNEXPECTEDLY(hr)) 1343 return; 1344 1345 switch (pos) 1346 { 1347 case ABE_TOP: 1348 rc->bottom -= size.cy; 1349 break; 1350 case ABE_BOTTOM: 1351 rc->top += size.cy; 1352 break; 1353 case ABE_LEFT: 1354 rc->right -= size.cx; 1355 break; 1356 case ABE_RIGHT: 1357 rc->left += size.cx; 1358 break; 1359 } 1360 } 1361 1362 VOID MakeTrayRectWithSize(IN DWORD Position, 1363 IN const SIZE *pTraySize, 1364 IN OUT RECT *pRect) 1365 { 1366 switch (Position) 1367 { 1368 case ABE_LEFT: 1369 pRect->right = pRect->left + pTraySize->cx; 1370 break; 1371 1372 case ABE_TOP: 1373 pRect->bottom = pRect->top + pTraySize->cy; 1374 break; 1375 1376 case ABE_RIGHT: 1377 pRect->left = pRect->right - pTraySize->cx; 1378 break; 1379 1380 case ABE_BOTTOM: 1381 default: 1382 pRect->top = pRect->bottom - pTraySize->cy; 1383 break; 1384 } 1385 } 1386 1387 VOID GetTrayRectFromScreenRect(IN DWORD Position, 1388 IN const RECT *pScreen, 1389 IN const SIZE *pTraySize OPTIONAL, 1390 OUT RECT *pRect) 1391 { 1392 if (pTraySize == NULL) 1393 pTraySize = &m_TraySize; 1394 1395 *pRect = *pScreen; 1396 1397 if(!m_Theme) 1398 { 1399 /* Move the border outside of the screen */ 1400 InflateRect(pRect, 1401 GetSystemMetrics(SM_CXEDGE), 1402 GetSystemMetrics(SM_CYEDGE)); 1403 } 1404 1405 MakeTrayRectWithSize(Position, pTraySize, pRect); 1406 } 1407 1408 BOOL IsPosHorizontal() 1409 { 1410 return m_Position == ABE_TOP || m_Position == ABE_BOTTOM; 1411 } 1412 1413 HMONITOR CalculateValidSize( 1414 IN DWORD Position, 1415 IN OUT RECT *pRect) 1416 { 1417 RECT rcScreen; 1418 //BOOL Horizontal; 1419 HMONITOR hMon; 1420 SIZE szMax, szWnd; 1421 1422 //Horizontal = IsPosHorizontal(); 1423 1424 szWnd.cx = pRect->right - pRect->left; 1425 szWnd.cy = pRect->bottom - pRect->top; 1426 1427 rcScreen = *pRect; 1428 hMon = GetScreenRectFromRect( 1429 &rcScreen, 1430 MONITOR_DEFAULTTONEAREST); 1431 1432 /* Calculate the maximum size of the tray window and limit the window 1433 size to half of the screen's size. */ 1434 szMax.cx = (rcScreen.right - rcScreen.left) / 2; 1435 szMax.cy = (rcScreen.bottom - rcScreen.top) / 2; 1436 if (szWnd.cx > szMax.cx) 1437 szWnd.cx = szMax.cx; 1438 if (szWnd.cy > szMax.cy) 1439 szWnd.cy = szMax.cy; 1440 1441 /* FIXME - calculate */ 1442 1443 GetTrayRectFromScreenRect(Position, 1444 &rcScreen, 1445 &szWnd, 1446 pRect); 1447 1448 return hMon; 1449 } 1450 1451 #if 0 1452 VOID 1453 GetMinimumWindowSize( 1454 OUT RECT *pRect) 1455 { 1456 RECT rcMin = {0}; 1457 1458 AdjustWindowRectEx(&rcMin, 1459 GetWindowLong(m_hWnd, 1460 GWL_STYLE), 1461 FALSE, 1462 GetWindowLong(m_hWnd, 1463 GWL_EXSTYLE)); 1464 1465 *pRect = rcMin; 1466 } 1467 #endif 1468 1469 1470 DWORD GetDraggingRectFromPt( 1471 IN POINT pt, 1472 OUT RECT *pRect, 1473 OUT HMONITOR *phMonitor) 1474 { 1475 HMONITOR hMon, hMonNew; 1476 DWORD PosH, PosV, Pos; 1477 SIZE DeltaPt, ScreenOffset; 1478 RECT rcScreen; 1479 1480 rcScreen.left = 0; 1481 rcScreen.top = 0; 1482 1483 /* Determine the screen rectangle */ 1484 hMon = MonitorFromPoint(pt, MONITOR_DEFAULTTONULL); 1485 if (hMon != NULL) 1486 { 1487 MONITORINFO mi; 1488 1489 mi.cbSize = sizeof(mi); 1490 if (!GetMonitorInfo(hMon, &mi)) 1491 { 1492 hMon = NULL; 1493 goto GetPrimaryScreenRect; 1494 } 1495 1496 /* make left top corner of the screen zero based to 1497 make calculations easier */ 1498 pt.x -= mi.rcMonitor.left; 1499 pt.y -= mi.rcMonitor.top; 1500 1501 ScreenOffset.cx = mi.rcMonitor.left; 1502 ScreenOffset.cy = mi.rcMonitor.top; 1503 rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left; 1504 rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top; 1505 } 1506 else 1507 { 1508 GetPrimaryScreenRect: 1509 ScreenOffset.cx = 0; 1510 ScreenOffset.cy = 0; 1511 rcScreen.right = GetSystemMetrics(SM_CXSCREEN); 1512 rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN); 1513 } 1514 1515 /* Calculate the nearest screen border */ 1516 if (pt.x < rcScreen.right / 2) 1517 { 1518 DeltaPt.cx = pt.x; 1519 PosH = ABE_LEFT; 1520 } 1521 else 1522 { 1523 DeltaPt.cx = rcScreen.right - pt.x; 1524 PosH = ABE_RIGHT; 1525 } 1526 1527 if (pt.y < rcScreen.bottom / 2) 1528 { 1529 DeltaPt.cy = pt.y; 1530 PosV = ABE_TOP; 1531 } 1532 else 1533 { 1534 DeltaPt.cy = rcScreen.bottom - pt.y; 1535 PosV = ABE_BOTTOM; 1536 } 1537 1538 Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV; 1539 1540 /* Fix the screen origin to be relative to the primary monitor again */ 1541 OffsetRect(&rcScreen, 1542 ScreenOffset.cx, 1543 ScreenOffset.cy); 1544 1545 RECT rcPos = m_TrayRects[Pos]; 1546 1547 hMonNew = GetMonitorFromRect(&rcPos); 1548 if (hMon != hMonNew) 1549 { 1550 SIZE szTray; 1551 1552 /* Recalculate the rectangle, we're dragging to another monitor. 1553 We don't need to recalculate the rect on single monitor systems. */ 1554 szTray.cx = rcPos.right - rcPos.left; 1555 szTray.cy = rcPos.bottom - rcPos.top; 1556 1557 GetTrayRectFromScreenRect(Pos, &rcScreen, &szTray, pRect); 1558 hMon = hMonNew; 1559 } 1560 else 1561 { 1562 /* The user is dragging the tray window on the same monitor. We don't need 1563 to recalculate the rectangle */ 1564 *pRect = rcPos; 1565 } 1566 1567 *phMonitor = hMon; 1568 1569 return Pos; 1570 } 1571 1572 DWORD GetDraggingRectFromRect( 1573 IN OUT RECT *pRect, 1574 OUT HMONITOR *phMonitor) 1575 { 1576 POINT pt; 1577 1578 /* Calculate the center of the rectangle. We call 1579 GetDraggingRectFromPt to calculate a valid 1580 dragging rectangle */ 1581 pt.x = pRect->left + ((pRect->right - pRect->left) / 2); 1582 pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2); 1583 1584 return GetDraggingRectFromPt( 1585 pt, 1586 pRect, 1587 phMonitor); 1588 } 1589 1590 VOID ChangingWinPos(IN OUT LPWINDOWPOS pwp) 1591 { 1592 RECT rcTray; 1593 1594 if (IsDragging) 1595 { 1596 rcTray.left = pwp->x; 1597 rcTray.top = pwp->y; 1598 rcTray.right = rcTray.left + pwp->cx; 1599 rcTray.bottom = rcTray.top + pwp->cy; 1600 1601 if (!EqualRect(&rcTray, 1602 &m_TrayRects[m_DraggingPosition])) 1603 { 1604 /* Recalculate the rectangle, the user dragged the tray 1605 window to another monitor or the window was somehow else 1606 moved or resized */ 1607 m_DraggingPosition = GetDraggingRectFromRect( 1608 &rcTray, 1609 &m_DraggingMonitor); 1610 //m_TrayRects[DraggingPosition] = rcTray; 1611 } 1612 1613 //Monitor = CalculateValidSize(DraggingPosition, 1614 // &rcTray); 1615 1616 m_Monitor = m_DraggingMonitor; 1617 m_Position = m_DraggingPosition; 1618 g_TaskbarSettings.sr.Position = m_Position; 1619 g_TaskbarSettings.Save(); 1620 IsDragging = FALSE; 1621 1622 m_TrayRects[m_Position] = rcTray; 1623 goto ChangePos; 1624 } 1625 else if (GetWindowRect(&rcTray)) 1626 { 1627 if (InSizeMove) 1628 { 1629 if (!(pwp->flags & SWP_NOMOVE)) 1630 { 1631 rcTray.left = pwp->x; 1632 rcTray.top = pwp->y; 1633 } 1634 1635 if (!(pwp->flags & SWP_NOSIZE)) 1636 { 1637 rcTray.right = rcTray.left + pwp->cx; 1638 rcTray.bottom = rcTray.top + pwp->cy; 1639 } 1640 1641 m_Position = GetDraggingRectFromRect(&rcTray, &m_Monitor); 1642 1643 if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE))) 1644 { 1645 SIZE szWnd; 1646 1647 szWnd.cx = pwp->cx; 1648 szWnd.cy = pwp->cy; 1649 1650 MakeTrayRectWithSize(m_Position, &szWnd, &rcTray); 1651 } 1652 1653 m_TrayRects[m_Position] = rcTray; 1654 } 1655 else if (m_Position != (DWORD)-1) 1656 { 1657 /* If the user isn't resizing the tray window we need to make sure the 1658 new size or position is valid. this is to prevent changes to the window 1659 without user interaction. */ 1660 rcTray = m_TrayRects[m_Position]; 1661 1662 if (g_TaskbarSettings.sr.AutoHide) 1663 { 1664 rcTray.left += m_AutoHideOffset.cx; 1665 rcTray.right += m_AutoHideOffset.cx; 1666 rcTray.top += m_AutoHideOffset.cy; 1667 rcTray.bottom += m_AutoHideOffset.cy; 1668 } 1669 1670 } 1671 1672 ChangePos: 1673 m_TraySize.cx = rcTray.right - rcTray.left; 1674 m_TraySize.cy = rcTray.bottom - rcTray.top; 1675 1676 pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE); 1677 pwp->x = rcTray.left; 1678 pwp->y = rcTray.top; 1679 pwp->cx = m_TraySize.cx; 1680 pwp->cy = m_TraySize.cy; 1681 } 1682 } 1683 1684 VOID ApplyClipping(IN BOOL Clip) 1685 { 1686 RECT rcClip, rcWindow; 1687 HRGN hClipRgn; 1688 1689 if (GetWindowRect(&rcWindow)) 1690 { 1691 /* Disable clipping on systems with only one monitor */ 1692 if (GetSystemMetrics(SM_CMONITORS) <= 1) 1693 Clip = FALSE; 1694 1695 if (Clip) 1696 { 1697 rcClip = rcWindow; 1698 1699 GetScreenRect(m_Monitor, &rcClip); 1700 1701 if (!IntersectRect(&rcClip, &rcClip, &rcWindow)) 1702 { 1703 rcClip = rcWindow; 1704 } 1705 1706 OffsetRect(&rcClip, 1707 -rcWindow.left, 1708 -rcWindow.top); 1709 1710 hClipRgn = CreateRectRgnIndirect(&rcClip); 1711 } 1712 else 1713 hClipRgn = NULL; 1714 1715 /* Set the clipping region or make sure the window isn't clipped 1716 by disabling it explicitly. */ 1717 SetWindowRgn(hClipRgn, TRUE); 1718 } 1719 } 1720 1721 VOID ResizeWorkArea() 1722 { 1723 #if !WIN7_DEBUG_MODE 1724 RECT rcTray, rcWorkArea; 1725 1726 /* If monitor has changed then fix the previous monitors work area */ 1727 if (m_PreviousMonitor != m_Monitor) 1728 { 1729 GetScreenRect(m_PreviousMonitor, &rcWorkArea); 1730 SystemParametersInfoW(SPI_SETWORKAREA, 1731 1, 1732 &rcWorkArea, 1733 SPIF_SENDCHANGE); 1734 } 1735 1736 rcTray = m_TrayRects[m_Position]; 1737 1738 GetScreenRect(m_Monitor, &rcWorkArea); 1739 m_PreviousMonitor = m_Monitor; 1740 1741 /* If AutoHide is false then change the workarea to exclude 1742 the area that the taskbar covers. */ 1743 if (!g_TaskbarSettings.sr.AutoHide) 1744 { 1745 switch (m_Position) 1746 { 1747 case ABE_TOP: 1748 rcWorkArea.top = rcTray.bottom; 1749 break; 1750 case ABE_LEFT: 1751 rcWorkArea.left = rcTray.right; 1752 break; 1753 case ABE_RIGHT: 1754 rcWorkArea.right = rcTray.left; 1755 break; 1756 case ABE_BOTTOM: 1757 rcWorkArea.bottom = rcTray.top; 1758 break; 1759 } 1760 } 1761 1762 /* 1763 * Resize the current monitor work area. Win32k will also send 1764 * a WM_SIZE message to automatically resize the desktop. 1765 */ 1766 SystemParametersInfoW(SPI_SETWORKAREA, 1767 1, 1768 &rcWorkArea, 1769 SPIF_SENDCHANGE); 1770 #endif 1771 } 1772 1773 VOID CheckTrayWndPosition() 1774 { 1775 /* Force the rebar bands to resize */ 1776 IUnknown_Exec(m_TrayBandSite, 1777 IID_IDeskBand, 1778 DBID_BANDINFOCHANGED, 1779 0, 1780 NULL, 1781 NULL); 1782 1783 /* Calculate the size of the taskbar based on the rebar */ 1784 FitToRebar(&m_TrayRects[m_Position]); 1785 1786 /* Move the tray window */ 1787 /* The handler of WM_WINDOWPOSCHANGING will override whatever size 1788 * and position we use here with m_TrayRects */ 1789 SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE); 1790 ResizeWorkArea(); 1791 ApplyClipping(TRUE); 1792 } 1793 1794 VOID RegLoadSettings() 1795 { 1796 DWORD Pos; 1797 RECT rcScreen; 1798 SIZE WndSize, EdgeSize, DlgFrameSize; 1799 SIZE StartBtnSize = m_StartButton.GetSize(); 1800 1801 EdgeSize.cx = GetSystemMetrics(SM_CXEDGE); 1802 EdgeSize.cy = GetSystemMetrics(SM_CYEDGE); 1803 DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME); 1804 DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME); 1805 1806 m_Position = g_TaskbarSettings.sr.Position; 1807 rcScreen = g_TaskbarSettings.sr.Rect; 1808 GetScreenRectFromRect(&rcScreen, MONITOR_DEFAULTTONEAREST); 1809 1810 if (!g_TaskbarSettings.sr.Size.cx || !g_TaskbarSettings.sr.Size.cy) 1811 { 1812 /* Use the minimum size of the taskbar, we'll use the start 1813 button as a minimum for now. Make sure we calculate the 1814 entire window size, not just the client size. However, we 1815 use a thinner border than a standard thick border, so that 1816 the start button and bands are not stuck to the screen border. */ 1817 if(!m_Theme) 1818 { 1819 g_TaskbarSettings.sr.Size.cx = StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx)); 1820 g_TaskbarSettings.sr.Size.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy)); 1821 } 1822 else 1823 { 1824 g_TaskbarSettings.sr.Size.cx = StartBtnSize.cx - EdgeSize.cx; 1825 g_TaskbarSettings.sr.Size.cy = StartBtnSize.cy - EdgeSize.cy; 1826 if(!g_TaskbarSettings.bLock) 1827 g_TaskbarSettings.sr.Size.cy += GetSystemMetrics(SM_CYSIZEFRAME); 1828 } 1829 } 1830 /* Determine a minimum tray window rectangle. The "client" height is 1831 zero here since we cannot determine an optimal minimum width when 1832 loaded as a vertical tray window. We just need to make sure the values 1833 loaded from the registry are at least. The windows explorer behaves 1834 the same way, it allows the user to save a zero width vertical tray 1835 window, but not a zero height horizontal tray window. */ 1836 if(!m_Theme) 1837 { 1838 WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx); 1839 WndSize.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy)); 1840 } 1841 else 1842 { 1843 WndSize.cx = StartBtnSize.cx; 1844 WndSize.cy = StartBtnSize.cy - EdgeSize.cy; 1845 } 1846 1847 if (WndSize.cx < g_TaskbarSettings.sr.Size.cx) 1848 WndSize.cx = g_TaskbarSettings.sr.Size.cx; 1849 if (WndSize.cy < g_TaskbarSettings.sr.Size.cy) 1850 WndSize.cy = g_TaskbarSettings.sr.Size.cy; 1851 1852 /* Save the calculated size */ 1853 m_TraySize = WndSize; 1854 1855 /* Calculate all docking rectangles. We need to do this here so they're 1856 initialized and dragging the tray window to another position gives 1857 usable results */ 1858 for (Pos = ABE_LEFT; Pos <= ABE_BOTTOM; Pos++) 1859 { 1860 GetTrayRectFromScreenRect(Pos, 1861 &rcScreen, 1862 &m_TraySize, 1863 &m_TrayRects[Pos]); 1864 // 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); 1865 } 1866 1867 /* Determine which monitor we are on. It shouldn't matter which docked 1868 position rectangle we use */ 1869 m_Monitor = GetMonitorFromRect(&m_TrayRects[ABE_LEFT]); 1870 } 1871 1872 VOID AlignControls(IN PRECT prcClient OPTIONAL) 1873 { 1874 RECT rcClient; 1875 SIZE TraySize, StartSize; 1876 POINT ptTrayNotify = { 0, 0 }; 1877 BOOL Horizontal; 1878 HDWP dwp; 1879 1880 m_StartButton.UpdateSize(); 1881 if (prcClient != NULL) 1882 { 1883 rcClient = *prcClient; 1884 } 1885 else 1886 { 1887 if (!GetClientRect(&rcClient)) 1888 { 1889 ERR("Could not get client rect lastErr=%d\n", GetLastError()); 1890 return; 1891 } 1892 } 1893 1894 Horizontal = IsPosHorizontal(); 1895 1896 /* We're about to resize/move the start button, the rebar control and 1897 the tray notification control */ 1898 dwp = BeginDeferWindowPos(4); 1899 if (dwp == NULL) 1900 { 1901 ERR("BeginDeferWindowPos failed. lastErr=%d\n", GetLastError()); 1902 return; 1903 } 1904 1905 /* Limit the Start button width to the client width, if necessary */ 1906 StartSize = m_StartButton.GetSize(); 1907 if (StartSize.cx > rcClient.right) 1908 StartSize.cx = rcClient.right; 1909 1910 HWND hwndTaskToolbar = ::GetWindow(m_TaskSwitch, GW_CHILD); 1911 if (hwndTaskToolbar) 1912 { 1913 DWORD size = SendMessageW(hwndTaskToolbar, TB_GETBUTTONSIZE, 0, 0); 1914 1915 /* Themed button covers Edge area as well */ 1916 StartSize.cy = HIWORD(size) + (m_Theme ? GetSystemMetrics(SM_CYEDGE) : 0); 1917 } 1918 1919 if (m_StartButton.m_hWnd != NULL) 1920 { 1921 /* Resize and reposition the button */ 1922 dwp = m_StartButton.DeferWindowPos(dwp, 1923 NULL, 1924 0, 1925 0, 1926 StartSize.cx, 1927 StartSize.cy, 1928 SWP_NOZORDER | SWP_NOACTIVATE); 1929 if (dwp == NULL) 1930 { 1931 ERR("DeferWindowPos for start button failed. lastErr=%d\n", GetLastError()); 1932 return; 1933 } 1934 } 1935 1936 if (m_ShowDesktopButton.m_hWnd) 1937 { 1938 // Get rectangle from rcClient 1939 RECT rc = rcClient; 1940 INT cxyShowDesktop = m_ShowDesktopButton.WidthOrHeight(); 1941 if (Horizontal) 1942 { 1943 rc.left = rc.right - cxyShowDesktop; 1944 rc.right += 5; // excessive 1945 } 1946 else 1947 { 1948 rc.top = rc.bottom - cxyShowDesktop; 1949 rc.bottom += 5; // excessive 1950 } 1951 1952 /* Resize and reposition the button */ 1953 dwp = m_ShowDesktopButton.DeferWindowPos(dwp, NULL, 1954 rc.left, rc.top, 1955 rc.right - rc.left, rc.bottom - rc.top, 1956 SWP_NOZORDER | SWP_NOACTIVATE); 1957 1958 // Adjust rcClient 1959 if (Horizontal) 1960 rcClient.right -= cxyShowDesktop + ::GetSystemMetrics(SM_CXEDGE); 1961 else 1962 rcClient.bottom -= cxyShowDesktop + ::GetSystemMetrics(SM_CYEDGE); 1963 } 1964 1965 /* Determine the size that the tray notification window needs */ 1966 if (Horizontal) 1967 { 1968 TraySize.cx = 0; 1969 TraySize.cy = rcClient.bottom; 1970 } 1971 else 1972 { 1973 TraySize.cx = rcClient.right; 1974 TraySize.cy = 0; 1975 } 1976 1977 if (m_TrayNotify != NULL && 1978 SendMessage(m_TrayNotify, 1979 TNWM_GETMINIMUMSIZE, 1980 (WPARAM)Horizontal, 1981 (LPARAM)&TraySize)) 1982 { 1983 /* Move the tray notification window to the desired location */ 1984 if (Horizontal) 1985 ptTrayNotify.x = rcClient.right - TraySize.cx; 1986 else 1987 ptTrayNotify.y = rcClient.bottom - TraySize.cy; 1988 1989 dwp = ::DeferWindowPos(dwp, 1990 m_TrayNotify, 1991 NULL, 1992 ptTrayNotify.x, 1993 ptTrayNotify.y, 1994 TraySize.cx, 1995 TraySize.cy, 1996 SWP_NOZORDER | SWP_NOACTIVATE); 1997 if (dwp == NULL) 1998 { 1999 ERR("DeferWindowPos for notification area failed. lastErr=%d\n", GetLastError()); 2000 return; 2001 } 2002 } 2003 2004 /* Resize/Move the rebar control */ 2005 if (m_Rebar != NULL) 2006 { 2007 POINT ptRebar = { 0, 0 }; 2008 SIZE szRebar; 2009 2010 SetWindowStyle(m_Rebar, CCS_VERT, Horizontal ? 0 : CCS_VERT); 2011 2012 if (Horizontal) 2013 { 2014 ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME); 2015 szRebar.cx = ptTrayNotify.x - ptRebar.x; 2016 szRebar.cy = rcClient.bottom; 2017 } 2018 else 2019 { 2020 ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME); 2021 szRebar.cx = rcClient.right; 2022 szRebar.cy = ptTrayNotify.y - ptRebar.y; 2023 } 2024 2025 dwp = ::DeferWindowPos(dwp, 2026 m_Rebar, 2027 NULL, 2028 ptRebar.x, 2029 ptRebar.y, 2030 szRebar.cx, 2031 szRebar.cy, 2032 SWP_NOZORDER | SWP_NOACTIVATE); 2033 } 2034 2035 if (dwp != NULL) 2036 EndDeferWindowPos(dwp); 2037 2038 if (m_TaskSwitch != NULL) 2039 { 2040 /* Update the task switch window configuration */ 2041 SendMessage(m_TaskSwitch, TSWM_UPDATETASKBARPOS, 0, 0); 2042 } 2043 } 2044 2045 void FitToRebar(PRECT pRect) 2046 { 2047 /* Get the rect of the rebar */ 2048 RECT rebarRect, taskbarRect, clientRect; 2049 ::GetWindowRect(m_Rebar, &rebarRect); 2050 ::GetWindowRect(m_hWnd, &taskbarRect); 2051 ::GetClientRect(m_hWnd, &clientRect); 2052 OffsetRect(&rebarRect, -taskbarRect.left, -taskbarRect.top); 2053 2054 /* Calculate the difference of size of the taskbar and the rebar */ 2055 SIZE margins; 2056 margins.cx = taskbarRect.right - taskbarRect.left - clientRect.right + clientRect.left; 2057 margins.cy = taskbarRect.bottom - taskbarRect.top - clientRect.bottom + clientRect.top; 2058 2059 /* Calculate the new size of the rebar and make it resize, then change the new taskbar size */ 2060 switch (m_Position) 2061 { 2062 case ABE_TOP: 2063 rebarRect.bottom = rebarRect.top + pRect->bottom - pRect->top - margins.cy; 2064 ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT, (LPARAM)&rebarRect); 2065 pRect->bottom = pRect->top + rebarRect.bottom - rebarRect.top + margins.cy; 2066 break; 2067 case ABE_BOTTOM: 2068 rebarRect.top = rebarRect.bottom - (pRect->bottom - pRect->top - margins.cy); 2069 ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT, (LPARAM)&rebarRect); 2070 pRect->top = pRect->bottom - (rebarRect.bottom - rebarRect.top + margins.cy); 2071 break; 2072 case ABE_LEFT: 2073 rebarRect.right = rebarRect.left + (pRect->right - pRect->left - margins.cx); 2074 ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT, (LPARAM)&rebarRect); 2075 pRect->right = pRect->left + (rebarRect.right - rebarRect.left + margins.cx); 2076 break; 2077 case ABE_RIGHT: 2078 rebarRect.left = rebarRect.right - (pRect->right - pRect->left - margins.cx); 2079 ::SendMessageW(m_Rebar, RB_SIZETORECT, RBSTR_CHANGERECT, (LPARAM)&rebarRect); 2080 pRect->left = pRect->right - (rebarRect.right - rebarRect.left + margins.cx); 2081 break; 2082 } 2083 2084 CalculateValidSize(m_Position, pRect); 2085 } 2086 2087 void PopupStartMenu() 2088 { 2089 if (m_StartMenuPopup != NULL) 2090 { 2091 POINTL pt; 2092 RECTL rcExclude; 2093 DWORD dwFlags = 0; 2094 2095 if (m_StartButton.GetWindowRect((RECT*) &rcExclude)) 2096 { 2097 switch (m_Position) 2098 { 2099 case ABE_BOTTOM: 2100 pt.x = rcExclude.left; 2101 pt.y = rcExclude.top; 2102 dwFlags |= MPPF_TOP; 2103 break; 2104 case ABE_TOP: 2105 pt.x = rcExclude.left; 2106 pt.y = rcExclude.bottom; 2107 dwFlags |= MPPF_BOTTOM; 2108 break; 2109 case ABE_LEFT: 2110 pt.x = rcExclude.right; 2111 pt.y = rcExclude.top; 2112 dwFlags |= MPPF_RIGHT; 2113 break; 2114 case ABE_RIGHT: 2115 pt.x = rcExclude.left; 2116 pt.y = rcExclude.top; 2117 dwFlags |= MPPF_LEFT; 2118 break; 2119 } 2120 2121 m_StartMenuPopup->Popup(&pt, &rcExclude, dwFlags); 2122 2123 m_StartButton.SendMessageW(BM_SETSTATE, TRUE, 0); 2124 } 2125 } 2126 } 2127 2128 void ProcessMouseTracking() 2129 { 2130 RECT rcCurrent; 2131 POINT pt; 2132 BOOL over; 2133 UINT state = m_AutoHideState; 2134 2135 GetCursorPos(&pt); 2136 GetWindowRect(&rcCurrent); 2137 over = PtInRect(&rcCurrent, pt); 2138 2139 if (m_StartButton.SendMessage( BM_GETSTATE, 0, 0) != BST_UNCHECKED) 2140 { 2141 over = TRUE; 2142 } 2143 2144 if (over) 2145 { 2146 if (state == AUTOHIDE_HIDING) 2147 { 2148 TRACE("AutoHide cancelling hide.\n"); 2149 m_AutoHideState = AUTOHIDE_SHOWING; 2150 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); 2151 } 2152 else if (state == AUTOHIDE_HIDDEN) 2153 { 2154 TRACE("AutoHide starting show.\n"); 2155 m_AutoHideState = AUTOHIDE_SHOWING; 2156 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL); 2157 } 2158 } 2159 else 2160 { 2161 if (state == AUTOHIDE_SHOWING) 2162 { 2163 TRACE("AutoHide cancelling show.\n"); 2164 m_AutoHideState = AUTOHIDE_HIDING; 2165 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); 2166 } 2167 else if (state == AUTOHIDE_SHOWN) 2168 { 2169 TRACE("AutoHide starting hide.\n"); 2170 m_AutoHideState = AUTOHIDE_HIDING; 2171 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL); 2172 } 2173 2174 KillTimer(TIMER_ID_MOUSETRACK); 2175 } 2176 } 2177 2178 void ProcessAutoHide() 2179 { 2180 INT w = m_TraySize.cx - GetSystemMetrics(SM_CXSIZEFRAME); 2181 INT h = m_TraySize.cy - GetSystemMetrics(SM_CYSIZEFRAME); 2182 2183 switch (m_AutoHideState) 2184 { 2185 case AUTOHIDE_HIDING: 2186 switch (m_Position) 2187 { 2188 case ABE_LEFT: 2189 m_AutoHideOffset.cy = 0; 2190 m_AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE; 2191 if (m_AutoHideOffset.cx < -w) 2192 m_AutoHideOffset.cx = w; 2193 break; 2194 case ABE_TOP: 2195 m_AutoHideOffset.cx = 0; 2196 m_AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE; 2197 if (m_AutoHideOffset.cy < -h) 2198 m_AutoHideOffset.cy = h; 2199 break; 2200 case ABE_RIGHT: 2201 m_AutoHideOffset.cy = 0; 2202 m_AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE; 2203 if (m_AutoHideOffset.cx > w) 2204 m_AutoHideOffset.cx = w; 2205 break; 2206 case ABE_BOTTOM: 2207 m_AutoHideOffset.cx = 0; 2208 m_AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE; 2209 if (m_AutoHideOffset.cy > h) 2210 m_AutoHideOffset.cy = h; 2211 break; 2212 } 2213 2214 if (m_AutoHideOffset.cx != w && m_AutoHideOffset.cy != h) 2215 { 2216 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); 2217 break; 2218 } 2219 2220 /* fallthrough */ 2221 case AUTOHIDE_HIDDEN: 2222 2223 switch (m_Position) 2224 { 2225 case ABE_LEFT: 2226 m_AutoHideOffset.cx = -w; 2227 m_AutoHideOffset.cy = 0; 2228 break; 2229 case ABE_TOP: 2230 m_AutoHideOffset.cx = 0; 2231 m_AutoHideOffset.cy = -h; 2232 break; 2233 case ABE_RIGHT: 2234 m_AutoHideOffset.cx = w; 2235 m_AutoHideOffset.cy = 0; 2236 break; 2237 case ABE_BOTTOM: 2238 m_AutoHideOffset.cx = 0; 2239 m_AutoHideOffset.cy = h; 2240 break; 2241 } 2242 2243 KillTimer(TIMER_ID_AUTOHIDE); 2244 m_AutoHideState = AUTOHIDE_HIDDEN; 2245 break; 2246 2247 case AUTOHIDE_SHOWING: 2248 if (m_AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW) 2249 { 2250 m_AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW; 2251 } 2252 else if (m_AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW) 2253 { 2254 m_AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW; 2255 } 2256 else 2257 { 2258 m_AutoHideOffset.cx = 0; 2259 } 2260 2261 if (m_AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW) 2262 { 2263 m_AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW; 2264 } 2265 else if (m_AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW) 2266 { 2267 m_AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW; 2268 } 2269 else 2270 { 2271 m_AutoHideOffset.cy = 0; 2272 } 2273 2274 if (m_AutoHideOffset.cx != 0 || m_AutoHideOffset.cy != 0) 2275 { 2276 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL); 2277 break; 2278 } 2279 2280 /* fallthrough */ 2281 case AUTOHIDE_SHOWN: 2282 2283 KillTimer(TIMER_ID_AUTOHIDE); 2284 m_AutoHideState = AUTOHIDE_SHOWN; 2285 break; 2286 } 2287 2288 SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER); 2289 } 2290 2291 2292 2293 2294 2295 /********************************************************** 2296 * ##### taskbar drawing ##### 2297 */ 2298 2299 LRESULT EraseBackgroundWithTheme(HDC hdc) 2300 { 2301 RECT rect; 2302 int iSBkgndPart[4] = {TBP_BACKGROUNDLEFT, TBP_BACKGROUNDTOP, TBP_BACKGROUNDRIGHT, TBP_BACKGROUNDBOTTOM}; 2303 2304 ASSERT(m_Position <= ABE_BOTTOM); 2305 2306 if (m_Theme) 2307 { 2308 GetClientRect(&rect); 2309 DrawThemeBackground(m_Theme, hdc, iSBkgndPart[m_Position], 0, &rect, 0); 2310 } 2311 2312 return 0; 2313 } 2314 2315 int DrawSizerWithTheme(IN HRGN hRgn) 2316 { 2317 HDC hdc; 2318 RECT rect; 2319 int iSizerPart[4] = {TBP_SIZINGBARLEFT, TBP_SIZINGBARTOP, TBP_SIZINGBARRIGHT, TBP_SIZINGBARBOTTOM}; 2320 SIZE size; 2321 2322 ASSERT(m_Position <= ABE_BOTTOM); 2323 2324 HRESULT hr = GetThemePartSize(m_Theme, NULL, iSizerPart[m_Position], 0, NULL, TS_TRUE, &size); 2325 if (FAILED_UNEXPECTEDLY(hr)) 2326 return 0; 2327 2328 GetWindowRect(&rect); 2329 OffsetRect(&rect, -rect.left, -rect.top); 2330 2331 hdc = GetWindowDC(); 2332 2333 switch (m_Position) 2334 { 2335 case ABE_LEFT: 2336 rect.left = rect.right - size.cx; 2337 break; 2338 case ABE_TOP: 2339 rect.top = rect.bottom - size.cy; 2340 break; 2341 case ABE_RIGHT: 2342 rect.right = rect.left + size.cx; 2343 break; 2344 case ABE_BOTTOM: 2345 default: 2346 rect.bottom = rect.top + size.cy; 2347 break; 2348 } 2349 2350 DrawThemeBackground(m_Theme, hdc, iSizerPart[m_Position], 0, &rect, 0); 2351 2352 ReleaseDC(hdc); 2353 return 0; 2354 } 2355 2356 2357 2358 2359 2360 /* 2361 * ITrayWindow 2362 */ 2363 HRESULT STDMETHODCALLTYPE Open() 2364 { 2365 RECT rcWnd; 2366 2367 /* Check if there's already a window created and try to show it. 2368 If it was somehow destroyed just create a new tray window. */ 2369 if (m_hWnd != NULL && IsWindow()) 2370 { 2371 return S_OK; 2372 } 2373 2374 DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE; 2375 if (g_TaskbarSettings.sr.AlwaysOnTop) 2376 dwExStyle |= WS_EX_TOPMOST; 2377 2378 DWORD dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 2379 if(!m_Theme) 2380 { 2381 dwStyle |= WS_THICKFRAME | WS_BORDER; 2382 } 2383 2384 ZeroMemory(&rcWnd, sizeof(rcWnd)); 2385 if (m_Position != (DWORD) -1) 2386 rcWnd = m_TrayRects[m_Position]; 2387 2388 if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle)) 2389 return E_FAIL; 2390 2391 /* Align all controls on the tray window */ 2392 AlignControls(NULL); 2393 2394 /* Move the tray window to the right position and resize it if necessary */ 2395 CheckTrayWndPosition(); 2396 2397 return S_OK; 2398 } 2399 2400 HRESULT STDMETHODCALLTYPE Close() 2401 { 2402 if (m_hWnd != NULL) 2403 { 2404 SendMessage(m_hWnd, 2405 WM_APP_TRAYDESTROY, 2406 0, 2407 0); 2408 } 2409 2410 return S_OK; 2411 } 2412 2413 HWND STDMETHODCALLTYPE GetHWND() 2414 { 2415 return m_hWnd; 2416 } 2417 2418 BOOL STDMETHODCALLTYPE IsSpecialHWND(IN HWND hWnd) 2419 { 2420 return (m_hWnd == hWnd || 2421 (m_DesktopWnd != NULL && m_hWnd == m_DesktopWnd)); 2422 } 2423 2424 BOOL STDMETHODCALLTYPE IsHorizontal() 2425 { 2426 return IsPosHorizontal(); 2427 } 2428 2429 BOOL STDMETHODCALLTYPE Lock(IN BOOL bLock) 2430 { 2431 BOOL bPrevLock = g_TaskbarSettings.bLock; 2432 2433 if (g_TaskbarSettings.bLock != bLock) 2434 { 2435 g_TaskbarSettings.bLock = bLock; 2436 2437 if (m_TrayBandSite != NULL) 2438 { 2439 if (!SUCCEEDED(m_TrayBandSite->Lock(bLock))) 2440 { 2441 /* Reset?? */ 2442 g_TaskbarSettings.bLock = bPrevLock; 2443 return bPrevLock; 2444 } 2445 } 2446 2447 if (m_Theme) 2448 { 2449 /* Update cached tray sizes */ 2450 for(DWORD Pos = ABE_LEFT; Pos <= ABE_BOTTOM; Pos++) 2451 { 2452 RECT rcGripper = {0}; 2453 AdjustSizerRect(&rcGripper, Pos); 2454 2455 if(g_TaskbarSettings.bLock) 2456 { 2457 m_TrayRects[Pos].top += rcGripper.top; 2458 m_TrayRects[Pos].left += rcGripper.left; 2459 m_TrayRects[Pos].bottom += rcGripper.bottom; 2460 m_TrayRects[Pos].right += rcGripper.right; 2461 } 2462 else 2463 { 2464 m_TrayRects[Pos].top -= rcGripper.top; 2465 m_TrayRects[Pos].left -= rcGripper.left; 2466 m_TrayRects[Pos].bottom -= rcGripper.bottom; 2467 m_TrayRects[Pos].right -= rcGripper.right; 2468 } 2469 } 2470 } 2471 SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER); 2472 ResizeWorkArea(); 2473 ApplyClipping(TRUE); 2474 } 2475 2476 return bPrevLock; 2477 } 2478 2479 /* The task window is visible and non-WS_EX_TOOLWINDOW and 2480 { has WS_EX_APPWINDOW style or has no owner } and is none of explorer's 2481 special windows (such as the desktop or the tray window) */ 2482 BOOL STDMETHODCALLTYPE IsTaskWnd(HWND hWnd) 2483 { 2484 if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) && !IsSpecialHWND(hWnd)) 2485 { 2486 DWORD exStyle = (DWORD)::GetWindowLongPtr(hWnd, GWL_EXSTYLE); 2487 if (((exStyle & WS_EX_APPWINDOW) || ::GetWindow(hWnd, GW_OWNER) == NULL) && 2488 !(exStyle & WS_EX_TOOLWINDOW)) 2489 { 2490 return TRUE; 2491 } 2492 } 2493 return FALSE; 2494 } 2495 2496 /* 2497 * IContextMenu 2498 */ 2499 HRESULT STDMETHODCALLTYPE QueryContextMenu(HMENU hPopup, 2500 UINT indexMenu, 2501 UINT idCmdFirst, 2502 UINT idCmdLast, 2503 UINT uFlags) 2504 { 2505 if (!m_ContextMenu) 2506 { 2507 HRESULT hr = TrayWindowCtxMenuCreator(this, m_hWnd, &m_ContextMenu); 2508 if (FAILED_UNEXPECTEDLY(hr)) 2509 return hr; 2510 } 2511 2512 return m_ContextMenu->QueryContextMenu(hPopup, indexMenu, idCmdFirst, idCmdLast, uFlags); 2513 } 2514 2515 HRESULT STDMETHODCALLTYPE InvokeCommand(LPCMINVOKECOMMANDINFO lpici) 2516 { 2517 if (!m_ContextMenu) 2518 return E_INVALIDARG; 2519 2520 return m_ContextMenu->InvokeCommand(lpici); 2521 } 2522 2523 HRESULT STDMETHODCALLTYPE GetCommandString(UINT_PTR idCmd, 2524 UINT uType, 2525 UINT *pwReserved, 2526 LPSTR pszName, 2527 UINT cchMax) 2528 { 2529 if (!m_ContextMenu) 2530 return E_INVALIDARG; 2531 2532 return m_ContextMenu->GetCommandString(idCmd, uType, pwReserved, pszName, cchMax); 2533 } 2534 2535 /********************************************************** 2536 * ##### message handling ##### 2537 */ 2538 2539 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2540 { 2541 HRESULT hRet; 2542 2543 ((ITrayWindow*)this)->AddRef(); 2544 2545 SetWindowTheme(m_hWnd, L"TaskBar", NULL); 2546 2547 /* Create the Start button */ 2548 m_StartButton.Create(m_hWnd); 2549 2550 /* Create the 'Show Desktop' button if necessary */ 2551 if (g_TaskbarSettings.bShowDesktopButton) 2552 m_ShowDesktopButton.DoCreate(m_hWnd); 2553 2554 /* Load the saved tray window settings */ 2555 RegLoadSettings(); 2556 2557 /* Create and initialize the start menu */ 2558 HBITMAP hbmBanner = LoadBitmapW(hExplorerInstance, MAKEINTRESOURCEW(IDB_STARTMENU)); 2559 m_StartMenuPopup = CreateStartMenu(this, &m_StartMenuBand, hbmBanner, 2560 g_TaskbarSettings.sr.SmSmallIcons); 2561 2562 /* Create the task band */ 2563 hRet = CTaskBand_CreateInstance(this, m_StartButton.m_hWnd, IID_PPV_ARG(IDeskBand, &m_TaskBand)); 2564 if (FAILED_UNEXPECTEDLY(hRet)) 2565 return FALSE; 2566 2567 /* Create the rebar band site. This actually creates the rebar and the tasks toolbar. */ 2568 hRet = CTrayBandSite_CreateInstance(this, m_TaskBand, &m_TrayBandSite); 2569 if (FAILED_UNEXPECTEDLY(hRet)) 2570 return FALSE; 2571 2572 /* Create the tray notification window */ 2573 hRet = CTrayNotifyWnd_CreateInstance(m_hWnd, IID_PPV_ARG(IUnknown, &m_TrayNotifyInstance)); 2574 if (FAILED_UNEXPECTEDLY(hRet)) 2575 return FALSE; 2576 2577 /* Get the hwnd of the rebar */ 2578 hRet = IUnknown_GetWindow(m_TrayBandSite, &m_Rebar); 2579 if (FAILED_UNEXPECTEDLY(hRet)) 2580 return FALSE; 2581 2582 /* Get the hwnd of the tasks toolbar */ 2583 hRet = IUnknown_GetWindow(m_TaskBand, &m_TaskSwitch); 2584 if (FAILED_UNEXPECTEDLY(hRet)) 2585 return FALSE; 2586 2587 /* Get the hwnd of the tray notification window */ 2588 hRet = IUnknown_GetWindow(m_TrayNotifyInstance, &m_TrayNotify); 2589 if (FAILED_UNEXPECTEDLY(hRet)) 2590 return FALSE; 2591 2592 SetWindowTheme(m_Rebar, L"TaskBar", NULL); 2593 2594 UpdateFonts(); 2595 2596 InitShellServices(&m_ShellServices); 2597 2598 if (g_TaskbarSettings.sr.AutoHide) 2599 { 2600 m_AutoHideState = AUTOHIDE_HIDING; 2601 SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL); 2602 } 2603 2604 /* Set the initial lock state in the band site */ 2605 m_TrayBandSite->Lock(g_TaskbarSettings.bLock); 2606 2607 RegisterHotKey(m_hWnd, IDHK_RUN, MOD_WIN, 'R'); 2608 RegisterHotKey(m_hWnd, IDHK_MINIMIZE_ALL, MOD_WIN, 'M'); 2609 RegisterHotKey(m_hWnd, IDHK_RESTORE_ALL, MOD_WIN|MOD_SHIFT, 'M'); 2610 RegisterHotKey(m_hWnd, IDHK_HELP, MOD_WIN, VK_F1); 2611 RegisterHotKey(m_hWnd, IDHK_EXPLORE, MOD_WIN, 'E'); 2612 RegisterHotKey(m_hWnd, IDHK_FIND, MOD_WIN, 'F'); 2613 RegisterHotKey(m_hWnd, IDHK_FIND_COMPUTER, MOD_WIN|MOD_CONTROL, 'F'); 2614 RegisterHotKey(m_hWnd, IDHK_NEXT_TASK, MOD_WIN, VK_TAB); 2615 RegisterHotKey(m_hWnd, IDHK_PREV_TASK, MOD_WIN|MOD_SHIFT, VK_TAB); 2616 RegisterHotKey(m_hWnd, IDHK_SYS_PROPERTIES, MOD_WIN, VK_PAUSE); 2617 RegisterHotKey(m_hWnd, IDHK_DESKTOP, MOD_WIN, 'D'); 2618 RegisterHotKey(m_hWnd, IDHK_PAGER, MOD_WIN, 'B'); 2619 2620 return TRUE; 2621 } 2622 2623 #define TIMER_ID_IGNOREPULSERESET 888 2624 #define TIMER_IGNOREPULSERESET_TIMEOUT 200 2625 2626 LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2627 { 2628 KillTimer(TIMER_ID_IGNOREPULSERESET); 2629 return 0; 2630 } 2631 2632 LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2633 { 2634 if (m_Theme) 2635 CloseThemeData(m_Theme); 2636 2637 m_Theme = OpenThemeData(m_hWnd, L"TaskBar"); 2638 2639 if (m_Theme) 2640 { 2641 SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, 0); 2642 } 2643 else 2644 { 2645 SetWindowStyle(m_hWnd, WS_THICKFRAME | WS_BORDER, WS_THICKFRAME | WS_BORDER); 2646 } 2647 SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER); 2648 2649 return TRUE; 2650 } 2651 2652 LRESULT OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2653 { 2654 if (wParam == SPI_SETNONCLIENTMETRICS) 2655 { 2656 SendMessage(m_TrayNotify, uMsg, wParam, lParam); 2657 SendMessage(m_TaskSwitch, uMsg, wParam, lParam); 2658 UpdateFonts(); 2659 AlignControls(NULL); 2660 CheckTrayWndPosition(); 2661 } 2662 2663 if (m_StartMenuPopup && lstrcmpiW((LPCWSTR)lParam, L"TraySettings") == 0) 2664 { 2665 HideStartMenu(); 2666 2667 HBITMAP hbmBanner = LoadBitmapW(hExplorerInstance, MAKEINTRESOURCEW(IDB_STARTMENU)); 2668 #if 1 // FIXME: Please re-use the start menu 2669 /* Re-create the start menu */ 2670 m_StartMenuBand.Release(); 2671 m_StartMenuPopup = CreateStartMenu(this, &m_StartMenuBand, hbmBanner, 2672 g_TaskbarSettings.sr.SmSmallIcons); 2673 FIXME("Use UpdateStartMenu\n"); 2674 #else 2675 // Update the start menu 2676 UpdateStartMenu(m_StartMenuPopup, hbmBanner, g_TaskbarSettings.sr.SmSmallIcons, TRUE); 2677 #endif 2678 } 2679 2680 return 0; 2681 } 2682 2683 LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2684 { 2685 HDC hdc = (HDC) wParam; 2686 2687 if (!m_Theme) 2688 { 2689 bHandled = FALSE; 2690 return 0; 2691 } 2692 2693 return EraseBackgroundWithTheme(hdc); 2694 } 2695 2696 LRESULT OnDisplayChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2697 { 2698 /* Load the saved tray window settings */ 2699 RegLoadSettings(); 2700 2701 /* Move the tray window to the right position and resize it if necessary */ 2702 CheckTrayWndPosition(); 2703 2704 return TRUE; 2705 } 2706 2707 LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2708 { 2709 COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT *)lParam; 2710 switch (pCopyData->dwData) 2711 { 2712 case TABDMC_APPBAR: 2713 return appbar_message(pCopyData); 2714 case TABDMC_NOTIFY: 2715 case TABDMC_LOADINPROC: 2716 return ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam); 2717 } 2718 return FALSE; 2719 } 2720 2721 // We have to draw non-client area because the 'Show Desktop' button is beyond client area. 2722 void DrawShowDesktopButton() 2723 { 2724 if (!m_ShowDesktopButton.IsWindow()) 2725 return; 2726 // Get the rectangle in window coordinates 2727 RECT rcButton, rcWnd; 2728 GetWindowRect(&rcWnd); 2729 m_ShowDesktopButton.GetWindowRect(&rcButton); 2730 ::OffsetRect(&rcButton, -rcWnd.left, -rcWnd.top); 2731 2732 HDC hdc = GetDCEx(NULL, DCX_WINDOW | DCX_CACHE); 2733 m_ShowDesktopButton.OnDraw(hdc, &rcButton); // Draw the button 2734 ReleaseDC(hdc); 2735 } 2736 2737 LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2738 { 2739 DefWindowProc(uMsg, wParam, lParam); 2740 bHandled = TRUE; 2741 2742 if (!m_Theme || g_TaskbarSettings.bLock) 2743 { 2744 DrawShowDesktopButton(); // We have to draw non-client area 2745 return 0; 2746 } 2747 2748 DrawSizerWithTheme((HRGN) wParam); 2749 DrawShowDesktopButton(); // We have to draw non-client area 2750 return 0; 2751 } 2752 2753 LRESULT OnCtlColorBtn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2754 { 2755 SetBkMode((HDC) wParam, TRANSPARENT); 2756 return (LRESULT) GetStockObject(HOLLOW_BRUSH); 2757 } 2758 2759 LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2760 { 2761 RECT rcClient; 2762 POINT pt; 2763 2764 if (g_TaskbarSettings.bLock) 2765 { 2766 /* The user may not be able to resize the tray window. 2767 Pretend like the window is not sizeable when the user 2768 clicks on the border. */ 2769 return HTBORDER; 2770 } 2771 2772 SetLastError(ERROR_SUCCESS); 2773 if (GetClientRect(&rcClient) && 2774 (MapWindowPoints(NULL, (LPPOINT) &rcClient, 2) != 0 || GetLastError() == ERROR_SUCCESS)) 2775 { 2776 pt.x = (SHORT) LOWORD(lParam); 2777 pt.y = (SHORT) HIWORD(lParam); 2778 2779 if (PtInRect(&rcClient, pt)) 2780 { 2781 /* The user is trying to drag the tray window */ 2782 return HTCAPTION; 2783 } 2784 2785 /* Depending on the position of the tray window, allow only 2786 changing the border next to the monitor working area */ 2787 switch (m_Position) 2788 { 2789 case ABE_TOP: 2790 if (pt.y > rcClient.bottom) 2791 return HTBOTTOM; 2792 break; 2793 case ABE_LEFT: 2794 if (pt.x > rcClient.right) 2795 return HTRIGHT; 2796 break; 2797 case ABE_RIGHT: 2798 if (pt.x < rcClient.left) 2799 return HTLEFT; 2800 break; 2801 case ABE_BOTTOM: 2802 default: 2803 if (pt.y < rcClient.top) 2804 return HTTOP; 2805 break; 2806 } 2807 } 2808 return HTBORDER; 2809 } 2810 2811 LRESULT OnMoving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2812 { 2813 POINT ptCursor; 2814 PRECT pRect = (PRECT) lParam; 2815 2816 /* We need to ensure that an application can not accidently 2817 move the tray window (using SetWindowPos). However, we still 2818 need to be able to move the window in case the user wants to 2819 drag the tray window to another position or in case the user 2820 wants to resize the tray window. */ 2821 if (!g_TaskbarSettings.bLock && GetCursorPos(&ptCursor)) 2822 { 2823 IsDragging = TRUE; 2824 m_DraggingPosition = GetDraggingRectFromPt(ptCursor, pRect, &m_DraggingMonitor); 2825 } 2826 else 2827 { 2828 *pRect = m_TrayRects[m_Position]; 2829 } 2830 return TRUE; 2831 } 2832 2833 LRESULT OnSizing(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2834 { 2835 PRECT pRect = (PRECT) lParam; 2836 2837 if (!g_TaskbarSettings.bLock) 2838 { 2839 FitToRebar(pRect); 2840 } 2841 else 2842 { 2843 *pRect = m_TrayRects[m_Position]; 2844 } 2845 return TRUE; 2846 } 2847 2848 LRESULT OnWindowPosChanging(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2849 { 2850 ChangingWinPos((LPWINDOWPOS) lParam); 2851 return TRUE; 2852 } 2853 2854 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2855 { 2856 RECT rcClient; 2857 if (wParam == SIZE_RESTORED && lParam == 0) 2858 { 2859 ResizeWorkArea(); 2860 /* Clip the tray window on multi monitor systems so the edges can't 2861 overlap into another monitor */ 2862 ApplyClipping(TRUE); 2863 2864 if (!GetClientRect(&rcClient)) 2865 { 2866 return FALSE; 2867 } 2868 } 2869 else 2870 { 2871 rcClient.left = rcClient.top = 0; 2872 rcClient.right = LOWORD(lParam); 2873 rcClient.bottom = HIWORD(lParam); 2874 } 2875 2876 AlignControls(&rcClient); 2877 return TRUE; 2878 } 2879 2880 LRESULT OnEnterSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2881 { 2882 InSizeMove = TRUE; 2883 IsDragging = FALSE; 2884 if (!g_TaskbarSettings.bLock) 2885 { 2886 /* Remove the clipping on multi monitor systems while dragging around */ 2887 ApplyClipping(FALSE); 2888 } 2889 return TRUE; 2890 } 2891 2892 LRESULT OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2893 { 2894 InSizeMove = FALSE; 2895 if (!g_TaskbarSettings.bLock) 2896 { 2897 FitToRebar(&m_TrayRects[m_Position]); 2898 2899 /* Apply clipping */ 2900 PostMessage(WM_SIZE, SIZE_RESTORED, 0); 2901 } 2902 return TRUE; 2903 } 2904 2905 LRESULT OnSysChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2906 { 2907 switch (wParam) 2908 { 2909 case TEXT(' '): 2910 { 2911 /* The user pressed Alt+Space, this usually brings up the system menu of a window. 2912 The tray window needs to handle this specially, since it normally doesn't have 2913 a system menu. */ 2914 2915 static const UINT uidDisableItem [] = { 2916 SC_RESTORE, 2917 SC_MOVE, 2918 SC_SIZE, 2919 SC_MAXIMIZE, 2920 SC_MINIMIZE, 2921 }; 2922 HMENU hSysMenu; 2923 UINT i, uId; 2924 2925 /* temporarily enable the system menu */ 2926 SetWindowStyle(m_hWnd, WS_SYSMENU, WS_SYSMENU); 2927 2928 hSysMenu = GetSystemMenu(FALSE); 2929 if (hSysMenu != NULL) 2930 { 2931 /* Disable all items that are not relevant */ 2932 for (i = 0; i < _countof(uidDisableItem); i++) 2933 { 2934 EnableMenuItem(hSysMenu, 2935 uidDisableItem[i], 2936 MF_BYCOMMAND | MF_GRAYED); 2937 } 2938 2939 EnableMenuItem(hSysMenu, 2940 SC_CLOSE, 2941 MF_BYCOMMAND | 2942 (SHRestricted(REST_NOCLOSE) ? MF_GRAYED : MF_ENABLED)); 2943 2944 /* Display the system menu */ 2945 uId = TrackMenu( 2946 hSysMenu, 2947 NULL, 2948 m_StartButton.m_hWnd, 2949 m_Position != ABE_TOP, 2950 FALSE); 2951 if (uId != 0) 2952 { 2953 SendMessage(m_hWnd, WM_SYSCOMMAND, (WPARAM) uId, 0); 2954 } 2955 } 2956 2957 /* revert the system menu window style */ 2958 SetWindowStyle(m_hWnd, WS_SYSMENU, 0); 2959 break; 2960 } 2961 2962 default: 2963 bHandled = FALSE; 2964 } 2965 return TRUE; 2966 } 2967 2968 LRESULT OnNcLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2969 { 2970 /* This handler implements the trick that makes the start button to 2971 get pressed when the user clicked left or below the button */ 2972 2973 POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; 2974 WINDOWINFO wi = {sizeof(WINDOWINFO)}; 2975 2976 bHandled = FALSE; 2977 2978 RECT rcStartBtn; 2979 m_StartButton.GetWindowRect(&rcStartBtn); 2980 2981 GetWindowInfo(m_hWnd, &wi); 2982 2983 switch (m_Position) 2984 { 2985 case ABE_TOP: 2986 case ABE_LEFT: 2987 { 2988 if (pt.x > rcStartBtn.right || pt.y > rcStartBtn.bottom) 2989 return 0; 2990 break; 2991 } 2992 case ABE_RIGHT: 2993 { 2994 if (pt.x < rcStartBtn.left || pt.y > rcStartBtn.bottom) 2995 return 0; 2996 2997 if (rcStartBtn.right + (int)wi.cxWindowBorders * 2 + 1 < wi.rcWindow.right && 2998 pt.x > rcStartBtn.right) 2999 { 3000 return 0; 3001 } 3002 break; 3003 } 3004 case ABE_BOTTOM: 3005 { 3006 if (pt.x > rcStartBtn.right || pt.y < rcStartBtn.top) 3007 return 0; 3008 3009 if (rcStartBtn.bottom + (int)wi.cyWindowBorders * 2 + 1 < wi.rcWindow.bottom && 3010 pt.y > rcStartBtn.bottom) 3011 { 3012 return 0; 3013 } 3014 3015 break; 3016 } 3017 } 3018 3019 bHandled = TRUE; 3020 PopupStartMenu(); 3021 return 0; 3022 } 3023 3024 LRESULT OnNcRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3025 { 3026 /* We want the user to be able to get a context menu even on the nonclient 3027 area (including the sizing border)! */ 3028 uMsg = WM_CONTEXTMENU; 3029 wParam = (WPARAM) m_hWnd; 3030 3031 return OnContextMenu(uMsg, wParam, lParam, bHandled); 3032 } 3033 3034 LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3035 { 3036 LRESULT Ret = FALSE; 3037 POINT pt, *ppt = NULL; 3038 HWND hWndExclude = NULL; 3039 3040 /* Check if the administrator has forbidden access to context menus */ 3041 if (SHRestricted(REST_NOTRAYCONTEXTMENU)) 3042 return FALSE; 3043 3044 pt.x = (SHORT) LOWORD(lParam); 3045 pt.y = (SHORT) HIWORD(lParam); 3046 3047 if (pt.x != -1 || pt.y != -1) 3048 ppt = &pt; 3049 else 3050 hWndExclude = m_StartButton.m_hWnd; 3051 3052 if ((HWND) wParam == m_StartButton.m_hWnd) 3053 { 3054 /* Make sure we can't track the context menu if the start 3055 menu is currently being shown */ 3056 if (!(m_StartButton.SendMessage(BM_GETSTATE, 0, 0) & BST_PUSHED)) 3057 { 3058 CComPtr<IContextMenu> ctxMenu; 3059 CStartMenuBtnCtxMenu_CreateInstance(this, m_hWnd, &ctxMenu); 3060 TrackCtxMenu(ctxMenu, ppt, hWndExclude, m_Position == ABE_BOTTOM, this); 3061 } 3062 } 3063 else 3064 { 3065 /* See if the context menu should be handled by the task band site */ 3066 if (ppt != NULL && m_TrayBandSite != NULL) 3067 { 3068 HWND hWndAtPt; 3069 POINT ptClient = *ppt; 3070 3071 /* Convert the coordinates to client-coordinates */ 3072 ::MapWindowPoints(NULL, m_hWnd, &ptClient, 1); 3073 3074 hWndAtPt = ChildWindowFromPoint(ptClient); 3075 if (hWndAtPt != NULL && 3076 (hWndAtPt == m_Rebar || ::IsChild(m_Rebar, hWndAtPt))) 3077 { 3078 /* Check if the user clicked on the task switch window */ 3079 ptClient = *ppt; 3080 ::MapWindowPoints(NULL, m_Rebar, &ptClient, 1); 3081 3082 hWndAtPt = ::ChildWindowFromPointEx(m_Rebar, ptClient, CWP_SKIPINVISIBLE | CWP_SKIPDISABLED); 3083 if (hWndAtPt == m_TaskSwitch) 3084 goto HandleTrayContextMenu; 3085 3086 /* Forward the message to the task band site */ 3087 m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret); 3088 } 3089 else 3090 goto HandleTrayContextMenu; 3091 } 3092 else 3093 { 3094 HandleTrayContextMenu: 3095 /* Tray the default tray window context menu */ 3096 TrackCtxMenu(this, ppt, NULL, FALSE, this); 3097 } 3098 } 3099 return Ret; 3100 } 3101 3102 LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3103 { 3104 LRESULT Ret = FALSE; 3105 /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside 3106 the rebar control! But we shouldn't forward messages that the band 3107 site doesn't handle, such as other controls (start button, tray window */ 3108 3109 HRESULT hr = E_FAIL; 3110 3111 if (m_TrayBandSite) 3112 { 3113 hr = m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret); 3114 if (SUCCEEDED(hr)) 3115 return Ret; 3116 } 3117 3118 if (m_TrayBandSite == NULL || FAILED(hr)) 3119 { 3120 const NMHDR *nmh = (const NMHDR *) lParam; 3121 3122 if (nmh->hwndFrom == m_TrayNotify) 3123 { 3124 switch (nmh->code) 3125 { 3126 case NTNWM_REALIGN: 3127 /* Cause all controls to be aligned */ 3128 PostMessage(WM_SIZE, SIZE_RESTORED, 0); 3129 break; 3130 } 3131 } 3132 } 3133 return Ret; 3134 } 3135 3136 BOOL CheckShowDesktopButtonClick(LPARAM lParam, BOOL& bHandled) 3137 { 3138 POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; 3139 if (m_ShowDesktopButton.PtInButton(pt)) // Did you click the button? 3140 { 3141 m_ShowDesktopButton.Click(); 3142 bHandled = TRUE; 3143 return TRUE; 3144 } 3145 3146 return FALSE; 3147 } 3148 3149 LRESULT OnNcLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3150 { 3151 /* Let the clock handle the double-click */ 3152 ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam); 3153 3154 /* We "handle" this message so users can't cause a weird maximize/restore 3155 window animation when double-clicking the tray window! */ 3156 return TRUE; 3157 } 3158 3159 LRESULT OnNcLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3160 { 3161 CheckShowDesktopButtonClick(lParam, bHandled); 3162 return FALSE; 3163 } 3164 3165 LRESULT OnAppTrayDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3166 { 3167 DestroyWindow(); 3168 return TRUE; 3169 } 3170 3171 LRESULT OnOpenStartMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3172 { 3173 HWND hwndStartMenu; 3174 HRESULT hr = IUnknown_GetWindow(m_StartMenuPopup, &hwndStartMenu); 3175 if (FAILED_UNEXPECTEDLY(hr)) 3176 return FALSE; 3177 3178 if (::IsWindowVisible(hwndStartMenu)) 3179 HideStartMenu(); 3180 else 3181 PopupStartMenu(); 3182 3183 return TRUE; 3184 } 3185 3186 LRESULT OnDoExitWindows(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3187 { 3188 /* 3189 * TWM_DOEXITWINDOWS is send by the CDesktopBrowser to us 3190 * to show the shutdown dialog. Also a WM_CLOSE message sent 3191 * by apps should show the dialog. 3192 */ 3193 return DoExitWindows(); 3194 } 3195 3196 LRESULT OnSysCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3197 { 3198 if (wParam == SC_CLOSE) 3199 { 3200 return DoExitWindows(); 3201 } 3202 3203 bHandled = FALSE; 3204 return TRUE; 3205 } 3206 3207 LRESULT OnGetTaskSwitch(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3208 { 3209 bHandled = TRUE; 3210 return (LRESULT)m_TaskSwitch; 3211 } 3212 3213 void RestoreMinimizedNonTaskWnds(BOOL bDestroyed, HWND hwndActive) 3214 { 3215 for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i) 3216 { 3217 HWND hwnd = g_MinimizedAll[i].hwnd; 3218 if (!hwnd || hwndActive == hwnd) 3219 continue; 3220 3221 if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd) && 3222 (!IsTaskWnd(hwnd) || !::IsWindowEnabled(hwnd))) 3223 { 3224 ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl); // Restore 3225 } 3226 } 3227 3228 g_MinimizedAll.RemoveAll(); 3229 3230 if (!bDestroyed) 3231 ::SetForegroundWindow(hwndActive); 3232 } 3233 3234 LRESULT OnPulse(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3235 { 3236 if (IgnorePulse) 3237 return 0; 3238 3239 KillTimer(TIMER_ID_IGNOREPULSERESET); 3240 IgnorePulse = TRUE; 3241 RestoreMinimizedNonTaskWnds((BOOL)wParam, (HWND)lParam); 3242 SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL); 3243 return 0; 3244 } 3245 3246 LRESULT OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3247 { 3248 return HandleHotKey(wParam); 3249 } 3250 3251 struct MINIMIZE_INFO 3252 { 3253 HWND hwndDesktop; 3254 HWND hTrayWnd; 3255 HWND hwndProgman; 3256 CSimpleArray<MINWNDPOS> *pMinimizedAll; 3257 BOOL bShowDesktop; 3258 }; 3259 3260 static BOOL IsDialog(HWND hwnd) 3261 { 3262 WCHAR szClass[32]; 3263 GetClassNameW(hwnd, szClass, _countof(szClass)); 3264 return wcscmp(szClass, L"#32770") == 0; 3265 } 3266 3267 static BOOL CALLBACK MinimizeWindowsProc(HWND hwnd, LPARAM lParam) 3268 { 3269 MINIMIZE_INFO *info = (MINIMIZE_INFO *)lParam; 3270 if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd || hwnd == info->hwndProgman) 3271 return TRUE; // Ignore special windows 3272 3273 if (!info->bShowDesktop) 3274 { 3275 if (!::IsWindowEnabled(hwnd) || IsDialog(hwnd)) 3276 return TRUE; 3277 HWND hwndOwner = ::GetWindow(hwnd, GW_OWNER); 3278 if (hwndOwner && !::IsWindowEnabled(hwndOwner)) 3279 return TRUE; 3280 } 3281 3282 if (CanBeMinimized(hwnd)) 3283 { 3284 MINWNDPOS mwp = { hwnd, { sizeof(mwp.wndpl) } }; 3285 if (::GetWindowPlacement(hwnd, &mwp.wndpl) && // Save the position and status 3286 ::ShowWindowAsync(hwnd, SW_SHOWMINNOACTIVE)) // Minimize 3287 { 3288 info->pMinimizedAll->Add(mwp); 3289 } 3290 } 3291 3292 return TRUE; 3293 } 3294 3295 VOID MinimizeAll(BOOL bShowDesktop = FALSE) 3296 { 3297 IgnorePulse = TRUE; 3298 KillTimer(TIMER_ID_IGNOREPULSERESET); 3299 3300 MINIMIZE_INFO info; 3301 info.hwndDesktop = GetDesktopWindow();; 3302 info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL); 3303 info.hwndProgman = FindWindowW(L"Progman", NULL); 3304 info.pMinimizedAll = &g_MinimizedAll; 3305 info.bShowDesktop = bShowDesktop; 3306 EnumWindows(MinimizeWindowsProc, (LPARAM)&info); 3307 3308 ::SetForegroundWindow(m_DesktopWnd); 3309 ::SetFocus(m_DesktopWnd); 3310 SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL); 3311 } 3312 3313 VOID ShowDesktop() 3314 { 3315 MinimizeAll(TRUE); 3316 } 3317 3318 VOID RestoreAll() 3319 { 3320 IgnorePulse = TRUE; 3321 KillTimer(TIMER_ID_IGNOREPULSERESET); 3322 3323 for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i) 3324 { 3325 HWND hwnd = g_MinimizedAll[i].hwnd; 3326 if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd)) 3327 ::SetWindowPlacement(hwnd, &g_MinimizedAll[i].wndpl); 3328 } 3329 3330 g_MinimizedAll.RemoveAll(); 3331 SetTimer(TIMER_ID_IGNOREPULSERESET, TIMER_IGNOREPULSERESET_TIMEOUT, NULL); 3332 } 3333 3334 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3335 { 3336 LRESULT Ret = FALSE; 3337 3338 if ((HWND) lParam == m_StartButton.m_hWnd) 3339 { 3340 return FALSE; 3341 } 3342 3343 if (m_TrayBandSite == NULL || FAILED_UNEXPECTEDLY(m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret))) 3344 { 3345 return HandleCommand(LOWORD(wParam)); 3346 } 3347 return Ret; 3348 } 3349 3350 LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3351 { 3352 POINT pt; 3353 ::GetCursorPos(&pt); 3354 if (m_ShowDesktopButton.PtInButton(pt)) 3355 m_ShowDesktopButton.StartHovering(); 3356 3357 if (g_TaskbarSettings.sr.AutoHide) 3358 { 3359 SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); 3360 } 3361 3362 return TRUE; 3363 } 3364 3365 LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3366 { 3367 if (wParam == TIMER_ID_MOUSETRACK) 3368 { 3369 ProcessMouseTracking(); 3370 } 3371 else if (wParam == TIMER_ID_AUTOHIDE) 3372 { 3373 ProcessAutoHide(); 3374 } 3375 else if (wParam == TIMER_ID_IGNOREPULSERESET) 3376 { 3377 KillTimer(TIMER_ID_IGNOREPULSERESET); 3378 IgnorePulse = FALSE; 3379 } 3380 return 0; 3381 } 3382 3383 LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3384 { 3385 LRESULT ret = DefWindowProc(uMsg, wParam, lParam); 3386 DrawShowDesktopButton(); // We have to draw non-client area 3387 bHandled = TRUE; 3388 return ret; 3389 } 3390 3391 LRESULT OnNcCalcSize(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3392 { 3393 RECT *rc = NULL; 3394 /* Ignore WM_NCCALCSIZE if we are not themed or locked */ 3395 if(!m_Theme || g_TaskbarSettings.bLock) 3396 { 3397 bHandled = FALSE; 3398 return 0; 3399 } 3400 if(!wParam) 3401 { 3402 rc = (RECT*)wParam; 3403 } 3404 else 3405 { 3406 NCCALCSIZE_PARAMS *prms = (NCCALCSIZE_PARAMS*)lParam; 3407 if(prms->lppos->flags & SWP_NOSENDCHANGING) 3408 { 3409 bHandled = FALSE; 3410 return 0; 3411 } 3412 rc = &prms->rgrc[0]; 3413 } 3414 3415 AdjustSizerRect(rc, m_Position); 3416 3417 return 0; 3418 } 3419 3420 LRESULT OnInitMenuPopup(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3421 { 3422 HMENU hMenu = (HMENU)wParam; 3423 if (::IsThereAnyEffectiveWindow(FALSE)) 3424 { 3425 ::EnableMenuItem(hMenu, ID_SHELL_CMD_CASCADE_WND, MF_BYCOMMAND | MF_ENABLED); 3426 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_H, MF_BYCOMMAND | MF_ENABLED); 3427 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_V, MF_BYCOMMAND | MF_ENABLED); 3428 if (g_Arrangement != NONE) 3429 { 3430 CStringW strCaption((g_Arrangement == TILED) ? MAKEINTRESOURCEW(IDS_TRAYWND_UNDO_TILE) 3431 : MAKEINTRESOURCEW(IDS_TRAYWND_UNDO_CASCADE)); 3432 MENUITEMINFOW mii = { sizeof(mii) }; 3433 ::GetMenuItemInfoW(hMenu, ID_SHELL_CMD_UNDO_ACTION, FALSE, &mii); 3434 mii.fMask = MIIM_TYPE; 3435 mii.fType = MFT_STRING; 3436 mii.dwTypeData = const_cast<LPWSTR>(&strCaption[0]); 3437 ::SetMenuItemInfoW(hMenu, ID_SHELL_CMD_UNDO_ACTION, FALSE, &mii); 3438 } 3439 else 3440 { 3441 ::DeleteMenu(hMenu, ID_SHELL_CMD_UNDO_ACTION, MF_BYCOMMAND); 3442 } 3443 } 3444 else 3445 { 3446 ::EnableMenuItem(hMenu, ID_SHELL_CMD_CASCADE_WND, MF_BYCOMMAND | MF_GRAYED); 3447 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_H, MF_BYCOMMAND | MF_GRAYED); 3448 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_V, MF_BYCOMMAND | MF_GRAYED); 3449 ::DeleteMenu(hMenu, ID_SHELL_CMD_UNDO_ACTION, MF_BYCOMMAND); 3450 g_Arrangement = NONE; 3451 g_WindowPosBackup.RemoveAll(); 3452 } 3453 return 0; 3454 } 3455 3456 LRESULT OnRebarAutoSize(INT code, LPNMHDR nmhdr, BOOL& bHandled) 3457 { 3458 #if 0 3459 LPNMRBAUTOSIZE as = (LPNMRBAUTOSIZE) nmhdr; 3460 3461 if (!as->fChanged) 3462 return 0; 3463 3464 RECT rc; 3465 ::GetWindowRect(m_hWnd, &rc); 3466 3467 SIZE szWindow = { 3468 rc.right - rc.left, 3469 rc.bottom - rc.top }; 3470 SIZE szTarget = { 3471 as->rcTarget.right - as->rcTarget.left, 3472 as->rcTarget.bottom - as->rcTarget.top }; 3473 SIZE szActual = { 3474 as->rcActual.right - as->rcActual.left, 3475 as->rcActual.bottom - as->rcActual.top }; 3476 3477 SIZE borders = { 3478 szWindow.cx - szTarget.cx, 3479 szWindow.cy - szTarget.cx, 3480 }; 3481 3482 switch (m_Position) 3483 { 3484 case ABE_LEFT: 3485 szWindow.cx = szActual.cx + borders.cx; 3486 break; 3487 case ABE_TOP: 3488 szWindow.cy = szActual.cy + borders.cy; 3489 break; 3490 case ABE_RIGHT: 3491 szWindow.cx = szActual.cx + borders.cx; 3492 rc.left = rc.right - szWindow.cy; 3493 break; 3494 case ABE_BOTTOM: 3495 szWindow.cy = szActual.cy + borders.cy; 3496 rc.top = rc.bottom - szWindow.cy; 3497 break; 3498 } 3499 3500 SetWindowPos(NULL, rc.left, rc.top, szWindow.cx, szWindow.cy, SWP_NOACTIVATE | SWP_NOZORDER); 3501 #else 3502 bHandled = FALSE; 3503 #endif 3504 return 0; 3505 } 3506 3507 LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3508 { 3509 TaskbarSettings* newSettings = (TaskbarSettings*)lParam; 3510 3511 /* Propagate the new settings to the children */ 3512 ::SendMessageW(m_TaskSwitch, uMsg, wParam, lParam); 3513 ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam); 3514 3515 /* Toggle autohide */ 3516 if (newSettings->sr.AutoHide != g_TaskbarSettings.sr.AutoHide) 3517 { 3518 g_TaskbarSettings.sr.AutoHide = newSettings->sr.AutoHide; 3519 memset(&m_AutoHideOffset, 0, sizeof(m_AutoHideOffset)); 3520 m_AutoHideState = AUTOHIDE_SHOWN; 3521 if (!newSettings->sr.AutoHide) 3522 SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER); 3523 else 3524 SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); 3525 } 3526 3527 /* Toggle lock state */ 3528 Lock(newSettings->bLock); 3529 3530 /* Toggle OnTop state */ 3531 if (newSettings->sr.AlwaysOnTop != g_TaskbarSettings.sr.AlwaysOnTop) 3532 { 3533 g_TaskbarSettings.sr.AlwaysOnTop = newSettings->sr.AlwaysOnTop; 3534 HWND hWndInsertAfter = newSettings->sr.AlwaysOnTop ? HWND_TOPMOST : HWND_BOTTOM; 3535 SetWindowPos(hWndInsertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 3536 } 3537 3538 /* Toggle show desktop button */ 3539 if (newSettings->bShowDesktopButton != g_TaskbarSettings.bShowDesktopButton) 3540 { 3541 g_TaskbarSettings.bShowDesktopButton = newSettings->bShowDesktopButton; 3542 if (!g_TaskbarSettings.bShowDesktopButton) 3543 ::DestroyWindow(m_ShowDesktopButton.m_hWnd); 3544 else if (!m_ShowDesktopButton.IsWindow()) 3545 m_ShowDesktopButton.DoCreate(m_hWnd); 3546 AlignControls(NULL); 3547 } 3548 3549 /* Adjust taskbar size */ 3550 CheckTrayWndPosition(); 3551 3552 g_TaskbarSettings.Save(); 3553 return 0; 3554 } 3555 3556 DECLARE_WND_CLASS_EX(szTrayWndClass, CS_DBLCLKS, COLOR_3DFACE) 3557 3558 BEGIN_MSG_MAP(CTrayWindow) 3559 if (m_StartMenuBand != NULL) 3560 { 3561 MSG Msg; 3562 LRESULT lRet; 3563 3564 Msg.hwnd = m_hWnd; 3565 Msg.message = uMsg; 3566 Msg.wParam = wParam; 3567 Msg.lParam = lParam; 3568 3569 if (m_StartMenuBand->TranslateMenuMessage(&Msg, &lRet) == S_OK) 3570 { 3571 return lRet; 3572 } 3573 3574 wParam = Msg.wParam; 3575 lParam = Msg.lParam; 3576 } 3577 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) 3578 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChanged) 3579 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnRebarAutoSize) // Doesn't quite work ;P 3580 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 3581 MESSAGE_HANDLER(WM_SIZE, OnSize) 3582 MESSAGE_HANDLER(WM_CREATE, OnCreate) 3583 MESSAGE_HANDLER(WM_DESTROY, OnDestroy) 3584 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) 3585 MESSAGE_HANDLER(WM_COMMAND, OnCommand) 3586 MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) 3587 MESSAGE_HANDLER(WM_NOTIFY, OnNotify) 3588 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) 3589 MESSAGE_HANDLER(WM_TIMER, OnTimer) 3590 MESSAGE_HANDLER(WM_DISPLAYCHANGE, OnDisplayChange) 3591 MESSAGE_HANDLER(WM_COPYDATA, OnCopyData) 3592 MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) 3593 MESSAGE_HANDLER(WM_NCACTIVATE, OnNcActivate) 3594 MESSAGE_HANDLER(WM_CTLCOLORBTN, OnCtlColorBtn) 3595 MESSAGE_HANDLER(WM_MOVING, OnMoving) 3596 MESSAGE_HANDLER(WM_SIZING, OnSizing) 3597 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging) 3598 MESSAGE_HANDLER(WM_ENTERSIZEMOVE, OnEnterSizeMove) 3599 MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove) 3600 MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown) 3601 MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar) 3602 MESSAGE_HANDLER(WM_NCRBUTTONUP, OnNcRButtonUp) 3603 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClick) 3604 MESSAGE_HANDLER(WM_NCLBUTTONUP, OnNcLButtonUp) 3605 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) 3606 MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseMove) 3607 MESSAGE_HANDLER(WM_APP_TRAYDESTROY, OnAppTrayDestroy) 3608 MESSAGE_HANDLER(WM_CLOSE, OnDoExitWindows) 3609 MESSAGE_HANDLER(WM_HOTKEY, OnHotkey) 3610 MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize) 3611 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) 3612 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged) 3613 MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu) 3614 MESSAGE_HANDLER(TWM_DOEXITWINDOWS, OnDoExitWindows) 3615 MESSAGE_HANDLER(TWM_GETTASKSWITCH, OnGetTaskSwitch) 3616 MESSAGE_HANDLER(TWM_PULSE, OnPulse) 3617 ALT_MSG_MAP(1) 3618 END_MSG_MAP() 3619 3620 /*****************************************************************************/ 3621 3622 VOID TrayProcessMessages() 3623 { 3624 MSG Msg; 3625 3626 /* FIXME: We should keep a reference here... */ 3627 3628 while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) 3629 { 3630 if (Msg.message == WM_QUIT) 3631 break; 3632 3633 if (m_StartMenuBand == NULL || 3634 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK) 3635 { 3636 TranslateMessage(&Msg); 3637 DispatchMessage(&Msg); 3638 } 3639 } 3640 } 3641 3642 VOID TrayMessageLoop() 3643 { 3644 MSG Msg; 3645 BOOL Ret; 3646 3647 /* FIXME: We should keep a reference here... */ 3648 3649 while (true) 3650 { 3651 Ret = GetMessage(&Msg, NULL, 0, 0); 3652 3653 if (!Ret || Ret == -1) 3654 break; 3655 3656 if (m_StartMenuBand == NULL || 3657 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK) 3658 { 3659 TranslateMessage(&Msg); 3660 DispatchMessage(&Msg); 3661 } 3662 } 3663 } 3664 3665 /* 3666 * IShellDesktopTray 3667 * 3668 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()! 3669 * These are the calls I observed, it may be wrong/incomplete/buggy!!! 3670 * The reason we implement it is because we have to use SHCreateDesktop() so 3671 * that the shell provides the desktop window and all the features that come 3672 * with it (especially positioning of desktop icons) 3673 */ 3674 3675 virtual ULONG STDMETHODCALLTYPE GetState() 3676 { 3677 /* FIXME: Return ABS_ flags? */ 3678 TRACE("IShellDesktopTray::GetState() unimplemented!\n"); 3679 return 0; 3680 } 3681 3682 virtual HRESULT STDMETHODCALLTYPE GetTrayWindow(OUT HWND *phWndTray) 3683 { 3684 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray); 3685 *phWndTray = m_hWnd; 3686 return S_OK; 3687 } 3688 3689 virtual HRESULT STDMETHODCALLTYPE RegisterDesktopWindow(IN HWND hWndDesktop) 3690 { 3691 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop); 3692 3693 m_DesktopWnd = hWndDesktop; 3694 return S_OK; 3695 } 3696 3697 virtual HRESULT STDMETHODCALLTYPE Unknown(IN DWORD dwUnknown1, IN DWORD dwUnknown2) 3698 { 3699 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2); 3700 return S_OK; 3701 } 3702 3703 virtual HRESULT RaiseStartButton() 3704 { 3705 m_StartButton.SendMessageW(BM_SETSTATE, FALSE, 0); 3706 return S_OK; 3707 } 3708 3709 HRESULT WINAPI GetWindow(HWND* phwnd) 3710 { 3711 if (!phwnd) 3712 return E_INVALIDARG; 3713 *phwnd = m_hWnd; 3714 return S_OK; 3715 } 3716 3717 HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode) 3718 { 3719 return E_NOTIMPL; 3720 } 3721 3722 void _Init() 3723 { 3724 m_Position = (DWORD) -1; 3725 } 3726 3727 DECLARE_NOT_AGGREGATABLE(CTrayWindow) 3728 3729 DECLARE_PROTECT_FINAL_CONSTRUCT() 3730 BEGIN_COM_MAP(CTrayWindow) 3731 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/ 3732 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray, IShellDesktopTray) 3733 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 3734 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) 3735 END_COM_MAP() 3736 }; 3737 3738 class CTrayWindowCtxMenu : 3739 public CComCoClass<CTrayWindowCtxMenu>, 3740 public CComObjectRootEx<CComMultiThreadModelNoCS>, 3741 public IContextMenu 3742 { 3743 HWND hWndOwner; 3744 CComPtr<CTrayWindow> TrayWnd; 3745 CComPtr<IContextMenu> pcm; 3746 UINT m_idCmdCmFirst; 3747 3748 public: 3749 HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner) 3750 { 3751 this->TrayWnd = (CTrayWindow *) pTrayWnd; 3752 this->hWndOwner = hWndOwner; 3753 this->m_idCmdCmFirst = 0; 3754 return S_OK; 3755 } 3756 3757 virtual HRESULT STDMETHODCALLTYPE 3758 QueryContextMenu(HMENU hPopup, 3759 UINT indexMenu, 3760 UINT idCmdFirst, 3761 UINT idCmdLast, 3762 UINT uFlags) 3763 { 3764 HMENU hMenuBase; 3765 3766 hMenuBase = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCEW(IDM_TRAYWND)); 3767 if (!hMenuBase) 3768 return HResultFromWin32(GetLastError()); 3769 3770 if (g_MinimizedAll.GetSize() != 0 && !::IsThereAnyEffectiveWindow(TRUE)) 3771 { 3772 CStringW strRestoreAll(MAKEINTRESOURCEW(IDS_RESTORE_ALL)); 3773 MENUITEMINFOW mii = { sizeof(mii) }; 3774 mii.fMask = MIIM_ID | MIIM_TYPE; 3775 mii.wID = ID_SHELL_CMD_RESTORE_ALL; 3776 mii.fType = MFT_STRING; 3777 mii.dwTypeData = const_cast<LPWSTR>(&strRestoreAll[0]); 3778 SetMenuItemInfoW(hMenuBase, ID_SHELL_CMD_SHOW_DESKTOP, FALSE, &mii); 3779 } 3780 3781 if (SHRestricted(REST_CLASSICSHELL) != 0) 3782 { 3783 DeleteMenu(hPopup, 3784 ID_LOCKTASKBAR, 3785 MF_BYCOMMAND); 3786 } 3787 3788 CheckMenuItem(hMenuBase, 3789 ID_LOCKTASKBAR, 3790 MF_BYCOMMAND | (g_TaskbarSettings.bLock ? MF_CHECKED : MF_UNCHECKED)); 3791 3792 UINT idCmdNext; 3793 idCmdNext = Shell_MergeMenus(hPopup, hMenuBase, indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS | MM_ADDSEPARATOR); 3794 m_idCmdCmFirst = idCmdNext - idCmdFirst; 3795 3796 ::DestroyMenu(hMenuBase); 3797 3798 if (TrayWnd->m_TrayBandSite != NULL) 3799 { 3800 pcm.Release(); 3801 if (FAILED(TrayWnd->m_TrayBandSite->AddContextMenus( 3802 hPopup, 3803 indexMenu, 3804 idCmdNext, 3805 idCmdLast, 3806 CMF_NORMAL, 3807 &pcm))) 3808 { 3809 WARN("AddContextMenus failed.\n"); 3810 pcm.Release(); 3811 } 3812 } 3813 3814 return S_OK; 3815 } 3816 3817 virtual HRESULT STDMETHODCALLTYPE 3818 InvokeCommand(LPCMINVOKECOMMANDINFO lpici) 3819 { 3820 UINT uiCmdId = PtrToUlong(lpici->lpVerb); 3821 if (uiCmdId != 0) 3822 { 3823 if (uiCmdId >= m_idCmdCmFirst) 3824 { 3825 CMINVOKECOMMANDINFO cmici = { 0 }; 3826 3827 if (pcm != NULL) 3828 { 3829 /* Setup and invoke the shell command */ 3830 cmici.cbSize = sizeof(cmici); 3831 cmici.hwnd = hWndOwner; 3832 cmici.lpVerb = (LPCSTR) MAKEINTRESOURCEW(uiCmdId - m_idCmdCmFirst); 3833 cmici.nShow = SW_NORMAL; 3834 3835 pcm->InvokeCommand(&cmici); 3836 } 3837 } 3838 else 3839 { 3840 TrayWnd->ExecContextMenuCmd(uiCmdId); 3841 } 3842 } 3843 3844 return S_OK; 3845 } 3846 3847 virtual HRESULT STDMETHODCALLTYPE 3848 GetCommandString(UINT_PTR idCmd, 3849 UINT uType, 3850 UINT *pwReserved, 3851 LPSTR pszName, 3852 UINT cchMax) 3853 { 3854 return E_NOTIMPL; 3855 } 3856 3857 CTrayWindowCtxMenu() 3858 { 3859 } 3860 3861 virtual ~CTrayWindowCtxMenu() 3862 { 3863 } 3864 3865 BEGIN_COM_MAP(CTrayWindowCtxMenu) 3866 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) 3867 END_COM_MAP() 3868 }; 3869 3870 HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu) 3871 { 3872 CTrayWindowCtxMenu * mnu = new CComObject<CTrayWindowCtxMenu>(); 3873 mnu->Initialize(TrayWnd, hWndOwner); 3874 *ppCtxMenu = mnu; 3875 return S_OK; 3876 } 3877 3878 HRESULT CreateTrayWindow(ITrayWindow ** ppTray) 3879 { 3880 CComPtr<CTrayWindow> Tray = new CComObject<CTrayWindow>(); 3881 if (Tray == NULL) 3882 return E_OUTOFMEMORY; 3883 3884 Tray->_Init(); 3885 Tray->Open(); 3886 3887 *ppTray = (ITrayWindow *) Tray; 3888 3889 return S_OK; 3890 } 3891 3892 HRESULT 3893 Tray_OnStartMenuDismissed(ITrayWindow* Tray) 3894 { 3895 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray); 3896 return TrayWindow->RaiseStartButton(); 3897 } 3898 3899 VOID TrayProcessMessages(ITrayWindow *Tray) 3900 { 3901 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray); 3902 TrayWindow->TrayProcessMessages(); 3903 } 3904 3905 VOID TrayMessageLoop(ITrayWindow *Tray) 3906 { 3907 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray); 3908 TrayWindow->TrayMessageLoop(); 3909 } 3910