733504176db03bff0bf2a61339465cdde18eb4bc
[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 return SHOpenNewFrame((LPITEMIDLIST)pidl, NULL, 0, 0);
288 }
289
290 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm)
291 {
292 return E_NOTIMPL;
293 }
294
295 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetControlWindow(UINT id, HWND *lphwnd)
296 {
297 if (lphwnd == NULL)
298 return E_POINTER;
299 return E_NOTIMPL;
300 }
301
302 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
303 {
304 if (pret == NULL)
305 return E_POINTER;
306 return E_NOTIMPL;
307 }
308
309 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryActiveShellView(IShellView **ppshv)
310 {
311 if (ppshv == NULL)
312 return E_POINTER;
313 *ppshv = m_ShellView;
314 if (m_ShellView != NULL)
315 m_ShellView->AddRef();
316
317 return S_OK;
318 }
319
320 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnViewWindowActive(IShellView *ppshv)
321 {
322 return E_NOTIMPL;
323 }
324
325 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
326 {
327 return E_NOTIMPL;
328 }
329
330 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryService(REFGUID guidService, REFIID riid, PVOID *ppv)
331 {
332 /* FIXME - handle guidService */
333 return QueryInterface(riid, ppv);
334 }
335
336 LRESULT CDesktopBrowser::_NotifyTray(UINT uMsg, WPARAM wParam, LPARAM lParam)
337 {
338 HWND hWndTray;
339 HRESULT hRet;
340
341 hRet = m_Tray->GetTrayWindow(&hWndTray);
342 if (SUCCEEDED(hRet))
343 ::PostMessageW(hWndTray, uMsg, wParam, lParam);
344
345 return 0;
346 }
347
348 LRESULT CDesktopBrowser::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
349 {
350 switch (LOWORD(wParam))
351 {
352 case FCIDM_DESKBROWSER_CLOSE:
353 return _NotifyTray(TWM_DOEXITWINDOWS, 0, 0);
354 case FCIDM_DESKBROWSER_FOCUS:
355 if (GetKeyState(VK_SHIFT))
356 return _NotifyTray(TWM_CYCLEFOCUS, 1, 0xFFFFFFFF);
357 else
358 return _NotifyTray(TWM_CYCLEFOCUS, 1, 1);
359 case FCIDM_DESKBROWSER_SEARCH:
360 SHFindFiles(NULL, NULL);
361 break;
362 case FCIDM_DESKBROWSER_REFRESH:
363 break;
364 }
365
366 return 0;
367 }
368
369
370 LRESULT CDesktopBrowser::OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
371 {
372 return (LRESULT)PaintDesktop((HDC)wParam);
373 }
374
375 LRESULT CDesktopBrowser::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
376 {
377 if (wParam == SIZE_MINIMIZED)
378 {
379 /* Hey, we're the desktop!!! */
380 ::ShowWindow(m_hWnd, SW_RESTORE);
381 }
382
383 return 0;
384 }
385
386 LRESULT CDesktopBrowser::OnSettingChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
387 {
388 if (m_hWndShellView)
389 {
390 /* Forward the message */
391 SendMessageW(m_hWndShellView, uMsg, wParam, lParam);
392 }
393
394 if (uMsg == WM_SETTINGCHANGE && wParam == SPI_SETWORKAREA && m_hWndShellView != NULL)
395 {
396 _Resize();
397 }
398
399 return 0;
400 }
401
402 LRESULT CDesktopBrowser::OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
403 {
404 return _NotifyTray(TWM_DOEXITWINDOWS, 0, 0);
405 }
406
407 LRESULT CDesktopBrowser::OnOpenNewWindow(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
408 {
409 TRACE("Proxy Desktop message 1035 received.\n");
410 SHOnCWMCommandLine((HANDLE)lParam);
411 return 0;
412 }
413
414 LRESULT CDesktopBrowser::OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled)
415 {
416 ::SetFocus(m_hWndShellView);
417 return 0;
418 }
419
420 HRESULT CDesktopBrowser_CreateInstance(IShellDesktopTray *Tray, REFIID riid, void **ppv)
421 {
422 return ShellObjectCreatorInit<CDesktopBrowser, IShellDesktopTray*>(Tray, riid, ppv);
423 }
424
425 /*************************************************************************
426 * SHCreateDesktop [SHELL32.200]
427 *
428 */
429 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *Tray)
430 {
431 if (Tray == NULL)
432 {
433 SetLastError(ERROR_INVALID_PARAMETER);
434 return NULL;
435 }
436
437 CComPtr<IShellBrowser> Browser;
438 HRESULT hr = CDesktopBrowser_CreateInstance(Tray, IID_PPV_ARG(IShellBrowser, &Browser));
439 if (FAILED_UNEXPECTEDLY(hr))
440 return NULL;
441
442 return static_cast<HANDLE>(Browser.Detach());
443 }
444
445 /*************************************************************************
446 * SHCreateDesktop [SHELL32.201]
447 *
448 */
449 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
450 {
451 if (hDesktop == NULL)
452 {
453 SetLastError(ERROR_INVALID_PARAMETER);
454 return FALSE;
455 }
456
457 MSG Msg;
458 BOOL bRet;
459
460 CComPtr<IShellBrowser> browser;
461 CComPtr<IShellView> shellView;
462
463 browser.Attach(static_cast<IShellBrowser*>(hDesktop));
464 HRESULT hr = browser->QueryActiveShellView(&shellView);
465 if (FAILED_UNEXPECTEDLY(hr))
466 return FALSE;
467
468 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
469 {
470 if (bRet != -1)
471 {
472 if (shellView->TranslateAcceleratorW(&Msg) != S_OK)
473 {
474 TranslateMessage(&Msg);
475 DispatchMessage(&Msg);
476 }
477 }
478 }
479
480 return TRUE;
481 }