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