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