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