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 #include <traycmd.h> 25 26 HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu); 27 28 #define WM_APP_TRAYDESTROY (WM_APP + 0x100) 29 30 #define TIMER_ID_AUTOHIDE 1 31 #define TIMER_ID_MOUSETRACK 2 32 #define MOUSETRACK_INTERVAL 100 33 #define AUTOHIDE_DELAY_HIDE 2000 34 #define AUTOHIDE_DELAY_SHOW 50 35 #define AUTOHIDE_INTERVAL_ANIMATING 10 36 37 #define AUTOHIDE_SPEED_SHOW 10 38 #define AUTOHIDE_SPEED_HIDE 1 39 40 #define AUTOHIDE_HIDDEN 0 41 #define AUTOHIDE_SHOWING 1 42 #define AUTOHIDE_SHOWN 2 43 #define AUTOHIDE_HIDING 3 44 45 #define IDHK_RUN 0x1f4 46 #define IDHK_MINIMIZE_ALL 0x1f5 47 #define IDHK_RESTORE_ALL 0x1f6 48 #define IDHK_HELP 0x1f7 49 #define IDHK_EXPLORE 0x1f8 50 #define IDHK_FIND 0x1f9 51 #define IDHK_FIND_COMPUTER 0x1fa 52 #define IDHK_NEXT_TASK 0x1fb 53 #define IDHK_PREV_TASK 0x1fc 54 #define IDHK_SYS_PROPERTIES 0x1fd 55 #define IDHK_DESKTOP 0x1fe 56 #define IDHK_PAGER 0x1ff 57 58 static const WCHAR szTrayWndClass[] = L"Shell_TrayWnd"; 59 60 struct EFFECTIVE_INFO 61 { 62 HWND hwndFound; 63 HWND hwndDesktop; 64 HWND hwndProgman; 65 HWND hTrayWnd; 66 BOOL bMustBeInMonitor; 67 }; 68 69 static BOOL CALLBACK 70 FindEffectiveProc(HWND hwnd, LPARAM lParam) 71 { 72 EFFECTIVE_INFO *pei = (EFFECTIVE_INFO *)lParam; 73 74 if (!IsWindowVisible(hwnd) || IsIconic(hwnd)) 75 return TRUE; // continue 76 77 if (pei->hTrayWnd == hwnd || pei->hwndDesktop == hwnd || 78 pei->hwndProgman == hwnd) 79 { 80 return TRUE; // continue 81 } 82 83 if (pei->bMustBeInMonitor) 84 { 85 // is the window in the nearest monitor? 86 HMONITOR hMon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); 87 if (hMon) 88 { 89 MONITORINFO info; 90 ZeroMemory(&info, sizeof(info)); 91 info.cbSize = sizeof(info); 92 if (GetMonitorInfoW(hMon, &info)) 93 { 94 RECT rcWindow, rcMonitor, rcIntersect; 95 rcMonitor = info.rcMonitor; 96 97 GetWindowRect(hwnd, &rcWindow); 98 99 if (!IntersectRect(&rcIntersect, &rcMonitor, &rcWindow)) 100 return TRUE; // continue 101 } 102 } 103 } 104 105 pei->hwndFound = hwnd; 106 return FALSE; // stop if found 107 } 108 109 static BOOL 110 IsThereAnyEffectiveWindow(BOOL bMustBeInMonitor) 111 { 112 EFFECTIVE_INFO ei; 113 ei.hwndFound = NULL; 114 ei.hwndDesktop = GetDesktopWindow(); 115 ei.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL); 116 ei.hwndProgman = FindWindowW(L"Progman", NULL); 117 ei.bMustBeInMonitor = bMustBeInMonitor; 118 119 EnumWindows(FindEffectiveProc, (LPARAM)&ei); 120 if (ei.hwndFound && FALSE) 121 { 122 WCHAR szClass[64], szText[64]; 123 GetClassNameW(ei.hwndFound, szClass, _countof(szClass)); 124 GetWindowTextW(ei.hwndFound, szText, _countof(szText)); 125 MessageBoxW(NULL, szText, szClass, 0); 126 } 127 return ei.hwndFound != NULL; 128 } 129 130 CSimpleArray<HWND> g_MinimizedAll; 131 132 /* 133 * ITrayWindow 134 */ 135 136 const GUID IID_IShellDesktopTray = { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } }; 137 138 class CStartButton 139 : public CWindowImpl<CStartButton> 140 { 141 HIMAGELIST m_ImageList; 142 SIZE m_Size; 143 HFONT m_Font; 144 145 public: 146 CStartButton() 147 : m_ImageList(NULL), 148 m_Font(NULL) 149 { 150 m_Size.cx = 0; 151 m_Size.cy = 0; 152 } 153 154 virtual ~CStartButton() 155 { 156 if (m_ImageList != NULL) 157 ImageList_Destroy(m_ImageList); 158 159 if (m_Font != NULL) 160 DeleteObject(m_Font); 161 } 162 163 SIZE GetSize() 164 { 165 return m_Size; 166 } 167 168 VOID UpdateSize() 169 { 170 SIZE Size = { 0, 0 }; 171 172 if (m_ImageList == NULL || 173 !SendMessageW(BCM_GETIDEALSIZE, 0, (LPARAM) &Size)) 174 { 175 Size.cx = 2 * GetSystemMetrics(SM_CXEDGE) + GetSystemMetrics(SM_CYCAPTION) * 3; 176 } 177 178 Size.cy = max(Size.cy, GetSystemMetrics(SM_CYCAPTION)); 179 180 /* Save the size of the start button */ 181 m_Size = Size; 182 } 183 184 VOID UpdateFont() 185 { 186 /* Get the system fonts, we use the caption font, always bold, though. */ 187 NONCLIENTMETRICS ncm = {sizeof(ncm)}; 188 if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE)) 189 return; 190 191 if (m_Font) 192 DeleteObject(m_Font); 193 194 ncm.lfCaptionFont.lfWeight = FW_BOLD; 195 m_Font = CreateFontIndirect(&ncm.lfCaptionFont); 196 197 SetFont(m_Font, FALSE); 198 } 199 200 VOID Initialize() 201 { 202 SubclassWindow(m_hWnd); 203 SetWindowTheme(m_hWnd, L"Start", NULL); 204 205 m_ImageList = ImageList_LoadImageW(hExplorerInstance, 206 MAKEINTRESOURCEW(IDB_START), 207 0, 0, 0, 208 IMAGE_BITMAP, 209 LR_LOADTRANSPARENT | LR_CREATEDIBSECTION); 210 211 BUTTON_IMAGELIST bil = {m_ImageList, {1,1,1,1}, BUTTON_IMAGELIST_ALIGN_LEFT}; 212 SendMessageW(BCM_SETIMAGELIST, 0, (LPARAM) &bil); 213 UpdateSize(); 214 } 215 216 HWND Create(HWND hwndParent) 217 { 218 WCHAR szStartCaption[32]; 219 if (!LoadStringW(hExplorerInstance, 220 IDS_START, 221 szStartCaption, 222 _countof(szStartCaption))) 223 { 224 wcscpy(szStartCaption, L"Start"); 225 } 226 227 DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | BS_PUSHBUTTON | BS_LEFT | BS_VCENTER; 228 229 m_hWnd = CreateWindowEx( 230 0, 231 WC_BUTTON, 232 szStartCaption, 233 dwStyle, 234 0, 0, 0, 0, 235 hwndParent, 236 (HMENU) IDC_STARTBTN, 237 hExplorerInstance, 238 NULL); 239 240 if (m_hWnd) 241 Initialize(); 242 243 return m_hWnd; 244 } 245 246 LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 247 { 248 if (uMsg == WM_KEYUP && wParam != VK_SPACE) 249 return 0; 250 251 GetParent().PostMessage(TWM_OPENSTARTMENU); 252 return 0; 253 } 254 255 BEGIN_MSG_MAP(CStartButton) 256 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) 257 END_MSG_MAP() 258 259 }; 260 261 class CTrayWindow : 262 public CComCoClass<CTrayWindow>, 263 public CComObjectRootEx<CComMultiThreadModelNoCS>, 264 public CWindowImpl < CTrayWindow, CWindow, CControlWinTraits >, 265 public ITrayWindow, 266 public IShellDesktopTray, 267 public IOleWindow, 268 public IContextMenu 269 { 270 CStartButton m_StartButton; 271 272 CComPtr<IMenuBand> m_StartMenuBand; 273 CComPtr<IMenuPopup> m_StartMenuPopup; 274 275 CComPtr<IDeskBand> m_TaskBand; 276 CComPtr<IContextMenu> m_ContextMenu; 277 HTHEME m_Theme; 278 279 HFONT m_Font; 280 281 HWND m_DesktopWnd; 282 HWND m_Rebar; 283 HWND m_TaskSwitch; 284 HWND m_TrayNotify; 285 286 CComPtr<IUnknown> m_TrayNotifyInstance; 287 288 DWORD m_Position; 289 HMONITOR m_Monitor; 290 HMONITOR m_PreviousMonitor; 291 DWORD m_DraggingPosition; 292 HMONITOR m_DraggingMonitor; 293 294 RECT m_TrayRects[4]; 295 SIZE m_TraySize; 296 297 HWND m_TrayPropertiesOwner; 298 HWND m_RunFileDlgOwner; 299 300 UINT m_AutoHideState; 301 SIZE m_AutoHideOffset; 302 TRACKMOUSEEVENT m_MouseTrackingInfo; 303 304 HDPA m_ShellServices; 305 306 public: 307 CComPtr<ITrayBandSite> m_TrayBandSite; 308 309 union 310 { 311 DWORD Flags; 312 struct 313 { 314 /* UI Status */ 315 DWORD InSizeMove : 1; 316 DWORD IsDragging : 1; 317 DWORD NewPosSize : 1; 318 }; 319 }; 320 321 public: 322 CTrayWindow() : 323 m_StartButton(), 324 m_Theme(NULL), 325 m_Font(NULL), 326 m_DesktopWnd(NULL), 327 m_Rebar(NULL), 328 m_TaskSwitch(NULL), 329 m_TrayNotify(NULL), 330 m_Position(0), 331 m_Monitor(NULL), 332 m_PreviousMonitor(NULL), 333 m_DraggingPosition(0), 334 m_DraggingMonitor(NULL), 335 m_TrayPropertiesOwner(NULL), 336 m_RunFileDlgOwner(NULL), 337 m_AutoHideState(NULL), 338 m_ShellServices(NULL), 339 Flags(0) 340 { 341 ZeroMemory(&m_TrayRects, sizeof(m_TrayRects)); 342 ZeroMemory(&m_TraySize, sizeof(m_TraySize)); 343 ZeroMemory(&m_AutoHideOffset, sizeof(m_AutoHideOffset)); 344 ZeroMemory(&m_MouseTrackingInfo, sizeof(m_MouseTrackingInfo)); 345 } 346 347 virtual ~CTrayWindow() 348 { 349 if (m_ShellServices != NULL) 350 { 351 ShutdownShellServices(m_ShellServices); 352 m_ShellServices = NULL; 353 } 354 355 if (m_Font != NULL) 356 { 357 DeleteObject(m_Font); 358 m_Font = NULL; 359 } 360 361 if (m_Theme) 362 { 363 CloseThemeData(m_Theme); 364 m_Theme = NULL; 365 } 366 367 PostQuitMessage(0); 368 } 369 370 371 372 373 374 /********************************************************** 375 * ##### command handling ##### 376 */ 377 378 HRESULT ExecResourceCmd(int id) 379 { 380 WCHAR szCommand[256]; 381 WCHAR *pszParameters; 382 383 if (!LoadStringW(hExplorerInstance, 384 id, 385 szCommand, 386 _countof(szCommand))) 387 { 388 return E_FAIL; 389 } 390 391 pszParameters = wcschr(szCommand, L'>'); 392 if (pszParameters) 393 { 394 *pszParameters = 0; 395 pszParameters++; 396 } 397 398 ShellExecuteW(m_hWnd, NULL, szCommand, pszParameters, NULL, SW_SHOWNORMAL); 399 return S_OK; 400 } 401 402 LRESULT DoExitWindows() 403 { 404 /* Display the ReactOS Shutdown Dialog */ 405 ExitWindowsDialog(m_hWnd); 406 407 /* 408 * If the user presses CTRL+ALT+SHIFT while exiting 409 * the shutdown dialog, exit the shell cleanly. 410 */ 411 if ((GetKeyState(VK_CONTROL) & 0x8000) && 412 (GetKeyState(VK_SHIFT) & 0x8000) && 413 (GetKeyState(VK_MENU) & 0x8000)) 414 { 415 PostMessage(WM_QUIT, 0, 0); 416 } 417 return 0; 418 } 419 420 DWORD WINAPI RunFileDlgThread() 421 { 422 HWND hwnd; 423 RECT posRect; 424 425 m_StartButton.GetWindowRect(&posRect); 426 427 hwnd = CreateWindowEx(0, 428 WC_STATIC, 429 NULL, 430 WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, 431 posRect.left, 432 posRect.top, 433 posRect.right - posRect.left, 434 posRect.bottom - posRect.top, 435 NULL, 436 NULL, 437 NULL, 438 NULL); 439 440 m_RunFileDlgOwner = hwnd; 441 442 // build the default directory from two environment variables 443 CStringW strDefaultDir, strHomePath; 444 strDefaultDir.GetEnvironmentVariable(L"HOMEDRIVE"); 445 strHomePath.GetEnvironmentVariable(L"HOMEPATH"); 446 strDefaultDir += strHomePath; 447 448 RunFileDlg(hwnd, NULL, (LPCWSTR)strDefaultDir, NULL, NULL, RFF_CALCDIRECTORY); 449 450 m_RunFileDlgOwner = NULL; 451 ::DestroyWindow(hwnd); 452 453 return 0; 454 } 455 456 static DWORD WINAPI s_RunFileDlgThread(IN OUT PVOID pParam) 457 { 458 CTrayWindow * This = (CTrayWindow*) pParam; 459 return This->RunFileDlgThread(); 460 } 461 462 void DisplayRunFileDlg() 463 { 464 HWND hRunDlg; 465 if (m_RunFileDlgOwner) 466 { 467 hRunDlg = ::GetLastActivePopup(m_RunFileDlgOwner); 468 if (hRunDlg != NULL && 469 hRunDlg != m_RunFileDlgOwner) 470 { 471 SetForegroundWindow(hRunDlg); 472 return; 473 } 474 } 475 476 CloseHandle(CreateThread(NULL, 0, s_RunFileDlgThread, this, 0, NULL)); 477 } 478 479 DWORD WINAPI TrayPropertiesThread() 480 { 481 HWND hwnd; 482 RECT posRect; 483 484 m_StartButton.GetWindowRect(&posRect); 485 hwnd = CreateWindowEx(0, 486 WC_STATIC, 487 NULL, 488 WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT, 489 posRect.left, 490 posRect.top, 491 posRect.right - posRect.left, 492 posRect.bottom - posRect.top, 493 NULL, 494 NULL, 495 NULL, 496 NULL); 497 498 m_TrayPropertiesOwner = hwnd; 499 500 DisplayTrayProperties(hwnd, m_hWnd); 501 502 m_TrayPropertiesOwner = NULL; 503 ::DestroyWindow(hwnd); 504 505 return 0; 506 } 507 508 static DWORD WINAPI s_TrayPropertiesThread(IN OUT PVOID pParam) 509 { 510 CTrayWindow *This = (CTrayWindow*) pParam; 511 512 return This->TrayPropertiesThread(); 513 } 514 515 HWND STDMETHODCALLTYPE DisplayProperties() 516 { 517 HWND hTrayProp; 518 519 if (m_TrayPropertiesOwner) 520 { 521 hTrayProp = ::GetLastActivePopup(m_TrayPropertiesOwner); 522 if (hTrayProp != NULL && 523 hTrayProp != m_TrayPropertiesOwner) 524 { 525 SetForegroundWindow(hTrayProp); 526 return NULL; 527 } 528 } 529 530 CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL)); 531 return NULL; 532 } 533 534 VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation) 535 { 536 WCHAR szDir[MAX_PATH]; 537 538 if (SHGetSpecialFolderPath(hWndOwner, 539 szDir, 540 CSIDL_COMMON_STARTMENU, 541 FALSE)) 542 { 543 ShellExecute(hWndOwner, 544 lpOperation, 545 szDir, 546 NULL, 547 NULL, 548 SW_SHOWNORMAL); 549 } 550 } 551 552 VOID OpenTaskManager(IN HWND hWndOwner) 553 { 554 ShellExecute(hWndOwner, 555 TEXT("open"), 556 TEXT("taskmgr.exe"), 557 NULL, 558 NULL, 559 SW_SHOWNORMAL); 560 } 561 562 VOID ToggleDesktop() 563 { 564 if (::IsThereAnyEffectiveWindow(TRUE)) 565 { 566 ShowDesktop(); 567 } 568 else 569 { 570 RestoreAll(); 571 } 572 } 573 574 BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd) 575 { 576 switch (uiCmd) 577 { 578 case ID_SHELL_CMD_PROPERTIES: 579 DisplayProperties(); 580 break; 581 582 case ID_SHELL_CMD_OPEN_ALL_USERS: 583 OpenCommonStartMenuDirectory(m_hWnd, 584 TEXT("open")); 585 break; 586 587 case ID_SHELL_CMD_EXPLORE_ALL_USERS: 588 OpenCommonStartMenuDirectory(m_hWnd, 589 TEXT("explore")); 590 break; 591 592 case ID_LOCKTASKBAR: 593 if (SHRestricted(REST_CLASSICSHELL) == 0) 594 { 595 Lock(!g_TaskbarSettings.bLock); 596 } 597 break; 598 599 case ID_SHELL_CMD_OPEN_TASKMGR: 600 OpenTaskManager(m_hWnd); 601 break; 602 603 case ID_SHELL_CMD_UNDO_ACTION: 604 break; 605 606 case ID_SHELL_CMD_SHOW_DESKTOP: 607 ShowDesktop(); 608 break; 609 610 case ID_SHELL_CMD_TILE_WND_H: 611 TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL); 612 break; 613 614 case ID_SHELL_CMD_TILE_WND_V: 615 TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL); 616 break; 617 618 case ID_SHELL_CMD_CASCADE_WND: 619 CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL); 620 break; 621 622 case ID_SHELL_CMD_CUST_NOTIF: 623 ShowCustomizeNotifyIcons(hExplorerInstance, m_hWnd); 624 break; 625 626 case ID_SHELL_CMD_ADJUST_DAT: 627 //FIXME: Use SHRunControlPanel 628 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL); 629 break; 630 631 case ID_SHELL_CMD_RESTORE_ALL: 632 RestoreAll(); 633 break; 634 635 default: 636 TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd); 637 return FALSE; 638 } 639 640 return TRUE; 641 } 642 643 LRESULT HandleHotKey(DWORD id) 644 { 645 switch (id) 646 { 647 case IDHK_RUN: 648 DisplayRunFileDlg(); 649 break; 650 case IDHK_HELP: 651 ExecResourceCmd(IDS_HELP_COMMAND); 652 break; 653 case IDHK_EXPLORE: 654 //FIXME: We don't support this yet: 655 //ShellExecuteW(0, L"explore", NULL, NULL, NULL, 1); 656 ShellExecuteW(0, NULL, L"explorer.exe", L"/e ,", NULL, 1); 657 break; 658 case IDHK_FIND: 659 SHFindFiles(NULL, NULL); 660 break; 661 case IDHK_FIND_COMPUTER: 662 SHFindComputer(NULL, NULL); 663 break; 664 case IDHK_SYS_PROPERTIES: 665 //FIXME: Use SHRunControlPanel 666 ShellExecuteW(m_hWnd, NULL, L"sysdm.cpl", NULL, NULL, SW_NORMAL); 667 break; 668 case IDHK_NEXT_TASK: 669 break; 670 case IDHK_PREV_TASK: 671 break; 672 case IDHK_MINIMIZE_ALL: 673 MinimizeAll(); 674 break; 675 case IDHK_RESTORE_ALL: 676 RestoreAll(); 677 break; 678 case IDHK_DESKTOP: 679 ToggleDesktop(); 680 break; 681 case IDHK_PAGER: 682 break; 683 } 684 685 return 0; 686 } 687 688 LRESULT HandleCommand(UINT uCommand) 689 { 690 switch (uCommand) 691 { 692 case TRAYCMD_STARTMENU: 693 // TODO: 694 break; 695 case TRAYCMD_RUN_DIALOG: 696 DisplayRunFileDlg(); 697 break; 698 case TRAYCMD_LOGOFF_DIALOG: 699 LogoffWindowsDialog(m_hWnd); // FIXME: Maybe handle it in a similar way as DoExitWindows? 700 break; 701 case TRAYCMD_CASCADE: 702 CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL); 703 break; 704 case TRAYCMD_TILE_H: 705 TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL); 706 break; 707 case TRAYCMD_TILE_V: 708 TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL); 709 break; 710 case TRAYCMD_TOGGLE_DESKTOP: 711 ToggleDesktop(); 712 break; 713 case TRAYCMD_DATE_AND_TIME: 714 ShellExecuteW(m_hWnd, NULL, L"timedate.cpl", NULL, NULL, SW_NORMAL); 715 break; 716 case TRAYCMD_TASKBAR_PROPERTIES: 717 DisplayProperties(); 718 break; 719 case TRAYCMD_MINIMIZE_ALL: 720 MinimizeAll(); 721 break; 722 case TRAYCMD_RESTORE_ALL: 723 RestoreAll(); 724 break; 725 case TRAYCMD_SHOW_DESKTOP: 726 ShowDesktop(); 727 break; 728 case TRAYCMD_SHOW_TASK_MGR: 729 OpenTaskManager(m_hWnd); 730 break; 731 case TRAYCMD_CUSTOMIZE_TASKBAR: 732 break; 733 case TRAYCMD_LOCK_TASKBAR: 734 if (SHRestricted(REST_CLASSICSHELL) == 0) 735 { 736 Lock(!g_TaskbarSettings.bLock); 737 } 738 break; 739 case TRAYCMD_HELP_AND_SUPPORT: 740 ExecResourceCmd(IDS_HELP_COMMAND); 741 break; 742 case TRAYCMD_CONTROL_PANEL: 743 // TODO: 744 break; 745 case TRAYCMD_SHUTDOWN_DIALOG: 746 DoExitWindows(); 747 break; 748 case TRAYCMD_PRINTERS_AND_FAXES: 749 // TODO: 750 break; 751 case TRAYCMD_LOCK_DESKTOP: 752 // TODO: 753 break; 754 case TRAYCMD_SWITCH_USER_DIALOG: 755 // TODO: 756 break; 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 StartMenuBtnCtxMenuCreator(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 OnHotkey(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2805 { 2806 return HandleHotKey(wParam); 2807 } 2808 2809 struct MINIMIZE_INFO 2810 { 2811 HWND hwndDesktop; 2812 HWND hTrayWnd; 2813 HWND hwndProgman; 2814 BOOL bRet; 2815 CSimpleArray<HWND> *pMinimizedAll; 2816 BOOL bShowDesktop; 2817 }; 2818 2819 static BOOL IsDialog(HWND hwnd) 2820 { 2821 WCHAR szClass[32]; 2822 GetClassNameW(hwnd, szClass, _countof(szClass)); 2823 return wcscmp(szClass, L"#32770") == 0; 2824 } 2825 2826 static BOOL CALLBACK MinimizeWindowsProc(HWND hwnd, LPARAM lParam) 2827 { 2828 MINIMIZE_INFO *info = (MINIMIZE_INFO *)lParam; 2829 if (hwnd == info->hwndDesktop || hwnd == info->hTrayWnd || 2830 hwnd == info->hwndProgman) 2831 { 2832 return TRUE; 2833 } 2834 if (!info->bShowDesktop) 2835 { 2836 if (!::IsWindowEnabled(hwnd) || IsDialog(hwnd)) 2837 return TRUE; 2838 HWND hwndOwner = ::GetWindow(hwnd, GW_OWNER); 2839 if (hwndOwner && !::IsWindowEnabled(hwndOwner)) 2840 return TRUE; 2841 } 2842 if (::IsWindowVisible(hwnd) && !::IsIconic(hwnd)) 2843 { 2844 ::ShowWindowAsync(hwnd, SW_MINIMIZE); 2845 info->bRet = TRUE; 2846 info->pMinimizedAll->Add(hwnd); 2847 } 2848 return TRUE; 2849 } 2850 2851 VOID MinimizeAll(BOOL bShowDesktop = FALSE) 2852 { 2853 MINIMIZE_INFO info; 2854 info.hwndDesktop = GetDesktopWindow();; 2855 info.hTrayWnd = FindWindowW(L"Shell_TrayWnd", NULL); 2856 info.hwndProgman = FindWindowW(L"Progman", NULL); 2857 info.bRet = FALSE; 2858 info.pMinimizedAll = &g_MinimizedAll; 2859 info.bShowDesktop = bShowDesktop; 2860 EnumWindows(MinimizeWindowsProc, (LPARAM)&info); 2861 2862 // invalid handles should be cleared to avoid mismatch of handles 2863 for (INT i = 0; i < g_MinimizedAll.GetSize(); ++i) 2864 { 2865 if (!::IsWindow(g_MinimizedAll[i])) 2866 g_MinimizedAll[i] = NULL; 2867 } 2868 2869 ::SetForegroundWindow(m_DesktopWnd); 2870 ::SetFocus(m_DesktopWnd); 2871 } 2872 2873 VOID ShowDesktop() 2874 { 2875 MinimizeAll(TRUE); 2876 } 2877 2878 VOID RestoreAll() 2879 { 2880 for (INT i = g_MinimizedAll.GetSize() - 1; i >= 0; --i) 2881 { 2882 HWND hwnd = g_MinimizedAll[i]; 2883 if (::IsWindowVisible(hwnd) && ::IsIconic(hwnd)) 2884 { 2885 ::ShowWindow(hwnd, SW_RESTORE); 2886 } 2887 } 2888 g_MinimizedAll.RemoveAll(); 2889 } 2890 2891 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2892 { 2893 LRESULT Ret = FALSE; 2894 2895 if ((HWND) lParam == m_StartButton.m_hWnd) 2896 { 2897 return FALSE; 2898 } 2899 2900 if (m_TrayBandSite == NULL || FAILED_UNEXPECTEDLY(m_TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret))) 2901 { 2902 return HandleCommand(LOWORD(wParam)); 2903 } 2904 return Ret; 2905 } 2906 2907 LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2908 { 2909 if (g_TaskbarSettings.sr.AutoHide) 2910 { 2911 SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); 2912 } 2913 2914 return TRUE; 2915 } 2916 2917 LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2918 { 2919 if (wParam == TIMER_ID_MOUSETRACK) 2920 { 2921 ProcessMouseTracking(); 2922 } 2923 else if (wParam == TIMER_ID_AUTOHIDE) 2924 { 2925 ProcessAutoHide(); 2926 } 2927 2928 bHandled = FALSE; 2929 return TRUE; 2930 } 2931 2932 LRESULT OnNcCalcSize(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2933 { 2934 RECT *rc = NULL; 2935 /* Ignore WM_NCCALCSIZE if we are not themed or locked */ 2936 if(!m_Theme || g_TaskbarSettings.bLock) 2937 { 2938 bHandled = FALSE; 2939 return 0; 2940 } 2941 if(!wParam) 2942 { 2943 rc = (RECT*)wParam; 2944 } 2945 else 2946 { 2947 NCCALCSIZE_PARAMS *prms = (NCCALCSIZE_PARAMS*)lParam; 2948 if(prms->lppos->flags & SWP_NOSENDCHANGING) 2949 { 2950 bHandled = FALSE; 2951 return 0; 2952 } 2953 rc = &prms->rgrc[0]; 2954 } 2955 2956 AdjustSizerRect(rc, m_Position); 2957 2958 return 0; 2959 } 2960 2961 LRESULT OnInitMenuPopup(INT code, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 2962 { 2963 HMENU hMenu = (HMENU)wParam; 2964 if (::IsThereAnyEffectiveWindow(FALSE)) 2965 { 2966 ::EnableMenuItem(hMenu, ID_SHELL_CMD_CASCADE_WND, MF_BYCOMMAND | MF_ENABLED); 2967 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_H, MF_BYCOMMAND | MF_ENABLED); 2968 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_V, MF_BYCOMMAND | MF_ENABLED); 2969 } 2970 else 2971 { 2972 ::EnableMenuItem(hMenu, ID_SHELL_CMD_CASCADE_WND, MF_BYCOMMAND | MF_GRAYED); 2973 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_H, MF_BYCOMMAND | MF_GRAYED); 2974 ::EnableMenuItem(hMenu, ID_SHELL_CMD_TILE_WND_V, MF_BYCOMMAND | MF_GRAYED); 2975 } 2976 return 0; 2977 } 2978 2979 LRESULT OnRebarAutoSize(INT code, LPNMHDR nmhdr, BOOL& bHandled) 2980 { 2981 #if 0 2982 LPNMRBAUTOSIZE as = (LPNMRBAUTOSIZE) nmhdr; 2983 2984 if (!as->fChanged) 2985 return 0; 2986 2987 RECT rc; 2988 ::GetWindowRect(m_hWnd, &rc); 2989 2990 SIZE szWindow = { 2991 rc.right - rc.left, 2992 rc.bottom - rc.top }; 2993 SIZE szTarget = { 2994 as->rcTarget.right - as->rcTarget.left, 2995 as->rcTarget.bottom - as->rcTarget.top }; 2996 SIZE szActual = { 2997 as->rcActual.right - as->rcActual.left, 2998 as->rcActual.bottom - as->rcActual.top }; 2999 3000 SIZE borders = { 3001 szWindow.cx - szTarget.cx, 3002 szWindow.cy - szTarget.cx, 3003 }; 3004 3005 switch (m_Position) 3006 { 3007 case ABE_LEFT: 3008 szWindow.cx = szActual.cx + borders.cx; 3009 break; 3010 case ABE_TOP: 3011 szWindow.cy = szActual.cy + borders.cy; 3012 break; 3013 case ABE_RIGHT: 3014 szWindow.cx = szActual.cx + borders.cx; 3015 rc.left = rc.right - szWindow.cy; 3016 break; 3017 case ABE_BOTTOM: 3018 szWindow.cy = szActual.cy + borders.cy; 3019 rc.top = rc.bottom - szWindow.cy; 3020 break; 3021 } 3022 3023 SetWindowPos(NULL, rc.left, rc.top, szWindow.cx, szWindow.cy, SWP_NOACTIVATE | SWP_NOZORDER); 3024 #else 3025 bHandled = FALSE; 3026 #endif 3027 return 0; 3028 } 3029 3030 LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) 3031 { 3032 TaskbarSettings* newSettings = (TaskbarSettings*)lParam; 3033 3034 /* Propagate the new settings to the children */ 3035 ::SendMessageW(m_TaskSwitch, uMsg, wParam, lParam); 3036 ::SendMessageW(m_TrayNotify, uMsg, wParam, lParam); 3037 3038 /* Toggle autohide */ 3039 if (newSettings->sr.AutoHide != g_TaskbarSettings.sr.AutoHide) 3040 { 3041 g_TaskbarSettings.sr.AutoHide = newSettings->sr.AutoHide; 3042 memset(&m_AutoHideOffset, 0, sizeof(m_AutoHideOffset)); 3043 m_AutoHideState = AUTOHIDE_SHOWN; 3044 if (!newSettings->sr.AutoHide) 3045 SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER); 3046 else 3047 SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL); 3048 } 3049 3050 /* Toggle lock state */ 3051 Lock(newSettings->bLock); 3052 3053 /* Toggle OnTop state */ 3054 if (newSettings->sr.AlwaysOnTop != g_TaskbarSettings.sr.AlwaysOnTop) 3055 { 3056 g_TaskbarSettings.sr.AlwaysOnTop = newSettings->sr.AlwaysOnTop; 3057 HWND hWndInsertAfter = newSettings->sr.AlwaysOnTop ? HWND_TOPMOST : HWND_BOTTOM; 3058 SetWindowPos(hWndInsertAfter, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 3059 } 3060 3061 g_TaskbarSettings.Save(); 3062 return 0; 3063 } 3064 3065 DECLARE_WND_CLASS_EX(szTrayWndClass, CS_DBLCLKS, COLOR_3DFACE) 3066 3067 BEGIN_MSG_MAP(CTrayWindow) 3068 if (m_StartMenuBand != NULL) 3069 { 3070 MSG Msg; 3071 LRESULT lRet; 3072 3073 Msg.hwnd = m_hWnd; 3074 Msg.message = uMsg; 3075 Msg.wParam = wParam; 3076 Msg.lParam = lParam; 3077 3078 if (m_StartMenuBand->TranslateMenuMessage(&Msg, &lRet) == S_OK) 3079 { 3080 return lRet; 3081 } 3082 3083 wParam = Msg.wParam; 3084 lParam = Msg.lParam; 3085 } 3086 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) 3087 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChanged) 3088 NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnRebarAutoSize) // Doesn't quite work ;P 3089 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) 3090 MESSAGE_HANDLER(WM_SIZE, OnSize) 3091 MESSAGE_HANDLER(WM_CREATE, OnCreate) 3092 /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/ 3093 MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest) 3094 MESSAGE_HANDLER(WM_COMMAND, OnCommand) 3095 MESSAGE_HANDLER(WM_SYSCOMMAND, OnSysCommand) 3096 MESSAGE_HANDLER(WM_NOTIFY, OnNotify) 3097 MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu) 3098 MESSAGE_HANDLER(WM_TIMER, OnTimer) 3099 MESSAGE_HANDLER(WM_DISPLAYCHANGE, OnDisplayChange) 3100 MESSAGE_HANDLER(WM_COPYDATA, OnCopyData) 3101 MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint) 3102 MESSAGE_HANDLER(WM_CTLCOLORBTN, OnCtlColorBtn) 3103 MESSAGE_HANDLER(WM_MOVING, OnMoving) 3104 MESSAGE_HANDLER(WM_SIZING, OnSizing) 3105 MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChanging) 3106 MESSAGE_HANDLER(WM_ENTERSIZEMOVE, OnEnterSizeMove) 3107 MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove) 3108 MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDown) 3109 MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar) 3110 MESSAGE_HANDLER(WM_NCRBUTTONUP, OnNcRButtonUp) 3111 MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClick) 3112 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) 3113 MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseMove) 3114 MESSAGE_HANDLER(WM_APP_TRAYDESTROY, OnAppTrayDestroy) 3115 MESSAGE_HANDLER(WM_CLOSE, OnDoExitWindows) 3116 MESSAGE_HANDLER(WM_HOTKEY, OnHotkey) 3117 MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize) 3118 MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup) 3119 MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged) 3120 MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu) 3121 MESSAGE_HANDLER(TWM_DOEXITWINDOWS, OnDoExitWindows) 3122 ALT_MSG_MAP(1) 3123 END_MSG_MAP() 3124 3125 /*****************************************************************************/ 3126 3127 VOID TrayProcessMessages() 3128 { 3129 MSG Msg; 3130 3131 /* FIXME: We should keep a reference here... */ 3132 3133 while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) 3134 { 3135 if (Msg.message == WM_QUIT) 3136 break; 3137 3138 if (m_StartMenuBand == NULL || 3139 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK) 3140 { 3141 TranslateMessage(&Msg); 3142 DispatchMessage(&Msg); 3143 } 3144 } 3145 } 3146 3147 VOID TrayMessageLoop() 3148 { 3149 MSG Msg; 3150 BOOL Ret; 3151 3152 /* FIXME: We should keep a reference here... */ 3153 3154 while (true) 3155 { 3156 Ret = GetMessage(&Msg, NULL, 0, 0); 3157 3158 if (!Ret || Ret == -1) 3159 break; 3160 3161 if (m_StartMenuBand == NULL || 3162 m_StartMenuBand->IsMenuMessage(&Msg) != S_OK) 3163 { 3164 TranslateMessage(&Msg); 3165 DispatchMessage(&Msg); 3166 } 3167 } 3168 } 3169 3170 /* 3171 * IShellDesktopTray 3172 * 3173 * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()! 3174 * These are the calls I observed, it may be wrong/incomplete/buggy!!! 3175 * The reason we implement it is because we have to use SHCreateDesktop() so 3176 * that the shell provides the desktop window and all the features that come 3177 * with it (especially positioning of desktop icons) 3178 */ 3179 3180 virtual ULONG STDMETHODCALLTYPE GetState() 3181 { 3182 /* FIXME: Return ABS_ flags? */ 3183 TRACE("IShellDesktopTray::GetState() unimplemented!\n"); 3184 return 0; 3185 } 3186 3187 virtual HRESULT STDMETHODCALLTYPE GetTrayWindow(OUT HWND *phWndTray) 3188 { 3189 TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray); 3190 *phWndTray = m_hWnd; 3191 return S_OK; 3192 } 3193 3194 virtual HRESULT STDMETHODCALLTYPE RegisterDesktopWindow(IN HWND hWndDesktop) 3195 { 3196 TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop); 3197 3198 m_DesktopWnd = hWndDesktop; 3199 return S_OK; 3200 } 3201 3202 virtual HRESULT STDMETHODCALLTYPE Unknown(IN DWORD dwUnknown1, IN DWORD dwUnknown2) 3203 { 3204 TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2); 3205 return S_OK; 3206 } 3207 3208 virtual HRESULT RaiseStartButton() 3209 { 3210 m_StartButton.SendMessageW(BM_SETSTATE, FALSE, 0); 3211 return S_OK; 3212 } 3213 3214 HRESULT WINAPI GetWindow(HWND* phwnd) 3215 { 3216 if (!phwnd) 3217 return E_INVALIDARG; 3218 *phwnd = m_hWnd; 3219 return S_OK; 3220 } 3221 3222 HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode) 3223 { 3224 return E_NOTIMPL; 3225 } 3226 3227 void _Init() 3228 { 3229 m_Position = (DWORD) -1; 3230 } 3231 3232 DECLARE_NOT_AGGREGATABLE(CTrayWindow) 3233 3234 DECLARE_PROTECT_FINAL_CONSTRUCT() 3235 BEGIN_COM_MAP(CTrayWindow) 3236 /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/ 3237 COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray, IShellDesktopTray) 3238 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 3239 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) 3240 END_COM_MAP() 3241 }; 3242 3243 class CTrayWindowCtxMenu : 3244 public CComCoClass<CTrayWindowCtxMenu>, 3245 public CComObjectRootEx<CComMultiThreadModelNoCS>, 3246 public IContextMenu 3247 { 3248 HWND hWndOwner; 3249 CComPtr<CTrayWindow> TrayWnd; 3250 CComPtr<IContextMenu> pcm; 3251 UINT m_idCmdCmFirst; 3252 3253 public: 3254 HRESULT Initialize(ITrayWindow * pTrayWnd, IN HWND hWndOwner) 3255 { 3256 this->TrayWnd = (CTrayWindow *) pTrayWnd; 3257 this->hWndOwner = hWndOwner; 3258 this->m_idCmdCmFirst = 0; 3259 return S_OK; 3260 } 3261 3262 virtual HRESULT STDMETHODCALLTYPE 3263 QueryContextMenu(HMENU hPopup, 3264 UINT indexMenu, 3265 UINT idCmdFirst, 3266 UINT idCmdLast, 3267 UINT uFlags) 3268 { 3269 HMENU hMenuBase; 3270 3271 hMenuBase = LoadPopupMenu(hExplorerInstance, MAKEINTRESOURCEW(IDM_TRAYWND)); 3272 3273 if (g_MinimizedAll.GetSize() != 0 && !::IsThereAnyEffectiveWindow(TRUE)) 3274 { 3275 CStringW strRestoreAll(MAKEINTRESOURCEW(IDS_RESTORE_ALL)); 3276 MENUITEMINFOW mii = { sizeof(mii) }; 3277 mii.fMask = MIIM_ID | MIIM_TYPE; 3278 mii.wID = ID_SHELL_CMD_RESTORE_ALL; 3279 mii.fType = MFT_STRING; 3280 mii.dwTypeData = const_cast<LPWSTR>(&strRestoreAll[0]); 3281 SetMenuItemInfoW(hMenuBase, ID_SHELL_CMD_SHOW_DESKTOP, FALSE, &mii); 3282 } 3283 3284 if (!hMenuBase) 3285 return HRESULT_FROM_WIN32(GetLastError()); 3286 3287 if (SHRestricted(REST_CLASSICSHELL) != 0) 3288 { 3289 DeleteMenu(hPopup, 3290 ID_LOCKTASKBAR, 3291 MF_BYCOMMAND); 3292 } 3293 3294 CheckMenuItem(hMenuBase, 3295 ID_LOCKTASKBAR, 3296 MF_BYCOMMAND | (g_TaskbarSettings.bLock ? MF_CHECKED : MF_UNCHECKED)); 3297 3298 UINT idCmdNext; 3299 idCmdNext = Shell_MergeMenus(hPopup, hMenuBase, indexMenu, idCmdFirst, idCmdLast, MM_SUBMENUSHAVEIDS | MM_ADDSEPARATOR); 3300 m_idCmdCmFirst = idCmdNext - idCmdFirst; 3301 3302 ::DestroyMenu(hMenuBase); 3303 3304 if (TrayWnd->m_TrayBandSite != NULL) 3305 { 3306 if (FAILED(TrayWnd->m_TrayBandSite->AddContextMenus( 3307 hPopup, 3308 indexMenu, 3309 idCmdNext, 3310 idCmdLast, 3311 CMF_NORMAL, 3312 &pcm))) 3313 { 3314 WARN("AddContextMenus failed.\n"); 3315 pcm = NULL; 3316 } 3317 } 3318 3319 return S_OK; 3320 } 3321 3322 virtual HRESULT STDMETHODCALLTYPE 3323 InvokeCommand(LPCMINVOKECOMMANDINFO lpici) 3324 { 3325 UINT uiCmdId = PtrToUlong(lpici->lpVerb); 3326 if (uiCmdId != 0) 3327 { 3328 if (uiCmdId >= m_idCmdCmFirst) 3329 { 3330 CMINVOKECOMMANDINFO cmici = { 0 }; 3331 3332 if (pcm != NULL) 3333 { 3334 /* Setup and invoke the shell command */ 3335 cmici.cbSize = sizeof(cmici); 3336 cmici.hwnd = hWndOwner; 3337 cmici.lpVerb = (LPCSTR) MAKEINTRESOURCEW(uiCmdId - m_idCmdCmFirst); 3338 cmici.nShow = SW_NORMAL; 3339 3340 pcm->InvokeCommand(&cmici); 3341 } 3342 } 3343 else 3344 { 3345 TrayWnd->ExecContextMenuCmd(uiCmdId); 3346 } 3347 } 3348 3349 return S_OK; 3350 } 3351 3352 virtual HRESULT STDMETHODCALLTYPE 3353 GetCommandString(UINT_PTR idCmd, 3354 UINT uType, 3355 UINT *pwReserved, 3356 LPSTR pszName, 3357 UINT cchMax) 3358 { 3359 return E_NOTIMPL; 3360 } 3361 3362 CTrayWindowCtxMenu() 3363 { 3364 } 3365 3366 virtual ~CTrayWindowCtxMenu() 3367 { 3368 } 3369 3370 BEGIN_COM_MAP(CTrayWindowCtxMenu) 3371 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) 3372 END_COM_MAP() 3373 }; 3374 3375 HRESULT TrayWindowCtxMenuCreator(ITrayWindow * TrayWnd, IN HWND hWndOwner, IContextMenu ** ppCtxMenu) 3376 { 3377 CTrayWindowCtxMenu * mnu = new CComObject<CTrayWindowCtxMenu>(); 3378 mnu->Initialize(TrayWnd, hWndOwner); 3379 *ppCtxMenu = mnu; 3380 return S_OK; 3381 } 3382 3383 HRESULT CreateTrayWindow(ITrayWindow ** ppTray) 3384 { 3385 CComPtr<CTrayWindow> Tray = new CComObject<CTrayWindow>(); 3386 if (Tray == NULL) 3387 return E_OUTOFMEMORY; 3388 3389 Tray->_Init(); 3390 Tray->Open(); 3391 3392 *ppTray = (ITrayWindow *) Tray; 3393 3394 return S_OK; 3395 } 3396 3397 HRESULT 3398 Tray_OnStartMenuDismissed(ITrayWindow* Tray) 3399 { 3400 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray); 3401 return TrayWindow->RaiseStartButton(); 3402 } 3403 3404 VOID TrayProcessMessages(ITrayWindow *Tray) 3405 { 3406 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray); 3407 TrayWindow->TrayProcessMessages(); 3408 } 3409 3410 VOID TrayMessageLoop(ITrayWindow *Tray) 3411 { 3412 CTrayWindow * TrayWindow = static_cast<CTrayWindow *>(Tray); 3413 TrayWindow->TrayMessageLoop(); 3414 } 3415