8079d2263f829d0c1bfabbb2279f6113c8a75c13
[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, FALSE);
161 ::MoveWindow(m_hWndShellView, 0, 0, rcNewSize.right - rcNewSize.left, rcNewSize.bottom - rcNewSize.top, FALSE);
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, FALSE);
180 ::MoveWindow(m_hWndShellView, 0, 0, rcNewSize.right - rcNewSize.left, rcNewSize.bottom - rcNewSize.top, FALSE);
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((LPITEMIDLIST)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 break;
365 }
366
367 return 0;
368 }
369
370
371 LRESULT CDesktopBrowser::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
372 {
373 return (LRESULT)PaintDesktop((HDC)wParam);
374 }
375
376 LRESULT CDesktopBrowser::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
377 {
378 if (wParam == SIZE_MINIMIZED)
379 {
380 /* Hey, we're the desktop!!! */
381 ::ShowWindow(m_hWnd, SW_RESTORE);
382 }
383
384 return 0;
385 }
386
387 LRESULT CDesktopBrowser::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
388 {
389 if (m_hWndShellView)
390 {
391 /* Forward the message */
392 SendMessageW(m_hWndShellView, uMsg, wParam, lParam);
393 }
394
395 if (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA && m_hWndShellView != NULL)
396 {
397 _Resize();
398 }
399
400 return 0;
401 }
402
403 LRESULT CDesktopBrowser::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
404 {
405 return _NotifyTray(TWM_DOEXITWINDOWS, 0, 0);
406 }
407
408 LRESULT CDesktopBrowser::OnOpenNewWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
409 {
410 TRACE("Proxy Desktop message 1035 received.\n");
411 SHOnCWMCommandLine((HANDLE)lParam);
412 return 0;
413 }
414
415 LRESULT CDesktopBrowser::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
416 {
417 ::SetFocus(m_hWndShellView);
418 return 0;
419 }
420
421 HRESULT CDesktopBrowser_CreateInstance(IShellDesktopTray *Tray, REFIID riid, void **ppv)
422 {
423 return ShellObjectCreatorInit<CDesktopBrowser, IShellDesktopTray*>(Tray, riid, ppv);
424 }
425
426 /*************************************************************************
427 * SHCreateDesktop [SHELL32.200]
428 *
429 */
430 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *Tray)
431 {
432 if (Tray == NULL)
433 {
434 SetLastError(ERROR_INVALID_PARAMETER);
435 return NULL;
436 }
437
438 CComPtr<IShellBrowser> Browser;
439 HRESULT hr = CDesktopBrowser_CreateInstance(Tray, IID_PPV_ARG(IShellBrowser, &Browser));
440 if (FAILED_UNEXPECTEDLY(hr))
441 return NULL;
442
443 return static_cast<HANDLE>(Browser.Detach());
444 }
445
446 /*************************************************************************
447 * SHCreateDesktop [SHELL32.201]
448 *
449 */
450 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
451 {
452 if (hDesktop == NULL)
453 {
454 SetLastError(ERROR_INVALID_PARAMETER);
455 return FALSE;
456 }
457
458 MSG Msg;
459 BOOL bRet;
460
461 CComPtr<IShellBrowser> browser;
462 CComPtr<IShellView> shellView;
463
464 browser.Attach(static_cast<IShellBrowser*>(hDesktop));
465 HRESULT hr = browser->QueryActiveShellView(&shellView);
466 if (FAILED_UNEXPECTEDLY(hr))
467 return FALSE;
468
469 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
470 {
471 if (bRet != -1)
472 {
473 if (shellView->TranslateAcceleratorW(&Msg) != S_OK)
474 {
475 TranslateMessage(&Msg);
476 DispatchMessage(&Msg);
477 }
478 }
479 }
480
481 return TRUE;
482 }