1 /* 2 * Shell Desktop 3 * 4 * Copyright 2008 Thomas Bluemel 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 St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include "shelldesktop.h" 22 23 // Support for multiple monitors is disabled till LVM_SETWORKAREAS gets implemented 24 #ifdef MULTIMONITOR_SUPPORT 25 #include <atlcoll.h> 26 #endif 27 28 29 30 WINE_DEFAULT_DEBUG_CHANNEL(desktop); 31 32 static const WCHAR szProgmanClassName[] = L"Progman"; 33 static const WCHAR szProgmanWindowName[] = L"Program Manager"; 34 35 class CDesktopBrowser : 36 public CWindowImpl<CDesktopBrowser, CWindow, CFrameWinTraits>, 37 public CComObjectRootEx<CComMultiThreadModelNoCS>, 38 public IShellBrowser, 39 public IServiceProvider 40 { 41 private: 42 HACCEL m_hAccel; 43 HWND m_hWndShellView; 44 CComPtr<IShellDesktopTray> m_Tray; 45 CComPtr<IShellView> m_ShellView; 46 47 LRESULT _NotifyTray(UINT uMsg, WPARAM wParam, LPARAM lParam); 48 HRESULT _Resize(); 49 50 public: 51 CDesktopBrowser(); 52 ~CDesktopBrowser(); 53 HRESULT Initialize(IShellDesktopTray *ShellDeskx); 54 55 // *** IOleWindow methods *** 56 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd); 57 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode); 58 59 // *** IShellBrowser methods *** 60 virtual HRESULT STDMETHODCALLTYPE InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths); 61 virtual HRESULT STDMETHODCALLTYPE SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject); 62 virtual HRESULT STDMETHODCALLTYPE RemoveMenusSB(HMENU hmenuShared); 63 virtual HRESULT STDMETHODCALLTYPE SetStatusTextSB(LPCOLESTR pszStatusText); 64 virtual HRESULT STDMETHODCALLTYPE EnableModelessSB(BOOL fEnable); 65 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorSB(MSG *pmsg, WORD wID); 66 virtual HRESULT STDMETHODCALLTYPE BrowseObject(LPCITEMIDLIST pidl, UINT wFlags); 67 virtual HRESULT STDMETHODCALLTYPE GetViewStateStream(DWORD grfMode, IStream **ppStrm); 68 virtual HRESULT STDMETHODCALLTYPE GetControlWindow(UINT id, HWND *lphwnd); 69 virtual HRESULT STDMETHODCALLTYPE SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret); 70 virtual HRESULT STDMETHODCALLTYPE QueryActiveShellView(struct IShellView **ppshv); 71 virtual HRESULT STDMETHODCALLTYPE OnViewWindowActive(struct IShellView *ppshv); 72 virtual HRESULT STDMETHODCALLTYPE SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags); 73 74 // *** IServiceProvider methods *** 75 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject); 76 77 // message handlers 78 LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 79 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 80 LRESULT OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 81 LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 82 LRESULT OnOpenNewWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 83 LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 84 LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled); 85 86 DECLARE_WND_CLASS_EX(szProgmanClassName, CS_DBLCLKS, COLOR_DESKTOP) 87 88 BEGIN_MSG_MAP(CBaseBar) 89 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd) 90 MESSAGE_HANDLER(WM_SIZE, OnSize) 91 MESSAGE_HANDLER(WM_SYSCOLORCHANGE, OnSettingChange) 92 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) 93 MESSAGE_HANDLER(WM_CLOSE, OnClose) 94 MESSAGE_HANDLER(WM_EXPLORER_OPEN_NEW_WINDOW, OnOpenNewWindow) 95 MESSAGE_HANDLER(WM_COMMAND, OnCommand) 96 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) 97 END_MSG_MAP() 98 99 BEGIN_COM_MAP(CDesktopBrowser) 100 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow) 101 COM_INTERFACE_ENTRY_IID(IID_IShellBrowser, IShellBrowser) 102 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider) 103 END_COM_MAP() 104 }; 105 106 CDesktopBrowser::CDesktopBrowser(): 107 m_hAccel(NULL), 108 m_hWndShellView(NULL) 109 { 110 } 111 112 CDesktopBrowser::~CDesktopBrowser() 113 { 114 if (m_ShellView.p != NULL && m_hWndShellView != NULL) 115 { 116 m_ShellView->DestroyViewWindow(); 117 } 118 } 119 120 #ifdef MULTIMONITOR_SUPPORT 121 BOOL CALLBACK MonitorEnumProc( 122 _In_ HMONITOR hMonitor, 123 _In_ HDC hdcMonitor, 124 _In_ LPRECT lprcMonitor, 125 _In_ LPARAM dwData 126 ) 127 { 128 CAtlList<RECT> *list = (CAtlList<RECT>*)dwData; 129 MONITORINFO MonitorInfo; 130 MonitorInfo.cbSize = sizeof(MonitorInfo); 131 if (::GetMonitorInfoW(hMonitor, &MonitorInfo)) 132 { 133 list->AddTail(MonitorInfo.rcWork); 134 } 135 136 return TRUE; 137 } 138 #endif 139 140 HRESULT CDesktopBrowser::_Resize() 141 { 142 RECT rcNewSize; 143 144 #ifdef MULTIMONITOR_SUPPORT 145 146 UINT cMonitors = GetSystemMetrics(SM_CMONITORS); 147 if (cMonitors == 1) 148 { 149 SystemParametersInfoW(SPI_GETWORKAREA, 0, &rcNewSize, 0); 150 } 151 else 152 { 153 SetRect(&rcNewSize, 154 GetSystemMetrics(SM_XVIRTUALSCREEN), 155 GetSystemMetrics(SM_YVIRTUALSCREEN), 156 GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN), 157 GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN)); 158 } 159 160 ::MoveWindow(m_hWnd, rcNewSize.left, rcNewSize.top, rcNewSize.right - rcNewSize.left, rcNewSize.bottom - rcNewSize.top, TRUE); 161 ::MoveWindow(m_hWndShellView, 0, 0, rcNewSize.right - rcNewSize.left, rcNewSize.bottom - rcNewSize.top, TRUE); 162 163 if (cMonitors != 1) 164 { 165 CAtlList<RECT> list; 166 EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&list); 167 RECT* prcWorkAreas = new RECT[list.GetCount()]; 168 int i = 0; 169 for (POSITION it = list.GetHeadPosition(); it; list.GetNext(it)) 170 prcWorkAreas[i++] = list.GetAt(it); 171 172 HWND hwndListView = FindWindowExW(m_hWndShellView, NULL, WC_LISTVIEW, NULL); 173 174 ::SendMessageW(hwndListView, LVM_SETWORKAREAS , i, (LPARAM)prcWorkAreas); 175 } 176 177 #else 178 SystemParametersInfoW(SPI_GETWORKAREA, 0, &rcNewSize, 0); 179 ::MoveWindow(m_hWnd, rcNewSize.left, rcNewSize.top, rcNewSize.right - rcNewSize.left, rcNewSize.bottom - rcNewSize.top, TRUE); 180 ::MoveWindow(m_hWndShellView, 0, 0, rcNewSize.right - rcNewSize.left, rcNewSize.bottom - rcNewSize.top, TRUE); 181 182 #endif 183 return S_OK; 184 } 185 186 HRESULT CDesktopBrowser::Initialize(IShellDesktopTray *ShellDesk) 187 { 188 CComPtr<IShellFolder> psfDesktop; 189 HRESULT hRet; 190 hRet = SHGetDesktopFolder(&psfDesktop); 191 if (FAILED_UNEXPECTEDLY(hRet)) 192 return hRet; 193 194 m_Tray = ShellDesk; 195 196 Create(NULL, NULL, szProgmanWindowName, WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_TOOLWINDOW); 197 if (!m_hWnd) 198 return E_FAIL; 199 200 CSFV csfv = {sizeof(CSFV), psfDesktop}; 201 hRet = SHCreateShellFolderViewEx(&csfv, &m_ShellView); 202 if (FAILED_UNEXPECTEDLY(hRet)) 203 return hRet; 204 205 m_Tray->RegisterDesktopWindow(m_hWnd); 206 if (FAILED_UNEXPECTEDLY(hRet)) 207 return hRet; 208 209 FOLDERSETTINGS fs; 210 RECT rcShellView = {0,0,0,0}; 211 fs.ViewMode = FVM_ICON; 212 fs.fFlags = FWF_DESKTOP | FWF_NOCLIENTEDGE | FWF_NOSCROLL | FWF_TRANSPARENT; 213 hRet = m_ShellView->CreateViewWindow(NULL, &fs, (IShellBrowser *)this, &rcShellView, &m_hWndShellView); 214 if (FAILED_UNEXPECTEDLY(hRet)) 215 return hRet; 216 217 _Resize(); 218 219 HWND hwndListView = FindWindowExW(m_hWndShellView, NULL, WC_LISTVIEW, NULL); 220 SetShellWindowEx(m_hWnd, hwndListView); 221 222 m_hAccel = LoadAcceleratorsW(shell32_hInstance, MAKEINTRESOURCEW(IDA_DESKBROWSER)); 223 224 #if 1 225 /* A Windows8+ specific hack */ 226 ::ShowWindow(m_hWndShellView, SW_SHOW); 227 ::ShowWindow(hwndListView, SW_SHOW); 228 #endif 229 ShowWindow(SW_SHOW); 230 UpdateWindow(); 231 232 return hRet; 233 } 234 235 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetWindow(HWND *lphwnd) 236 { 237 if (lphwnd == NULL) 238 return E_POINTER; 239 *lphwnd = m_hWnd; 240 return S_OK; 241 } 242 243 HRESULT STDMETHODCALLTYPE CDesktopBrowser::ContextSensitiveHelp(BOOL fEnterMode) 244 { 245 return E_NOTIMPL; 246 } 247 248 HRESULT STDMETHODCALLTYPE CDesktopBrowser::InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths) 249 { 250 return E_NOTIMPL; 251 } 252 253 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject) 254 { 255 return E_NOTIMPL; 256 } 257 258 HRESULT STDMETHODCALLTYPE CDesktopBrowser::RemoveMenusSB(HMENU hmenuShared) 259 { 260 return E_NOTIMPL; 261 } 262 263 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText) 264 { 265 return E_NOTIMPL; 266 } 267 268 HRESULT STDMETHODCALLTYPE CDesktopBrowser::EnableModelessSB(BOOL fEnable) 269 { 270 return E_NOTIMPL; 271 } 272 273 HRESULT STDMETHODCALLTYPE CDesktopBrowser::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID) 274 { 275 if (!::TranslateAcceleratorW(m_hWnd, m_hAccel, lpmsg)) 276 return S_FALSE; 277 return S_OK; 278 } 279 280 HRESULT STDMETHODCALLTYPE CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags) 281 { 282 /* 283 * We should use IShellWindows interface here in order to attempt to 284 * find an open shell window that shows the requested pidl and activate it 285 */ 286 287 DWORD dwFlags = ((wFlags & SBSP_EXPLOREMODE) != 0) ? SH_EXPLORER_CMDLINE_FLAG_E : 0; 288 return SHOpenNewFrame(ILClone(pidl), NULL, 0, dwFlags); 289 } 290 291 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm) 292 { 293 return E_NOTIMPL; 294 } 295 296 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetControlWindow(UINT id, HWND *lphwnd) 297 { 298 if (lphwnd == NULL) 299 return E_POINTER; 300 return E_NOTIMPL; 301 } 302 303 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret) 304 { 305 if (pret == NULL) 306 return E_POINTER; 307 return E_NOTIMPL; 308 } 309 310 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryActiveShellView(IShellView **ppshv) 311 { 312 if (ppshv == NULL) 313 return E_POINTER; 314 *ppshv = m_ShellView; 315 if (m_ShellView != NULL) 316 m_ShellView->AddRef(); 317 318 return S_OK; 319 } 320 321 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnViewWindowActive(IShellView *ppshv) 322 { 323 return E_NOTIMPL; 324 } 325 326 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags) 327 { 328 return E_NOTIMPL; 329 } 330 331 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryService(REFGUID guidService, REFIID riid, PVOID *ppv) 332 { 333 /* FIXME - handle guidService */ 334 return QueryInterface(riid, ppv); 335 } 336 337 LRESULT CDesktopBrowser::_NotifyTray(UINT uMsg, WPARAM wParam, LPARAM lParam) 338 { 339 HWND hWndTray; 340 HRESULT hRet; 341 342 hRet = m_Tray->GetTrayWindow(&hWndTray); 343 if (SUCCEEDED(hRet)) 344 ::PostMessageW(hWndTray, uMsg, wParam, lParam); 345 346 return 0; 347 } 348 349 LRESULT CDesktopBrowser::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 350 { 351 switch (LOWORD(wParam)) 352 { 353 case FCIDM_DESKBROWSER_CLOSE: 354 return _NotifyTray(TWM_DOEXITWINDOWS, 0, 0); 355 case FCIDM_DESKBROWSER_FOCUS: 356 if (GetKeyState(VK_SHIFT)) 357 return _NotifyTray(TWM_CYCLEFOCUS, 1, 0xFFFFFFFF); 358 else 359 return _NotifyTray(TWM_CYCLEFOCUS, 1, 1); 360 case FCIDM_DESKBROWSER_SEARCH: 361 SHFindFiles(NULL, NULL); 362 break; 363 case FCIDM_DESKBROWSER_REFRESH: 364 if (m_ShellView) 365 m_ShellView->Refresh(); 366 break; 367 } 368 369 return 0; 370 } 371 372 373 LRESULT CDesktopBrowser::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 374 { 375 return (LRESULT)PaintDesktop((HDC)wParam); 376 } 377 378 LRESULT CDesktopBrowser::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 379 { 380 if (wParam == SIZE_MINIMIZED) 381 { 382 /* Hey, we're the desktop!!! */ 383 ::ShowWindow(m_hWnd, SW_RESTORE); 384 } 385 386 ::InvalidateRect(m_hWndShellView, NULL, TRUE); 387 388 return 0; 389 } 390 391 LRESULT CDesktopBrowser::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 392 { 393 LPVOID lpEnvironment; 394 RegenerateUserEnvironment(&lpEnvironment, TRUE); 395 396 if (m_hWndShellView) 397 { 398 /* Forward the message */ 399 SendMessageW(m_hWndShellView, uMsg, wParam, lParam); 400 } 401 402 if (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA && m_hWndShellView != NULL) 403 { 404 _Resize(); 405 } 406 407 return 0; 408 } 409 410 LRESULT CDesktopBrowser::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 411 { 412 return _NotifyTray(TWM_DOEXITWINDOWS, 0, 0); 413 } 414 415 LRESULT CDesktopBrowser::OnOpenNewWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 416 { 417 TRACE("Proxy Desktop message 1035 received.\n"); 418 SHOnCWMCommandLine((HANDLE)lParam); 419 return 0; 420 } 421 422 LRESULT CDesktopBrowser::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) 423 { 424 ::SetFocus(m_hWndShellView); 425 return 0; 426 } 427 428 HRESULT CDesktopBrowser_CreateInstance(IShellDesktopTray *Tray, REFIID riid, void **ppv) 429 { 430 return ShellObjectCreatorInit<CDesktopBrowser, IShellDesktopTray*>(Tray, riid, ppv); 431 } 432 433 /************************************************************************* 434 * SHCreateDesktop [SHELL32.200] 435 * 436 */ 437 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *Tray) 438 { 439 if (Tray == NULL) 440 { 441 SetLastError(ERROR_INVALID_PARAMETER); 442 return NULL; 443 } 444 445 CComPtr<IShellBrowser> Browser; 446 HRESULT hr = CDesktopBrowser_CreateInstance(Tray, IID_PPV_ARG(IShellBrowser, &Browser)); 447 if (FAILED_UNEXPECTEDLY(hr)) 448 return NULL; 449 450 return static_cast<HANDLE>(Browser.Detach()); 451 } 452 453 /************************************************************************* 454 * SHCreateDesktop [SHELL32.201] 455 * 456 */ 457 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop) 458 { 459 if (hDesktop == NULL) 460 { 461 SetLastError(ERROR_INVALID_PARAMETER); 462 return FALSE; 463 } 464 465 MSG Msg; 466 BOOL bRet; 467 468 CComPtr<IShellBrowser> browser; 469 CComPtr<IShellView> shellView; 470 471 browser.Attach(static_cast<IShellBrowser*>(hDesktop)); 472 HRESULT hr = browser->QueryActiveShellView(&shellView); 473 if (FAILED_UNEXPECTEDLY(hr)) 474 return FALSE; 475 476 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0) 477 { 478 if (bRet != -1) 479 { 480 if (shellView->TranslateAcceleratorW(&Msg) != S_OK) 481 { 482 TranslateMessage(&Msg); 483 DispatchMessage(&Msg); 484 } 485 } 486 } 487 488 return TRUE; 489 } 490