* open MDI cabinet folders instead of new mainframe windows
[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/window.h"
33
34 #include "desktop.h"
35 #include "../taskbar/desktopbar.h"
36 #include "../shell/mainframe.h" // for MainFrame::Create()
37
38 #include "../externals.h"
39 #include "../explorer_intres.h"
40
41
42 static BOOL (WINAPI*SetShellWindow)(HWND);
43 static BOOL (WINAPI*SetShellWindowEx)(HWND, HWND);
44
45
46 BOOL IsAnyDesktopRunning()
47 {
48 HINSTANCE shell32 = GetModuleHandle(_T("user32"));
49
50 SetShellWindow = (BOOL(WINAPI*)(HWND)) GetProcAddress(shell32, "SetShellWindow");
51 SetShellWindowEx = (BOOL(WINAPI*)(HWND,HWND)) GetProcAddress(shell32, "SetShellWindowEx");
52
53 return GetShellWindow() != 0;
54 }
55
56
57 static void draw_desktop_background(HWND hwnd, HDC hdc)
58 {
59 ClientRect rect(hwnd);
60
61 PaintDesktop(hdc);
62 /*
63 HBRUSH bkgndBrush = CreateSolidBrush(RGB(0,32,160)); // dark blue
64 FillRect(hdc, &rect, bkgndBrush);
65 DeleteBrush(bkgndBrush);
66 */
67
68 rect.left = rect.right - 280;
69 rect.top = rect.bottom - 56 - DESKTOPBARBAR_HEIGHT;
70 rect.right = rect.left + 250;
71 rect.bottom = rect.top + 40;
72
73 #include "../buildno.h"
74 static const LPCTSTR BkgndText = _T("ReactOS ")_T(KERNEL_VERSION_STR)_T(" Explorer\nby Martin Fuchs");
75
76 BkMode bkMode(hdc, TRANSPARENT);
77
78 TextColor textColor(hdc, RGB(128,128,192));
79 DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
80
81 SetTextColor(hdc, RGB(255,255,255));
82 --rect.right;
83 ++rect.top;
84 DrawText(hdc, BkgndText, -1, &rect, DT_RIGHT);
85 }
86
87
88 LRESULT BackgroundWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
89 {
90 switch(nmsg) {
91 case WM_ERASEBKGND:
92 PaintDesktop((HDC)wparam);
93 return TRUE;
94
95 case WM_MBUTTONDBLCLK:
96 explorer_show_frame(_hwnd, SW_SHOWNORMAL);
97 break;
98
99 default:
100 return super::WndProc(nmsg, wparam, lparam);
101 }
102
103 return 0;
104 }
105
106
107 DesktopWindow::DesktopWindow(HWND hwnd)
108 : super(hwnd)
109 {
110 _pShellView = NULL;
111 }
112
113 DesktopWindow::~DesktopWindow()
114 {
115 if (_pShellView)
116 _pShellView->Release();
117 }
118
119
120 HWND DesktopWindow::Create()
121 {
122 IconWindowClass wcDesktop(_T("Progman"), IDI_REACTOS, CS_DBLCLKS);
123 wcDesktop.hbrBackground = (HBRUSH)(COLOR_BACKGROUND+1);
124
125 int width = GetSystemMetrics(SM_CXSCREEN);
126 int height = GetSystemMetrics(SM_CYSCREEN);
127
128 HWND hwndDesktop = Window::Create(WINDOW_CREATOR(DesktopWindow),
129 WS_EX_TOOLWINDOW, wcDesktop, _T("Program Manager"), WS_POPUP|WS_VISIBLE|WS_CLIPCHILDREN,
130 0, 0, width, height, 0);
131
132 // work around to display desktop bar in Wine
133 ShowWindow(GET_WINDOW(DesktopWindow, hwndDesktop)->_desktopBar, SW_SHOW);
134
135 // work around for Windows NT, Win 98, ...
136 // Without this the desktop has mysteriously only a size of 800x600 pixels.
137 MoveWindow(hwndDesktop, 0, 0, width, height, TRUE);
138
139 return hwndDesktop;
140 }
141
142
143 LRESULT DesktopWindow::Init(LPCREATESTRUCT pcs)
144 {
145 if (super::Init(pcs))
146 return 1;
147
148 HRESULT hr = Desktop()->CreateViewObject(_hwnd, IID_IShellView, (void**)&_pShellView);
149 /* also possible:
150 SFV_CREATE sfv_create;
151
152 sfv_create.cbSize = sizeof(SFV_CREATE);
153 sfv_create.pshf = Desktop();
154 sfv_create.psvOuter = NULL;
155 sfv_create.psfvcb = NULL;
156
157 HRESULT hr = SHCreateShellFolderView(&sfv_create, &_pShellView);
158 */
159 HWND hWndView = 0;
160
161 if (SUCCEEDED(hr)) {
162 FOLDERSETTINGS fs;
163
164 fs.ViewMode = FVM_ICON;
165 fs.fFlags = FWF_DESKTOP|FWF_NOCLIENTEDGE|FWF_NOSCROLL|FWF_BESTFITWINDOW|FWF_SNAPTOGRID;
166
167 ClientRect rect(_hwnd);
168
169 hr = _pShellView->CreateViewWindow(NULL, &fs, this, &rect, &hWndView);
170
171 //TODO: use IShellBrowser::GetViewStateStream() to restore previous view state -> see SHOpenRegStream()
172
173 if (SUCCEEDED(hr)) {
174 _pShellView->UIActivate(SVUIA_ACTIVATE_FOCUS);
175
176 /*
177 IShellView2* pShellView2;
178
179 hr = _pShellView->QueryInterface(IID_IShellView2, (void**)&pShellView2);
180
181 SV2CVW2_PARAMS params;
182 params.cbSize = sizeof(SV2CVW2_PARAMS);
183 params.psvPrev = _pShellView;
184 params.pfs = &fs;
185 params.psbOwner = this;
186 params.prcView = ▭
187 params.pvid = params.pvid;//@@
188
189 hr = pShellView2->CreateViewWindow2(&params);
190 params.pvid;
191 */
192
193 /*
194 IFolderView* pFolderView;
195
196 hr = _pShellView->QueryInterface(IID_IFolderView, (void**)&pFolderView);
197
198 if (SUCCEEDED(hr)) {
199 hr = pFolderView->GetAutoArrange();
200 hr = pFolderView->SetCurrentViewMode(FVM_DETAILS);
201 }
202 */
203
204 HWND hwndFolderView = ::GetNextWindow(hWndView, GW_CHILD);
205
206 // work around for Windows NT, Win 98, ...
207 // Without this the desktop has mysteriously only a size of 800x600 pixels.
208 MoveWindow(hwndFolderView, 0, 0, rect.right, rect.bottom, TRUE);
209
210 new BackgroundWindow(hwndFolderView);
211 }
212 }
213
214 if (hWndView && SetShellWindowEx)
215 SetShellWindowEx(_hwnd, hWndView);
216 else if (SetShellWindow)
217 SetShellWindow(_hwnd);
218
219 // create the explorer bar
220 _desktopBar = DesktopBar::Create();
221
222 return 0;
223 }
224
225
226 LRESULT DesktopWindow::WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
227 {
228 switch(nmsg) {
229 case WM_PAINT:
230 draw_desktop_background(_hwnd, PaintCanvas(_hwnd));
231 break;
232
233 case WM_LBUTTONDBLCLK:
234 case WM_RBUTTONDBLCLK:
235 case WM_MBUTTONDBLCLK:
236 explorer_show_frame(_hwnd, SW_SHOWNORMAL);
237 break;
238
239 case WM_GETISHELLBROWSER:
240 return (LRESULT)static_cast<IShellBrowser*>(this);
241
242 case WM_DESTROY:
243
244 //TODO: use IShellBrowser::GetViewStateStream() and _pShellView->SaveViewState() to store view state
245
246 if (SetShellWindow)
247 SetShellWindow(0);
248 break;
249
250 case WM_CLOSE:
251 break; // Over-ride close. We need to close desktop some other way.
252
253 case WM_SYSCOMMAND:
254 if (wparam == SC_TASKLIST) {
255 if (_desktopBar)
256 SendMessage(_desktopBar, nmsg, wparam, lparam);
257 }
258 goto def;
259
260 default: def:
261 return super::WndProc(nmsg, wparam, lparam);
262 }
263
264 return 0;
265 }
266
267
268 HRESULT DesktopWindow::OnDefaultCommand(LPIDA pIDList)
269 {
270 if (MainFrame::OpenShellFolders(pIDList, 0))
271 return S_OK;
272
273 return E_NOTIMPL;
274 }