moved setings dialogs in separate file
[reactos.git] / reactos / subsys / system / explorer / desktop / desktop.cpp
1 /*
2 * Copyright 2003 Martin Fuchs
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer clone
22 //
23 // desktop.cpp
24 //
25 // Martin Fuchs, 09.08.2003
26 //
27
28
29 #include "../utility/utility.h"
30 #include "../utility/shellclasses.h"
31 #include "../utility/shellbrowserimpl.h"
32 #include "../utility/dragdropimpl.h"
33 #include "../utility/window.h"
34
35 #include "../globals.h"
36 #include "../externals.h"
37 #include "../explorer_intres.h"
38
39 #include "desktop.h"
40 #include "../taskbar/desktopbar.h"
41 #include "../shell/mainframe.h" // for MainFrame::Create()
42
43
44 static BOOL (WINAPI*SetShellWindow)(HWND);
45 static BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
46
47
48 BOOL IsAnyDesktopRunning()
49 {
50 HINSTANCE hUser32 = GetModuleHandle(TEXT("user32"));
51
52 SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(hUser32, "SetShellWindow");
53 SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(hUser32, "SetShellWindowEx");
54
55 return GetShellWindow() != 0;
56 }
57
58
59 static void draw_desktop_background(HWND hwnd, HDC hdc)
60 {
61 ClientRect rect(hwnd);
62
63 PaintDesktop(hdc);
64 /*
65 HBRUSH bkgndBrush = CreateSolidBrush(RGB(0,32,160)); // dark blue
66 FillRect(hdc, &rect, bkgndBrush);
67 DeleteBrush(bkgndBrush);
68 */
69
70 rect.left = rect.right - 280;
71 rect.top = rect.bottom - 56 - DESKTOPBARBAR_HEIGHT;
72 rect.right = rect.left + 250;
73 rect.bottom = rect.top + 40;
74
75 #include "../buildno.h"
76 static const LPCTSTR BkgndText = TEXT("ReactOS ")TEXT(KERNEL_VERSION_STR)TEXT(" Explorer\nby Martin Fuchs");
77
78 BkMode bkMode(hdc, TRANSPARENT);
79
80 TextColor textColor(hdc, RGB(128,128,192));
81 DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
82
83 SetTextColor(hdc, RGB(255,255,255));
84 --rect.right;
85 ++rect.top;
86 DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
87 }
88
89
90 LRESULT BackgroundWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
91 {
92 switch(nmsg) {
93 case WM_ERASEBKGND:
94 PaintDesktop((HDC)wparam);
95 return TRUE;
96
97 case WM_MBUTTONDBLCLK:
98 explorer_show_frame(_hwnd, SW_SHOWNORMAL);
99 break;
100
101 default:
102 return super::WndProc(nmsg, wparam, lparam);
103 }
104
105 return 0;
106 }
107
108
109 DesktopWindow::DesktopWindow(HWND hwnd)
110 : super(hwnd)
111 {
112 _pShellView = NULL;
113 }
114
115 DesktopWindow::~DesktopWindow()
116 {
117 if (_pShellView)
118 _pShellView->Release();
119 }
120
121
122 HWND DesktopWindow::Create()
123 {
124 IconWindowClass wcDesktop(TEXT("Progman"), IDI_REACTOS, CS_DBLCLKS);
125 wcDesktop.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
126
127 int width = GetSystemMetrics(SM_CXSCREEN);
128 int height = GetSystemMetrics(SM_CYSCREEN);
129
130 HWND hwndDesktop = Window::Create(WINDOW_CREATOR(DesktopWindow),
131 WS_EX_TOOLWINDOW, wcDesktop, TEXT("Program Manager"), WS_POPUP|WS_VISIBLE|WS_CLIPCHILDREN,
132 0, 0, width, height, 0);
133
134 // work around to display desktop bar in Wine
135 ShowWindow(GET_WINDOW(DesktopWindow, hwndDesktop)->_desktopBar, SW_SHOW);
136
137 // work around for Windows NT, Win 98, ...
138 // Without this the desktop has mysteriously only a size of 800x600 pixels.
139 MoveWindow(hwndDesktop, 0, 0, width, height, TRUE);
140
141 return hwndDesktop;
142 }
143
144
145 LRESULT DesktopWindow::Init(LPCREATESTRUCT pcs)
146 {
147 if (super::Init(pcs))
148 return 1;
149
150 HRESULT hr = Desktop()->CreateViewObject(_hwnd, IID_IShellView, (void**)&_pShellView);
151 /* also possible:
152 SFV_CREATE sfv_create;
153
154 sfv_create.cbSize = sizeof(SFV_CREATE);
155 sfv_create.pshf = Desktop();
156 sfv_create.psvOuter = NULL;
157 sfv_create.psfvcb = NULL;
158
159 HRESULT hr = SHCreateShellFolderView(&sfv_create, &_pShellView);
160 */
161 HWND hWndView = 0;
162
163 if (SUCCEEDED(hr)) {
164 FOLDERSETTINGS fs;
165
166 fs.ViewMode = FVM_ICON;
167 fs.fFlags = FWF_DESKTOP|FWF_NOCLIENTEDGE|FWF_NOSCROLL|FWF_BESTFITWINDOW|FWF_SNAPTOGRID; //|FWF_AUTOARRANGE;
168
169 ClientRect rect(_hwnd);
170
171 hr = _pShellView->CreateViewWindow(NULL, &fs, this, &rect, &hWndView);
172
173 ///@todo use IShellBrowser::GetViewStateStream() to restore previous view state -> see SHOpenRegStream()
174
175 if (SUCCEEDED(hr)) {
176 // subclass shellview window
177 new DesktopShellView(hWndView, _pShellView);
178
179 _pShellView->UIActivate(SVUIA_ACTIVATE_FOCUS);
180
181 /*
182 IShellView2* pShellView2;
183
184 hr = _pShellView->QueryInterface(IID_IShellView2, (void**)&pShellView2);
185
186 SV2CVW2_PARAMS params;
187 params.cbSize = sizeof(SV2CVW2_PARAMS);
188 params.psvPrev = _pShellView;
189 params.pfs = &fs;
190 params.psbOwner = this;
191 params.prcView = ▭
192 params.pvid = params.pvid;//@@
193
194 hr = pShellView2->CreateViewWindow2(&params);
195 params.pvid;
196 */
197
198 /*
199 IFolderView* pFolderView;
200
201 hr = _pShellView->QueryInterface(IID_IFolderView, (void**)&pFolderView);
202
203 if (SUCCEEDED(hr)) {
204 hr = pFolderView->GetAutoArrange();
205 hr = pFolderView->SetCurrentViewMode(FVM_DETAILS);
206 }
207 */
208
209 HWND hwndFolderView = ::GetNextWindow(hWndView, GW_CHILD);
210
211 SetWindowStyle(hwndFolderView, (GetWindowStyle(hwndFolderView)&~LVS_ALIGNLEFT)|LVS_ALIGNTOP|LVS_AUTOARRANGE);
212
213 // work around for Windows NT, Win 98, ...
214 // Without this the desktop has mysteriously only a size of 800x600 pixels.
215 MoveWindow(hwndFolderView, 0, 0, rect.right, rect.bottom, TRUE);
216
217 // subclass background window
218 new BackgroundWindow(hwndFolderView);
219 }
220 }
221
222 if (hWndView && SetShellWindowEx)
223 SetShellWindowEx(_hwnd, hWndView);
224 else if (SetShellWindow)
225 SetShellWindow(_hwnd);
226
227 // create the explorer bar
228 _desktopBar = DesktopBar::Create();
229 g_Globals._hwndDesktopBar = _desktopBar;
230
231 return 0;
232 }
233
234
235 LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
236 {
237 switch(nmsg) {
238 case WM_PAINT:
239 draw_desktop_background(_hwnd, PaintCanvas(_hwnd));
240 break;
241
242 case WM_LBUTTONDBLCLK:
243 case WM_RBUTTONDBLCLK:
244 case WM_MBUTTONDBLCLK:
245 explorer_show_frame(_hwnd, SW_SHOWNORMAL);
246 break;
247
248 case WM_GETISHELLBROWSER:
249 return (LRESULT)static_cast<IShellBrowser*>(this);
250
251 case WM_DESTROY:
252
253 ///@todo use IShellBrowser::GetViewStateStream() and _pShellView->SaveViewState() to store view state
254
255 if (SetShellWindow)
256 SetShellWindow(0);
257 break;
258
259 case WM_CLOSE:
260 ShowExitWindowsDialog(_hwnd);
261 break;
262
263 case WM_SYSCOMMAND:
264 if (wparam == SC_TASKLIST) {
265 if (_desktopBar)
266 SendMessage(_desktopBar, nmsg, wparam, lparam);
267 }
268 goto def;
269
270 default: def:
271 return super::WndProc(nmsg, wparam, lparam);
272 }
273
274 return 0;
275 }
276
277
278 HRESULT DesktopWindow::OnDefaultCommand(LPIDA pida)
279 {
280 if (MainFrame::OpenShellFolders(pida, 0))
281 return S_OK;
282
283 return E_NOTIMPL;
284 }
285
286
287 DesktopShellView::DesktopShellView(HWND hwnd, IShellView* pShellView)
288 : super(hwnd),
289 _pShellView(pShellView)
290 {
291 InitDragDrop();
292 }
293
294 bool DesktopShellView::InitDragDrop()
295 {
296 CONTEXT("DesktopShellView::InitDragDrop()");
297
298 _pDropTarget = new DesktopDropTarget(_hwnd);
299
300 if (!_pDropTarget)
301 return false;
302
303 _pDropTarget->AddRef();
304
305 if (FAILED(RegisterDragDrop(_hwnd, _pDropTarget))) {
306 _pDropTarget->Release();
307 _pDropTarget = NULL;
308 return false;
309 }
310 else
311 _pDropTarget->Release();
312
313 FORMATETC ftetc;
314
315 ftetc.dwAspect = DVASPECT_CONTENT;
316 ftetc.lindex = -1;
317 ftetc.tymed = TYMED_HGLOBAL;
318 ftetc.cfFormat = CF_HDROP;
319
320 _pDropTarget->AddSuportedFormat(ftetc);
321
322 return true;
323 }
324
325 LRESULT DesktopShellView::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
326 {
327 switch(nmsg) {
328 case WM_CONTEXTMENU:
329 if (!DoContextMenu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam)))
330 DoDesktopContextMenu(GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam));
331 break;
332
333 default:
334 return super::WndProc(nmsg, wparam, lparam);
335 }
336
337 return 0;
338 }
339
340 int DesktopShellView::Command(int id, int code)
341 {
342 return super::Command(id, code);
343 }
344
345 int DesktopShellView::Notify(int id, NMHDR* pnmh)
346 {
347 return super::Notify(id, pnmh);
348 }
349
350 bool DesktopShellView::DoContextMenu(int x, int y)
351 {
352 IDataObject* selection;
353
354 HRESULT hr = _pShellView->GetItemObject(SVGIO_SELECTION, IID_IDataObject, (void**)&selection);
355 if (FAILED(hr))
356 return false;
357
358 PIDList pidList;
359
360 hr = pidList.GetData(selection);
361 if (FAILED(hr)) {
362 selection->Release();
363 //CHECKERROR(hr);
364 return false;
365 }
366
367 LPIDA pida = pidList;
368 if (!pida->cidl) {
369 selection->Release();
370 return false;
371 }
372
373 LPCITEMIDLIST parent_pidl = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[0]);
374
375 LPCITEMIDLIST* apidl = (LPCITEMIDLIST*) alloca(pida->cidl*sizeof(LPCITEMIDLIST));
376
377 for(int i=pida->cidl; i>0; --i)
378 apidl[i-1] = (LPCITEMIDLIST) ((LPBYTE)pida+pida->aoffset[i]);
379
380 hr = ShellFolderContextMenu(ShellFolder(parent_pidl), _hwnd, pida->cidl, apidl, x, y);
381
382 selection->Release();
383
384 CHECKERROR(hr);
385
386 return true;
387 }
388
389 HRESULT DesktopShellView::DoDesktopContextMenu(int x, int y)
390 {
391 IContextMenu* pcm;
392
393 HRESULT hr = DesktopFolder()->GetUIObjectOf(_hwnd, 0, NULL, IID_IContextMenu, NULL, (LPVOID*)&pcm);
394
395 if (SUCCEEDED(hr)) {
396 HMENU hmenu = CreatePopupMenu();
397
398 if (hmenu) {
399 hr = pcm->QueryContextMenu(hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST-1, CMF_NORMAL|CMF_EXPLORE);
400
401 if (SUCCEEDED(hr)) {
402 AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
403 AppendMenu(hmenu, 0, FCIDM_SHVIEWLAST-1, ResString(IDS_ABOUT_EXPLORER));
404
405 UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, _hwnd, NULL);
406
407 if (idCmd == FCIDM_SHVIEWLAST-1) {
408 explorer_about(_hwnd);
409 } else if (idCmd) {
410 CMINVOKECOMMANDINFO cmi;
411
412 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
413 cmi.fMask = 0;
414 cmi.hwnd = _hwnd;
415 cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST);
416 cmi.lpParameters = NULL;
417 cmi.lpDirectory = NULL;
418 cmi.nShow = SW_SHOWNORMAL;
419 cmi.dwHotKey = 0;
420 cmi.hIcon = 0;
421
422 hr = pcm->InvokeCommand(&cmi);
423 }
424 }
425 }
426
427 pcm->Release();
428 }
429
430 return hr;
431 }