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