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