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