dacc0c2e8684658fb7f4a4668e256da3c18c751e
[reactos.git] / reactos / dll / win32 / shell32 / shelldesktop / CDesktopBrowser.cpp
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 return 0;
387 }
388
389 LRESULT CDesktopBrowser::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
390 {
391 if (m_hWndShellView)
392 {
393 /* Forward the message */
394 SendMessageW(m_hWndShellView, uMsg, wParam, lParam);
395 }
396
397 if (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA && m_hWndShellView != NULL)
398 {
399 _Resize();
400 }
401
402 return 0;
403 }
404
405 LRESULT CDesktopBrowser::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
406 {
407 return _NotifyTray(TWM_DOEXITWINDOWS, 0, 0);
408 }
409
410 LRESULT CDesktopBrowser::OnOpenNewWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
411 {
412 TRACE("Proxy Desktop message 1035 received.\n");
413 SHOnCWMCommandLine((HANDLE)lParam);
414 return 0;
415 }
416
417 LRESULT CDesktopBrowser::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
418 {
419 ::SetFocus(m_hWndShellView);
420 return 0;
421 }
422
423 HRESULT CDesktopBrowser_CreateInstance(IShellDesktopTray *Tray, REFIID riid, void **ppv)
424 {
425 return ShellObjectCreatorInit<CDesktopBrowser, IShellDesktopTray*>(Tray, riid, ppv);
426 }
427
428 /*************************************************************************
429 * SHCreateDesktop [SHELL32.200]
430 *
431 */
432 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *Tray)
433 {
434 if (Tray == NULL)
435 {
436 SetLastError(ERROR_INVALID_PARAMETER);
437 return NULL;
438 }
439
440 CComPtr<IShellBrowser> Browser;
441 HRESULT hr = CDesktopBrowser_CreateInstance(Tray, IID_PPV_ARG(IShellBrowser, &Browser));
442 if (FAILED_UNEXPECTEDLY(hr))
443 return NULL;
444
445 return static_cast<HANDLE>(Browser.Detach());
446 }
447
448 /*************************************************************************
449 * SHCreateDesktop [SHELL32.201]
450 *
451 */
452 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
453 {
454 if (hDesktop == NULL)
455 {
456 SetLastError(ERROR_INVALID_PARAMETER);
457 return FALSE;
458 }
459
460 MSG Msg;
461 BOOL bRet;
462
463 CComPtr<IShellBrowser> browser;
464 CComPtr<IShellView> shellView;
465
466 browser.Attach(static_cast<IShellBrowser*>(hDesktop));
467 HRESULT hr = browser->QueryActiveShellView(&shellView);
468 if (FAILED_UNEXPECTEDLY(hr))
469 return FALSE;
470
471 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
472 {
473 if (bRet != -1)
474 {
475 if (shellView->TranslateAcceleratorW(&Msg) != S_OK)
476 {
477 TranslateMessage(&Msg);
478 DispatchMessage(&Msg);
479 }
480 }
481 }
482
483 return TRUE;
484 }