[HEADERS]
[reactos.git] / reactos / base / shell / rshell / 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 "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(desktop);
24
25 #define SHDESK_TAG 0x4b534544
26
27 static const WCHAR szProgmanClassName [] = L"Progman";
28 static const WCHAR szProgmanWindowName [] = L"Program Manager";
29
30 class CDesktopBrowser :
31 public CComObjectRootEx<CComMultiThreadModelNoCS>,
32 public IShellBrowser,
33 public ICommDlgBrowser,
34 public IServiceProvider
35 {
36 public:
37 DWORD Tag;
38 private:
39 HWND hWnd;
40 HWND hWndShellView;
41 HWND hWndDesktopListView;
42 CComPtr<IShellDesktopTray> ShellDesk;
43 CComPtr<IShellView> DesktopView;
44 IShellBrowser *DefaultShellBrowser;
45 LPITEMIDLIST pidlDesktopDirectory;
46 LPITEMIDLIST pidlDesktop;
47 public:
48 CDesktopBrowser();
49 ~CDesktopBrowser();
50 HRESULT Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx);
51 HWND FindDesktopListView();
52 BOOL CreateDeskWnd();
53 HWND DesktopGetWindowControl(IN UINT id);
54 static LRESULT CALLBACK ProgmanWindowProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam);
55 static BOOL MessageLoop();
56
57 // *** IOleWindow methods ***
58 virtual HRESULT STDMETHODCALLTYPE GetWindow(HWND *lphwnd);
59 virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL fEnterMode);
60
61 // *** IShellBrowser methods ***
62 virtual HRESULT STDMETHODCALLTYPE InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths);
63 virtual HRESULT STDMETHODCALLTYPE SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject);
64 virtual HRESULT STDMETHODCALLTYPE RemoveMenusSB(HMENU hmenuShared);
65 virtual HRESULT STDMETHODCALLTYPE SetStatusTextSB(LPCOLESTR pszStatusText);
66 virtual HRESULT STDMETHODCALLTYPE EnableModelessSB(BOOL fEnable);
67 virtual HRESULT STDMETHODCALLTYPE TranslateAcceleratorSB(MSG *pmsg, WORD wID);
68 virtual HRESULT STDMETHODCALLTYPE BrowseObject(LPCITEMIDLIST pidl, UINT wFlags);
69 virtual HRESULT STDMETHODCALLTYPE GetViewStateStream(DWORD grfMode, IStream **ppStrm);
70 virtual HRESULT STDMETHODCALLTYPE GetControlWindow(UINT id, HWND *lphwnd);
71 virtual HRESULT STDMETHODCALLTYPE SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret);
72 virtual HRESULT STDMETHODCALLTYPE QueryActiveShellView(struct IShellView **ppshv);
73 virtual HRESULT STDMETHODCALLTYPE OnViewWindowActive(struct IShellView *ppshv);
74 virtual HRESULT STDMETHODCALLTYPE SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags);
75
76 // *** ICommDlgBrowser methods ***
77 virtual HRESULT STDMETHODCALLTYPE OnDefaultCommand(struct IShellView *ppshv);
78 virtual HRESULT STDMETHODCALLTYPE OnStateChange(struct IShellView *ppshv, ULONG uChange);
79 virtual HRESULT STDMETHODCALLTYPE IncludeObject(struct IShellView *ppshv, LPCITEMIDLIST pidl);
80
81 // *** IServiceProvider methods ***
82 virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID guidService, REFIID riid, void **ppvObject);
83
84 BEGIN_COM_MAP(CDesktopBrowser)
85 COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
86 COM_INTERFACE_ENTRY_IID(IID_IShellBrowser, IShellBrowser)
87 COM_INTERFACE_ENTRY_IID(IID_ICommDlgBrowser, ICommDlgBrowser)
88 COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
89 END_COM_MAP()
90 };
91
92 CDesktopBrowser::CDesktopBrowser()
93 {
94 Tag = SHDESK_TAG;
95 hWnd = NULL;
96 hWndShellView = NULL;
97 hWndDesktopListView = NULL;
98 DefaultShellBrowser = NULL;
99 pidlDesktopDirectory = NULL;
100 pidlDesktop = NULL;
101 }
102
103 CDesktopBrowser::~CDesktopBrowser()
104 {
105 if (DesktopView.p != NULL)
106 {
107 if (hWndShellView != NULL)
108 DesktopView->DestroyViewWindow();
109
110 hWndShellView = NULL;
111 hWndDesktopListView = NULL;
112 }
113
114 if (pidlDesktopDirectory != NULL)
115 {
116 ILFree(pidlDesktopDirectory);
117 pidlDesktopDirectory = NULL;
118 }
119
120 if (pidlDesktop != NULL)
121 {
122 ILFree(pidlDesktop);
123 pidlDesktop = NULL;
124 }
125 }
126
127 HRESULT CDesktopBrowser::Initialize(HWND hWndx, IShellDesktopTray *ShellDeskx)
128 {
129 CComPtr<IShellFolder> psfDesktopFolder;
130 CSFV csfv;
131 HRESULT hRet;
132
133 hWnd = hWndx;
134 ShellDesk = ShellDeskx;
135 ShellDesk->AddRef();
136
137 pidlDesktopDirectory = SHCloneSpecialIDList(hWnd, CSIDL_DESKTOPDIRECTORY, FALSE);
138 hRet = SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &pidlDesktop);
139 if (FAILED(hRet))
140 return hRet;
141
142 hRet = SHGetDesktopFolder(&psfDesktopFolder);
143 if (FAILED(hRet))
144 return hRet;
145
146 ZeroMemory(&csfv, sizeof(csfv));
147 csfv.cbSize = sizeof(csfv);
148 csfv.pshf = psfDesktopFolder;
149 csfv.psvOuter = NULL;
150
151 hRet = SHCreateShellFolderViewEx(&csfv, &DesktopView);
152
153 return hRet;
154 }
155
156 static CDesktopBrowser *SHDESK_Create(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
157 {
158 IShellDesktopTray *ShellDesk;
159 CComObject<CDesktopBrowser> *pThis;
160 HRESULT hRet;
161
162 ShellDesk = static_cast<IShellDesktopTray *>(lpCreateStruct->lpCreateParams);
163 if (ShellDesk == NULL)
164 {
165 WARN("No IShellDesk interface provided!");
166 return NULL;
167 }
168
169 pThis = new CComObject<CDesktopBrowser>;
170 if (pThis == NULL)
171 return NULL;
172 pThis->AddRef();
173
174 hRet = pThis->Initialize(hWnd, ShellDesk);
175 if (FAILED(hRet))
176 {
177 pThis->Release();
178 return NULL;
179 }
180
181 return pThis;
182 }
183
184 HWND CDesktopBrowser::FindDesktopListView()
185 {
186 return FindWindowExW(hWndShellView, NULL, WC_LISTVIEW, NULL);
187 }
188
189 BOOL CDesktopBrowser::CreateDeskWnd()
190 {
191 FOLDERSETTINGS fs;
192 RECT rcClient;
193 HRESULT hRet;
194
195 if (!GetClientRect(hWnd, &rcClient))
196 {
197 return FALSE;
198 }
199
200 fs.ViewMode = FVM_ICON;
201 fs.fFlags = FWF_DESKTOP | FWF_NOCLIENTEDGE | FWF_NOSCROLL | FWF_TRANSPARENT;
202 hRet = DesktopView->CreateViewWindow(NULL, &fs, static_cast<IShellBrowser *>(this), &rcClient, &hWndShellView);
203 if (!SUCCEEDED(hRet))
204 return FALSE;
205
206 SetShellWindowEx(hWnd, FindDesktopListView());
207
208 #if 1
209 /* A windows 8 specific hack */
210 ::ShowWindow(hWndShellView, SW_SHOW);
211 ::ShowWindow(FindDesktopListView(), SW_SHOW);
212 #endif
213
214 return TRUE;
215 }
216
217 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetWindow(HWND *phwnd)
218 {
219 if (hWnd != NULL)
220 {
221 *phwnd = hWnd;
222 return S_OK;
223 }
224
225 *phwnd = NULL;
226 return E_UNEXPECTED;
227 }
228
229 HRESULT STDMETHODCALLTYPE CDesktopBrowser::ContextSensitiveHelp(BOOL fEnterMode)
230 {
231 return E_NOTIMPL;
232 }
233
234 HRESULT STDMETHODCALLTYPE CDesktopBrowser::InsertMenusSB(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
235 {
236 return E_NOTIMPL;
237 }
238
239 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetMenuSB(HMENU hmenuShared, HOLEMENU holemenuRes, HWND hwndActiveObject)
240 {
241 return E_NOTIMPL;
242 }
243
244 HRESULT STDMETHODCALLTYPE CDesktopBrowser::RemoveMenusSB(HMENU hmenuShared)
245 {
246 return E_NOTIMPL;
247 }
248
249 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetStatusTextSB(LPCOLESTR lpszStatusText)
250 {
251 return E_NOTIMPL;
252 }
253
254 HRESULT STDMETHODCALLTYPE CDesktopBrowser::EnableModelessSB(BOOL fEnable)
255 {
256 return E_NOTIMPL;
257 }
258
259 HRESULT STDMETHODCALLTYPE CDesktopBrowser::TranslateAcceleratorSB(LPMSG lpmsg, WORD wID)
260 {
261 return S_FALSE;
262 }
263
264 typedef HRESULT(WINAPI *SH_OPEN_NEW_FRAME)(LPITEMIDLIST pidl, IUnknown *paramC, long param10, long param14);
265
266 HRESULT STDMETHODCALLTYPE CDesktopBrowser::BrowseObject(LPCITEMIDLIST pidl, UINT wFlags)
267 {
268 /* FIXME: Implement executing filebrowser.exe and somehow pass the pidl to it */
269
270 /* Returning failure here will make windows 7 and 8 to use the default file browser */
271 return E_FAIL;
272 }
273
274 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm)
275 {
276 return E_NOTIMPL;
277 }
278
279 HWND CDesktopBrowser::DesktopGetWindowControl(IN UINT id)
280 {
281 switch (id)
282 {
283 case FCW_TOOLBAR:
284 case FCW_STATUS:
285 case FCW_TREE:
286 case FCW_PROGRESS:
287 return NULL;
288
289 default:
290 return NULL;
291 }
292
293 }
294
295 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetControlWindow(UINT id, HWND *lphwnd)
296 {
297 HWND hWnd;
298
299 hWnd = DesktopGetWindowControl(id);
300 if (hWnd != NULL)
301 {
302 *lphwnd = hWnd;
303 return S_OK;
304 }
305
306 *lphwnd = NULL;
307 return E_NOTIMPL;
308 }
309
310 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
311 {
312 HWND hWnd;
313
314 if (pret == NULL)
315 return E_POINTER;
316
317 hWnd = DesktopGetWindowControl(id);
318 if (hWnd != NULL)
319 {
320 *pret = SendMessageW(hWnd, uMsg, wParam, lParam);
321 return S_OK;
322 }
323
324 return E_NOTIMPL;
325 }
326
327 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryActiveShellView(IShellView **ppshv)
328 {
329 *ppshv = DesktopView;
330 if (DesktopView != NULL)
331 DesktopView->AddRef();
332
333 return S_OK;
334 }
335
336 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnViewWindowActive(IShellView *ppshv)
337 {
338 return E_NOTIMPL;
339 }
340
341 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
342 {
343 return E_NOTIMPL;
344 }
345
346 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnDefaultCommand(IShellView *ppshv)
347 {
348 return E_NOTIMPL;
349 }
350
351 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnStateChange(IShellView *ppshv, ULONG uChange)
352 {
353 return S_OK;
354 }
355
356 HRESULT STDMETHODCALLTYPE CDesktopBrowser::IncludeObject(IShellView *ppshv, LPCITEMIDLIST pidl)
357 {
358 return S_OK;
359 }
360
361 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryService(REFGUID guidService, REFIID riid, PVOID *ppv)
362 {
363 /* FIXME - handle guidService */
364 return QueryInterface(riid, ppv);
365 }
366
367 BOOL CDesktopBrowser::MessageLoop()
368 {
369 MSG Msg;
370 BOOL bRet;
371
372 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
373 {
374 if (bRet != -1)
375 {
376 TranslateMessage(&Msg);
377 DispatchMessageW(&Msg);
378 }
379 }
380
381 return TRUE;
382 }
383
384 LRESULT CALLBACK CDesktopBrowser::ProgmanWindowProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
385 {
386 CDesktopBrowser *pThis = NULL;
387 LRESULT Ret = FALSE;
388
389 if (uMsg != WM_NCCREATE)
390 {
391 pThis = reinterpret_cast<CDesktopBrowser*>(GetWindowLongPtrW(hwnd, 0));
392 if (pThis == NULL)
393 goto DefMsgHandler;
394 }
395
396 if (pThis != NULL || uMsg == WM_NCCREATE)
397 {
398 switch (uMsg)
399 {
400 case WM_ERASEBKGND:
401 return (LRESULT) PaintDesktop(reinterpret_cast<HDC>(wParam));
402
403 case WM_GETISHELLBROWSER:
404 Ret = reinterpret_cast<LRESULT>(static_cast<IShellBrowser *>(pThis));
405 break;
406
407 case WM_SIZE:
408 if (wParam == SIZE_MINIMIZED)
409 {
410 /* Hey, we're the desktop!!! */
411 ShowWindow(hwnd,
412 SW_RESTORE);
413 }
414 else
415 {
416
417 /* FIXME: Update work area */
418 #if 0
419 RECT rcDesktop;
420
421 rcDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
422 rcDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
423 rcDesktop.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
424 rcDesktop.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);
425 #endif
426 }
427 break;
428
429 case WM_SYSCOLORCHANGE:
430 case WM_SETTINGCHANGE:
431 {
432 if (uMsg == WM_SYSCOLORCHANGE || wParam == SPI_SETDESKWALLPAPER || wParam == 0)
433 {
434 if (pThis->hWndShellView != NULL)
435 {
436 /* Forward the message */
437 SendMessageW(pThis->hWndShellView,
438 uMsg,
439 wParam,
440 lParam);
441 }
442 }
443 break;
444 }
445
446 case WM_CREATE:
447 {
448 pThis->ShellDesk->RegisterDesktopWindow(pThis->hWnd);
449
450 if (!pThis->CreateDeskWnd())
451 WARN("Could not create the desktop view control!\n");
452 break;
453 }
454
455 case WM_NCCREATE:
456 {
457 LPCREATESTRUCT CreateStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
458 pThis = SHDESK_Create(hwnd, CreateStruct);
459 if (pThis == NULL)
460 {
461 WARN("Failed to create desktop structure\n");
462 break;
463 }
464
465 SetWindowLongPtrW(hwnd,
466 0,
467 reinterpret_cast<LONG_PTR>(pThis));
468 Ret = TRUE;
469 break;
470 }
471
472 case WM_NCDESTROY:
473 {
474 pThis->Release();
475 break;
476 }
477
478 default:
479 DefMsgHandler :
480 Ret = DefWindowProcW(hwnd, uMsg, wParam, lParam);
481 break;
482 }
483 }
484
485 return Ret;
486 }
487
488 static BOOL
489 RegisterProgmanWindowClass(VOID)
490 {
491 WNDCLASSW wcProgman;
492
493 wcProgman.style = CS_DBLCLKS;
494 wcProgman.lpfnWndProc = CDesktopBrowser::ProgmanWindowProc;
495 wcProgman.cbClsExtra = 0;
496 wcProgman.cbWndExtra = sizeof(CDesktopBrowser *);
497 wcProgman.hInstance = shell32_hInstance;
498 wcProgman.hIcon = NULL;
499 wcProgman.hCursor = LoadCursorW(NULL, IDC_ARROW);
500 wcProgman.hbrBackground = (HBRUSH) (COLOR_BACKGROUND + 1);
501 wcProgman.lpszMenuName = NULL;
502 wcProgman.lpszClassName = szProgmanClassName;
503
504 return RegisterClassW(&wcProgman) != 0;
505 }
506
507
508 /*************************************************************************
509 * SHCreateDesktop [SHELL32.200]
510 *
511 */
512 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
513 {
514 HWND hWndDesk;
515 RECT rcDesk;
516
517 if (ShellDesk == NULL)
518 {
519 SetLastError(ERROR_INVALID_PARAMETER);
520 return NULL;
521 }
522
523 if (RegisterProgmanWindowClass() == 0)
524 {
525 WARN("Failed to register the Progman window class!\n");
526 return NULL;
527 }
528
529 rcDesk.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
530 rcDesk.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
531 rcDesk.right = rcDesk.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
532 rcDesk.bottom = rcDesk.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
533
534 if (IsRectEmpty(&rcDesk))
535 {
536 rcDesk.left = rcDesk.top = 0;
537 rcDesk.right = GetSystemMetrics(SM_CXSCREEN);
538 rcDesk.bottom = GetSystemMetrics(SM_CYSCREEN);
539 }
540
541 hWndDesk = CreateWindowExW(WS_EX_TOOLWINDOW, szProgmanClassName, szProgmanWindowName,
542 WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
543 rcDesk.left, rcDesk.top, rcDesk.right, rcDesk.bottom,
544 NULL, NULL, shell32_hInstance, reinterpret_cast<LPVOID>(ShellDesk));
545 if (hWndDesk != NULL)
546 return (HANDLE) GetWindowLongPtrW(hWndDesk, 0);
547
548 return NULL;
549 }
550
551 /*************************************************************************
552 * SHCreateDesktop [SHELL32.201]
553 *
554 */
555 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
556 {
557 CDesktopBrowser *Desk = reinterpret_cast<CDesktopBrowser *>(hDesktop);
558
559 if (Desk == NULL || Desk->Tag != SHDESK_TAG)
560 {
561 SetLastError(ERROR_INVALID_PARAMETER);
562 return FALSE;
563 }
564
565 return Desk->MessageLoop();
566 }