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