Committing latest progress, still much TODO:
[reactos.git] / rosapps / winfile / framewnd.c
1 /*
2 * ReactOS winfile
3 *
4 * framewnd.c
5 *
6 * Copyright (C) 2002 Robert Dickenson <robd@reactos.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #ifdef _MSC_VER
24 #include "stdafx.h"
25 #else
26 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
27 #include <windows.h>
28 #include <commctrl.h>
29 #include <stdlib.h>
30 #include <malloc.h>
31 #include <memory.h>
32 #include <tchar.h>
33 #include <process.h>
34 #include <stdio.h>
35 #endif
36
37 //#include <shellapi.h>
38 #include <windowsx.h>
39 #include <assert.h>
40 #define ASSERT assert
41
42 #include "main.h"
43 #include "about.h"
44 #include "framewnd.h"
45 #include "childwnd.h"
46 #include "utils.h"
47 #include "run.h"
48 #include "format.h"
49
50
51 ////////////////////////////////////////////////////////////////////////////////
52 // Global Variables:
53 //
54
55 BOOL bInMenuLoop = FALSE; // Tells us if we are in the menu loop
56 int nOldWidth; // Holds the previous client area width
57 int nOldHeight; // Holds the previous client area height
58
59
60 ////////////////////////////////////////////////////////////////////////////////
61 // Local module support methods
62 //
63
64 static void resize_frame_rect(HWND hWnd, PRECT prect)
65 {
66 int new_top;
67 RECT rt;
68
69 if (IsWindowVisible(Globals.hToolBar)) {
70 SendMessage(Globals.hToolBar, WM_SIZE, 0, 0);
71 GetClientRect(Globals.hToolBar, &rt);
72 prect->top = rt.bottom+3;
73 prect->bottom -= rt.bottom+3;
74 }
75 if (IsWindowVisible(Globals.hDriveBar)) {
76 SendMessage(Globals.hDriveBar, WM_SIZE, 0, 0);
77 GetClientRect(Globals.hDriveBar, &rt);
78 new_top = --prect->top + rt.bottom+3;
79 MoveWindow(Globals.hDriveBar, 0, prect->top, rt.right, new_top, TRUE);
80 prect->top = new_top;
81 prect->bottom -= rt.bottom+2;
82 }
83 if (IsWindowVisible(Globals.hStatusBar)) {
84 SetupStatusBar(TRUE);
85 // int parts[] = {300, 500};
86 // SendMessage(Globals.hStatusBar, WM_SIZE, 0, 0);
87 // SendMessage(Globals.hStatusBar, SB_SETPARTS, 2, (LPARAM)&parts);
88 GetClientRect(Globals.hStatusBar, &rt);
89 prect->bottom -= rt.bottom;
90 }
91 MoveWindow(Globals.hMDIClient, prect->left-1,prect->top-1,prect->right+2,prect->bottom+1, TRUE);
92 }
93
94 static void resize_frame(HWND hWnd, int cx, int cy)
95 {
96 RECT rect = {0, 0, cx, cy};
97
98 resize_frame_rect(hWnd, &rect);
99 }
100
101 void resize_frame_client(HWND hWnd)
102 {
103 RECT rect;
104
105 GetClientRect(hWnd, &rect);
106 resize_frame_rect(hWnd, &rect);
107 }
108
109 ////////////////////////////////////////////////////////////////////////////////
110 static HHOOK hcbthook;
111 static ChildWnd* newchild = NULL;
112
113 static LRESULT CALLBACK CBTProc(int code, WPARAM wParam, LPARAM lParam)
114 {
115 if (code == HCBT_CREATEWND && newchild) {
116 ChildWnd* pChildWnd = newchild;
117 newchild = NULL;
118 pChildWnd->hWnd = (HWND)wParam;
119 SetWindowLong(pChildWnd->hWnd, GWL_USERDATA, (LPARAM)pChildWnd);
120 }
121 return CallNextHookEx(hcbthook, code, wParam, lParam);
122 }
123
124
125 /*
126 BOOL FindChildWindow(int cmd)
127 {
128 TCHAR drv[_MAX_DRIVE];
129 LPCTSTR root = Globals.drives;
130 int i;
131 for(i = cmd - ID_DRIVE_FIRST; i--; root++)
132 while(*root)
133 root++;
134 if (activate_drive_window(root))
135 return TRUE;
136 _tsplitpath(root, drv, 0, 0, 0);
137 if (!SetCurrentDirectory(drv)) {
138 display_error(hWnd, GetLastError());
139 //return TRUE;
140 }
141 return FALSE;
142 }
143 */
144
145 static ChildWnd* alloc_child_window(LPCTSTR path)
146 {
147 TCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
148 ChildWnd* pChildWnd = (ChildWnd*)malloc(sizeof(ChildWnd));
149 Root* root = &pChildWnd->root;
150 Entry* entry;
151
152 memset(pChildWnd, 0, sizeof(ChildWnd));
153 pChildWnd->left.treePane = TRUE;
154 pChildWnd->left.visible_cols = 0;
155 pChildWnd->right.treePane = FALSE;
156 #ifndef _NO_EXTENSIONS
157 pChildWnd->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_INDEX|COL_LINKS;
158 #else
159 pChildWnd->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES;
160 #endif
161 pChildWnd->pos.length = sizeof(WINDOWPLACEMENT);
162 pChildWnd->pos.flags = 0;
163 pChildWnd->pos.showCmd = SW_SHOWNORMAL;
164 pChildWnd->pos.rcNormalPosition.left = CW_USEDEFAULT;
165 pChildWnd->pos.rcNormalPosition.top = CW_USEDEFAULT;
166 pChildWnd->pos.rcNormalPosition.right = CW_USEDEFAULT;
167 pChildWnd->pos.rcNormalPosition.bottom = CW_USEDEFAULT;
168 pChildWnd->nFocusPanel = 0;
169 pChildWnd->nSplitPos = 200;
170 pChildWnd->sortOrder = SORT_NAME;
171 pChildWnd->header_wdths_ok = FALSE;
172 lstrcpy(pChildWnd->szPath, path);
173 _tsplitpath(path, drv, dir, name, ext);
174 #if !defined(_NO_EXTENSIONS) && defined(__linux__)
175 if (*path == '/') {
176 root->drive_type = GetDriveType(path);
177 lstrcat(drv, _T("/"));
178 lstrcpy(root->volname, _T("root fs"));
179 root->fs_flags = 0;
180 lstrcpy(root->fs, _T("unixfs"));
181 lstrcpy(root->path, _T("/"));
182 entry = read_tree_unix(root, path, pChildWnd->sortOrder);
183 } else
184 #endif
185 {
186 root->drive_type = GetDriveType(path);
187 lstrcat(drv, _T("\\"));
188 GetVolumeInformation(drv, root->volname, _MAX_FNAME, 0, 0, &root->fs_flags, root->fs, _MAX_DIR);
189 lstrcpy(root->path, drv);
190 entry = read_tree_win(root, path, pChildWnd->sortOrder);
191 }
192 //@@lstrcpy(root->entry.data.cFileName, drv);
193 wsprintf(root->entry.data.cFileName, _T("%s - %s"), drv, root->fs);
194 root->entry.data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
195 pChildWnd->left.root = &root->entry;
196 set_curdir(pChildWnd, entry);
197 return pChildWnd;
198 }
199
200 HWND CreateChildWindow(int drv_id)
201 {
202 //TCHAR drv[_MAX_DRIVE];
203 TCHAR path[MAX_PATH];
204 ChildWnd* pChildWnd = NULL;
205 /*
206 LPCTSTR root = Globals.drives;
207 int i;
208 for(i = cmd - ID_DRIVE_FIRST; i--; root++)
209 while(*root)
210 root++;
211 if (activate_drive_window(root))
212 return 0;
213 _tsplitpath(root, drv, 0, 0, 0);
214 if (!SetCurrentDirectory(drv)) {
215 display_error(hWnd, GetLastError());
216 return 0;
217 }
218 */
219 GetCurrentDirectory(MAX_PATH, path);
220 // pChildWnd = (ChildWnd*)malloc(sizeof(ChildWnd));
221 pChildWnd = alloc_child_window(path);
222 // if (!create_child_window(pChildWnd))
223 // free(pChildWnd);
224
225 if (pChildWnd != NULL) {
226 MDICREATESTRUCT mcs = {
227 szChildClass, path, hInst,
228 CW_USEDEFAULT, CW_USEDEFAULT,
229 CW_USEDEFAULT, CW_USEDEFAULT,
230 0/*style*/, 0/*lParam*/
231 };
232 hcbthook = SetWindowsHookEx(WH_CBT, CBTProc, 0, GetCurrentThreadId());
233 newchild = pChildWnd;
234 pChildWnd->hWnd = (HWND)SendMessage(Globals.hMDIClient, WM_MDICREATE, 0, (LPARAM)&mcs);
235 UnhookWindowsHookEx(hcbthook);
236 if (pChildWnd->hWnd == NULL) {
237 free(pChildWnd);
238 newchild = pChildWnd = NULL;
239 }
240 return pChildWnd->hWnd;
241 }
242 return 0;
243 }
244
245 BOOL CALLBACK CloseEnumProc(HWND hWnd, LPARAM lParam)
246 {
247 if (!GetWindow(hWnd, GW_OWNER)) {
248 SendMessage(GetParent(hWnd), WM_MDIRESTORE, (WPARAM)hWnd, 0);
249 if (SendMessage(hWnd, WM_QUERYENDSESSION, 0, 0)) {
250 SendMessage(GetParent(hWnd), WM_MDIDESTROY, (WPARAM)hWnd, 0);
251 }
252 }
253 return 1;
254 }
255
256 void OnEnterMenuLoop(HWND hWnd)
257 {
258 int nParts;
259
260 // Update the status bar pane sizes
261 nParts = -1;
262 SendMessage(Globals.hStatusBar, SB_SETPARTS, 1, (long)&nParts);
263 bInMenuLoop = TRUE;
264 SendMessage(Globals.hStatusBar, SB_SETTEXT, (WPARAM)0, (LPARAM)_T(""));
265 }
266
267 void OnExitMenuLoop(HWND hWnd)
268 {
269 RECT rc;
270 int nParts[3];
271
272 bInMenuLoop = FALSE;
273 // Update the status bar pane sizes
274 GetClientRect(hWnd, &rc);
275 nParts[0] = 100;
276 nParts[1] = 210;
277 nParts[2] = rc.right;
278 SendMessage(Globals.hStatusBar, SB_SETPARTS, 3, (long)nParts);
279 SendMessage(Globals.hStatusBar, SB_SETTEXT, 0, (LPARAM)_T(""));
280 SetupStatusBar(TRUE);
281 UpdateStatusBar();
282 }
283
284 void OnMenuSelect(HWND hWnd, UINT nItemID, UINT nFlags, HMENU hSysMenu)
285 {
286 TCHAR str[100];
287
288 strcpy(str, TEXT(""));
289 if (nFlags & MF_POPUP) {
290 if (hSysMenu != GetMenu(hWnd)) {
291 if (nItemID == 2) nItemID = 5;
292 }
293 }
294 if (LoadString(Globals.hInstance, nItemID, str, 100)) {
295 // load appropriate string
296 LPTSTR lpsz = str;
297 // first newline terminates actual string
298 lpsz = _tcschr(lpsz, '\n');
299 if (lpsz != NULL)
300 *lpsz = '\0';
301 }
302 SendMessage(Globals.hStatusBar, SB_SETTEXT, 0, (LPARAM)str);
303 }
304
305
306 static BOOL activate_drive_window(LPCTSTR path)
307 {
308 TCHAR drv1[_MAX_DRIVE], drv2[_MAX_DRIVE];
309 HWND child_wnd;
310
311 _tsplitpath(path, drv1, 0, 0, 0);
312
313 // search for a already open window for the same drive
314 for (child_wnd = GetNextWindow(Globals.hMDIClient,GW_CHILD);
315 child_wnd;
316 child_wnd = GetNextWindow(child_wnd, GW_HWNDNEXT)) {
317 ChildWnd* pChildWnd = (ChildWnd*) GetWindowLong(child_wnd, GWL_USERDATA);
318 if (pChildWnd) {
319 _tsplitpath(pChildWnd->root.path, drv2, 0, 0, 0);
320 if (!lstrcmpi(drv2, drv1)) {
321 SendMessage(Globals.hMDIClient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
322 if (IsMinimized(child_wnd))
323 ShowWindow(child_wnd, SW_SHOWNORMAL);
324 return TRUE;
325 }
326 }
327 }
328 return FALSE;
329 }
330
331 static void toggle_child(HWND hWnd, UINT cmd, HWND hchild)
332 {
333 BOOL vis = IsWindowVisible(hchild);
334
335 CheckMenuItem(Globals.hMenuOptions, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
336 ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
337 #ifndef _NO_EXTENSIONS
338 if (g_fullscreen.mode)
339 fullscreen_move(hWnd);
340 #endif
341 resize_frame_client(hWnd);
342 }
343
344 ////////////////////////////////////////////////////////////////////////////////
345 //
346 // FUNCTION: _CmdWndProc(HWND, unsigned, WORD, LONG)
347 //
348 // PURPOSE: Processes WM_COMMAND messages for the main frame window.
349 //
350 //
351
352 LRESULT _CmdWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
353 {
354 UINT cmd = LOWORD(wParam);
355 HWND hChildWnd;
356 // HWND hwndClient = (HWND)SendMessage(Globals.hMDIClient, WM_MDIGETACTIVE, 0, 0);
357 // if (hwndClient)
358 // if (SendMessage(hwndClient, WM_DISPATCH_COMMAND, wParam, lParam))
359 // return 0;
360
361 if (cmd >= ID_DRIVE_FIRST && cmd <= (ID_DRIVE_FIRST + 0xFF)) {
362 TCHAR drv[_MAX_DRIVE];
363 //TCHAR path[MAX_PATH];
364 //ChildWnd* pChildWnd;
365 LPCTSTR root = Globals.drives;
366 int i;
367 for (i = cmd - ID_DRIVE_FIRST; i--; root++)
368 while (*root)
369 root++;
370 if (activate_drive_window(root))
371 return 0;
372 _tsplitpath(root, drv, 0, 0, 0);
373 if (!SetCurrentDirectory(drv)) {
374 display_error(hWnd, GetLastError());
375 return 0;
376 }
377 //GetCurrentDirectory(MAX_PATH, path); //@@ letztes Verzeichnis pro Laufwerk speichern
378 //CreateChildWindow(path);
379 CreateChildWindow(cmd - ID_DRIVE_FIRST);
380
381 // pChildWnd = alloc_child_window(path);
382 // if (!create_child_window(pChildWnd))
383 // free(pChildWnd);
384 } else {
385 switch (cmd) {
386 case ID_WINDOW_CLOSEALL:
387 EnumChildWindows(Globals.hMDIClient, &CloseEnumProc, 0);
388 break;
389 case ID_WINDOW_CLOSE:
390 hChildWnd = (HWND) SendMessage(Globals.hMDIClient, WM_MDIGETACTIVE, 0, 0);
391 if (!SendMessage(hChildWnd, WM_QUERYENDSESSION, 0, 0))
392 SendMessage(Globals.hMDIClient, WM_MDIDESTROY, (WPARAM)hChildWnd, 0);
393 break;
394 case ID_FILE_EXIT:
395 SendMessage(hWnd, WM_CLOSE, 0, 0);
396 break;
397 case ID_FILE_RUN:
398 OnFileRun();
399 break;
400 case ID_DISK_FORMAT_DISK:
401 // SHFormatDrive(hWnd, 0 /* A: */, SHFMT_ID_DEFAULT, 0);
402 {
403 UINT OldMode = SetErrorMode(0); // Get the current Error Mode settings.
404 SetErrorMode(OldMode & ~SEM_FAILCRITICALERRORS); // Force O/S to handle
405 // Call SHFormatDrive here.
406 SHFormatDrive(hWnd, 0 /* A: */, SHFMT_ID_DEFAULT, 0);
407 SetErrorMode(OldMode); // Put it back the way it was.
408 }
409 break;
410 case ID_OPTIONS_CONFIRMATION:
411 {
412 // struct ExecuteDialog dlg = {{0}};
413 // if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_EXECUTE), hWnd, ExecuteDialogWndProg, (LPARAM)&dlg) == IDOK)
414 // ShellExecute(hWnd, _T("open")/*operation*/, dlg.cmd/*file*/, NULL/*parameters*/, NULL/*dir*/, dlg.cmdshow);
415 }
416 break;
417 case ID_OPTIONS_FONT:
418 break;
419 case ID_OPTIONS_CUSTOMISE_TOOLBAR:
420 break;
421 case ID_OPTIONS_TOOLBAR:
422 toggle_child(hWnd, cmd, Globals.hToolBar);
423 break;
424 case ID_OPTIONS_DRIVEBAR:
425 toggle_child(hWnd, cmd, Globals.hDriveBar);
426 break;
427 case ID_OPTIONS_STATUSBAR:
428 toggle_child(hWnd, cmd, Globals.hStatusBar);
429 break;
430 case ID_OPTIONS_OPEN_NEW_WINDOW_ON_CONNECT:
431 break;
432 case ID_OPTIONS_MINIMISE_ON_USE:
433 break;
434 case ID_OPTIONS_SAVE_ON_EXIT:
435 break;
436
437 case ID_WINDOW_NEW_WINDOW:
438 CreateChildWindow(-1);
439 // {
440 // ChildWnd* pChildWnd = alloc_child_window(path);
441 // if (!create_child_window(pChildWnd))
442 // free(pChildWnd);
443 // }
444 break;
445 case ID_WINDOW_CASCADE:
446 SendMessage(Globals.hMDIClient, WM_MDICASCADE, 0, 0);
447 break;
448 case ID_WINDOW_TILE_HORZ:
449 SendMessage(Globals.hMDIClient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
450 break;
451 case ID_WINDOW_TILE_VERT:
452 SendMessage(Globals.hMDIClient, WM_MDITILE, MDITILE_VERTICAL, 0);
453 break;
454 case ID_WINDOW_ARRANGE_ICONS:
455 SendMessage(Globals.hMDIClient, WM_MDIICONARRANGE, 0, 0);
456 break;
457 case ID_HELP_CONTENTS:
458 WinHelp(hWnd, _T("winfile"), HELP_INDEX, 0);
459 break;
460 case ID_HELP_SEARCH_HELP:
461 break;
462 case ID_HELP_HOW_TO_USE_HELP:
463 #ifdef WINSHELLAPI
464 ShellAbout(hWnd, szTitle, "", LoadIcon(Globals.hInstance, (LPCTSTR)IDI_WINFILE));
465 #endif
466 break;
467 case ID_HELP_ABOUT:
468 ShowAboutBox(hWnd);
469 break;
470 default:
471 /*
472 if ((cmd<IDW_FIRST_CHILD || cmd>=IDW_FIRST_CHILD+0x100) &&
473 (cmd<SC_SIZE || cmd>SC_RESTORE)) {
474 MessageBox(hWnd, _T("Not yet implemented"), _T("Winefile"), MB_OK);
475 }
476 return DefFrameProc(hWnd, Globals.hMDIClient, message, wParam, lParam);
477 */
478 hChildWnd = (HWND)SendMessage(Globals.hMDIClient, WM_MDIGETACTIVE, 0, 0);
479 if (IsWindow(hChildWnd))
480 SendMessage(hChildWnd, WM_COMMAND, wParam, lParam);
481 else
482 return DefFrameProc(hWnd, Globals.hMDIClient, message, wParam, lParam);
483 }
484 }
485 return 0;
486 }
487
488
489 ////////////////////////////////////////////////////////////////////////////////
490 //
491 // FUNCTION: FrameWndProc(HWND, unsigned, WORD, LONG)
492 //
493 // PURPOSE: Processes messages for the main frame window.
494 //
495 // WM_COMMAND - process the application menu
496 // WM_DESTROY - post a quit message and return
497 //
498 //
499
500 LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
501 {
502 switch (message) {
503 case WM_CREATE:
504 {
505 HMENU hMenuWindow = GetSubMenu(Globals.hMenuFrame, GetMenuItemCount(Globals.hMenuFrame)-2);
506 CLIENTCREATESTRUCT ccs = { hMenuWindow, IDW_FIRST_CHILD };
507 #if 0
508 hMDIClient = CreateWindow(_T("MDICLIENT"), NULL,
509 WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
510 0, 0, 0, 0,
511 hWnd, (HMENU)1, hInst, &ccs);
512 #else
513 Globals.hMDIClient = CreateWindowEx(0, _T("MDICLIENT"), NULL,
514 //WS_CHILD|WS_CLIPCHILDREN|WS_VSCROLL|WS_HSCROLL|WS_VISIBLE|WS_BORDER,
515 WS_CHILD|WS_CLIPCHILDREN|WS_VISIBLE,
516 0, 0, 0, 0,
517 hWnd, (HMENU)0, hInst, &ccs);
518 #endif
519 }
520 break;
521 case WM_COMMAND:
522 return _CmdWndProc(hWnd, message, wParam, lParam);
523 break;
524 case WM_SIZE:
525 resize_frame_client(hWnd);
526 break;
527 case WM_ENTERMENULOOP:
528 OnEnterMenuLoop(hWnd);
529 break;
530 case WM_EXITMENULOOP:
531 OnExitMenuLoop(hWnd);
532 break;
533 case WM_MENUSELECT:
534 OnMenuSelect(hWnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
535 break;
536 case WM_DESTROY:
537 PostQuitMessage(0);
538 break;
539 case WM_QUERYENDSESSION:
540 case WM_CLOSE:
541 SendMessage(hWnd, WM_COMMAND, ID_WINDOW_CLOSEALL, 0);
542 if (GetWindow(Globals.hMDIClient, GW_CHILD) != NULL)
543 return 0;
544 // else fall thru...
545 default:
546 return DefFrameProc(hWnd, Globals.hMDIClient, message, wParam, lParam);
547 }
548 return 0;
549 }