[browseui]
[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 /*
273 * We should use IShellWindows interface here in order to attempt to
274 * find an open shell window that shows the requested pidl and activate it
275 */
276
277 #if 0
278 HMODULE hBrowseui = LoadLibraryW(L"browseui.dll");
279 if (hBrowseui)
280 {
281 SH_OPEN_NEW_FRAME SHOpenNewFrame = (SH_OPEN_NEW_FRAME)GetProcAddress(hBrowseui, (LPCSTR)103);
282 return SHOpenNewFrame((LPITEMIDLIST)pidl, NULL, 0, 0);
283 }
284 #endif
285 return E_FAIL;
286 }
287
288 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetViewStateStream(DWORD grfMode, IStream **ppStrm)
289 {
290 return E_NOTIMPL;
291 }
292
293 HWND CDesktopBrowser::DesktopGetWindowControl(IN UINT id)
294 {
295 switch (id)
296 {
297 case FCW_TOOLBAR:
298 case FCW_STATUS:
299 case FCW_TREE:
300 case FCW_PROGRESS:
301 return NULL;
302
303 default:
304 return NULL;
305 }
306
307 }
308
309 HRESULT STDMETHODCALLTYPE CDesktopBrowser::GetControlWindow(UINT id, HWND *lphwnd)
310 {
311 HWND hWnd;
312
313 hWnd = DesktopGetWindowControl(id);
314 if (hWnd != NULL)
315 {
316 *lphwnd = hWnd;
317 return S_OK;
318 }
319
320 *lphwnd = NULL;
321 return E_NOTIMPL;
322 }
323
324 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SendControlMsg(UINT id, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pret)
325 {
326 HWND hWnd;
327
328 if (pret == NULL)
329 return E_POINTER;
330
331 hWnd = DesktopGetWindowControl(id);
332 if (hWnd != NULL)
333 {
334 *pret = SendMessageW(hWnd,
335 uMsg,
336 wParam,
337 lParam);
338 return S_OK;
339 }
340
341 return E_NOTIMPL;
342 }
343
344 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryActiveShellView(IShellView **ppshv)
345 {
346 *ppshv = DesktopView;
347 if (DesktopView != NULL)
348 DesktopView->AddRef();
349
350 return S_OK;
351 }
352
353 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnViewWindowActive(IShellView *ppshv)
354 {
355 return E_NOTIMPL;
356 }
357
358 HRESULT STDMETHODCALLTYPE CDesktopBrowser::SetToolbarItems(LPTBBUTTON lpButtons, UINT nButtons, UINT uFlags)
359 {
360 return E_NOTIMPL;
361 }
362
363 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnDefaultCommand(IShellView *ppshv)
364 {
365 return E_NOTIMPL;
366 }
367
368 HRESULT STDMETHODCALLTYPE CDesktopBrowser::OnStateChange(IShellView *ppshv, ULONG uChange)
369 {
370 return S_OK;
371 }
372
373 HRESULT STDMETHODCALLTYPE CDesktopBrowser::IncludeObject(IShellView *ppshv, LPCITEMIDLIST pidl)
374 {
375 return S_OK;
376 }
377
378 HRESULT STDMETHODCALLTYPE CDesktopBrowser::QueryService(REFGUID guidService, REFIID riid, PVOID *ppv)
379 {
380 /* FIXME - handle guidService */
381 return QueryInterface(riid, ppv);
382 }
383
384 BOOL CDesktopBrowser::MessageLoop()
385 {
386 MSG Msg;
387 BOOL bRet;
388
389 while ((bRet = GetMessageW(&Msg, NULL, 0, 0)) != 0)
390 {
391 if (bRet != -1)
392 {
393 TranslateMessage(&Msg);
394 DispatchMessageW(&Msg);
395 }
396 }
397
398 return TRUE;
399 }
400
401 LRESULT CALLBACK CDesktopBrowser::ProgmanWindowProc(IN HWND hwnd, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
402 {
403 CDesktopBrowser *pThis = NULL;
404 LRESULT Ret = FALSE;
405
406 if (uMsg != WM_NCCREATE)
407 {
408 pThis = (CDesktopBrowser*)GetWindowLongPtrW(hwnd,
409 0);
410 if (pThis == NULL)
411 goto DefMsgHandler;
412 }
413
414 if (pThis != NULL || uMsg == WM_NCCREATE)
415 {
416 switch (uMsg)
417 {
418 case WM_ERASEBKGND:
419 return (LRESULT)PaintDesktop((HDC)wParam);
420
421 case WM_GETISHELLBROWSER:
422 Ret = (LRESULT)((IShellBrowser *)pThis);
423 break;
424
425 case WM_SIZE:
426 if (wParam == SIZE_MINIMIZED)
427 {
428 /* Hey, we're the desktop!!! */
429 ShowWindow(hwnd,
430 SW_RESTORE);
431 }
432 else
433 {
434 RECT rcDesktop;
435
436 rcDesktop.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
437 rcDesktop.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
438 rcDesktop.right = GetSystemMetrics(SM_CXVIRTUALSCREEN);
439 rcDesktop.bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN);
440
441 /* FIXME: Update work area */
442 }
443 break;
444
445 case WM_SYSCOLORCHANGE:
446 case WM_SETTINGCHANGE:
447 {
448 if (uMsg == WM_SYSCOLORCHANGE || wParam == SPI_SETDESKWALLPAPER || wParam == 0)
449 {
450 if (pThis->hWndShellView != NULL)
451 {
452 /* Forward the message */
453 SendMessageW(pThis->hWndShellView,
454 uMsg,
455 wParam,
456 lParam);
457 }
458 }
459 break;
460 }
461
462 case WM_CREATE:
463 {
464 pThis->ShellDesk->RegisterDesktopWindow(pThis->hWnd);
465
466 if (!pThis->CreateDeskWnd())
467 WARN("Could not create the desktop view control!\n");
468 break;
469 }
470
471 case WM_NCCREATE:
472 {
473 LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
474 pThis = SHDESK_Create(hwnd, CreateStruct);
475 if (pThis == NULL)
476 {
477 WARN("Failed to create desktop structure\n");
478 break;
479 }
480
481 SetWindowLongPtrW(hwnd,
482 0,
483 (LONG_PTR)pThis);
484 Ret = TRUE;
485 break;
486 }
487
488 case WM_NCDESTROY:
489 {
490 pThis->Release();
491 break;
492 }
493
494 default:
495 DefMsgHandler:
496 Ret = DefWindowProcW(hwnd, uMsg, wParam, lParam);
497 break;
498 }
499 }
500
501 return Ret;
502 }
503
504 static BOOL
505 RegisterProgmanWindowClass(VOID)
506 {
507 WNDCLASSW wcProgman;
508
509 wcProgman.style = CS_DBLCLKS;
510 wcProgman.lpfnWndProc = CDesktopBrowser::ProgmanWindowProc;
511 wcProgman.cbClsExtra = 0;
512 wcProgman.cbWndExtra = sizeof(CDesktopBrowser *);
513 wcProgman.hInstance = shell32_hInstance;
514 wcProgman.hIcon = NULL;
515 wcProgman.hCursor = LoadCursorW(NULL, IDC_ARROW);
516 wcProgman.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
517 wcProgman.lpszMenuName = NULL;
518 wcProgman.lpszClassName = szProgmanClassName;
519
520 return RegisterClassW(&wcProgman) != 0;
521 }
522
523
524 /*************************************************************************
525 * SHCreateDesktop [SHELL32.200]
526 *
527 */
528 HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
529 {
530 HWND hWndDesk;
531 RECT rcDesk;
532
533 if (ShellDesk == NULL)
534 {
535 SetLastError(ERROR_INVALID_PARAMETER);
536 return NULL;
537 }
538
539 if (RegisterProgmanWindowClass() == 0)
540 {
541 WARN("Failed to register the Progman window class!\n");
542 return NULL;
543 }
544
545 rcDesk.left = GetSystemMetrics(SM_XVIRTUALSCREEN);
546 rcDesk.top = GetSystemMetrics(SM_YVIRTUALSCREEN);
547 rcDesk.right = rcDesk.left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
548 rcDesk.bottom = rcDesk.top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
549
550 if (IsRectEmpty(&rcDesk))
551 {
552 rcDesk.left = rcDesk.top = 0;
553 rcDesk.right = GetSystemMetrics(SM_CXSCREEN);
554 rcDesk.bottom = GetSystemMetrics(SM_CYSCREEN);
555 }
556
557 hWndDesk = CreateWindowExW(0, szProgmanClassName, szProgmanWindowName,
558 WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
559 rcDesk.left, rcDesk.top, rcDesk.right, rcDesk.bottom,
560 NULL, NULL, shell32_hInstance, (LPVOID)ShellDesk);
561 if (hWndDesk != NULL)
562 return (HANDLE)GetWindowLongPtrW(hWndDesk, 0);
563
564 return NULL;
565 }
566
567 /*************************************************************************
568 * SHCreateDesktop [SHELL32.201]
569 *
570 */
571 BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
572 {
573 CDesktopBrowser *Desk = (CDesktopBrowser *)hDesktop;
574
575 if (Desk == NULL || Desk->Tag != SHDESK_TAG)
576 {
577 SetLastError(ERROR_INVALID_PARAMETER);
578 return FALSE;
579 }
580
581 return Desk->MessageLoop();
582 }