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