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