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