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