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