make read_directory_unix() static
[reactos.git] / reactos / subsys / system / winefile / winefile.c
1 /*
2 * Winefile
3 *
4 * Copyright 2000, 2003, 2004 Martin Fuchs
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "winefile.h"
22
23 #include "resource.h"
24
25
26 #ifdef _NO_EXTENSIONS
27 #undef _LEFT_FILES
28 #endif
29
30 #ifndef _MAX_PATH
31 #define _MAX_DRIVE 3
32 #define _MAX_FNAME 256
33 #define _MAX_DIR _MAX_FNAME
34 #define _MAX_EXT _MAX_FNAME
35 #define _MAX_PATH 260
36 #endif
37
38 #ifdef NONAMELESSUNION
39 #define UNION_MEMBER(x) DUMMYUNIONNAME.x
40 #else
41 #define UNION_MEMBER(x) x
42 #endif
43
44
45 #ifdef _SHELL_FOLDERS
46 #define DEFAULT_SPLIT_POS 300
47 #else
48 #define DEFAULT_SPLIT_POS 200
49 #endif
50
51
52 enum ENTRY_TYPE {
53 ET_WINDOWS,
54 ET_UNIX,
55 #ifdef _SHELL_FOLDERS
56 ET_SHELL
57 #endif
58 };
59
60 typedef struct _Entry {
61 struct _Entry* next;
62 struct _Entry* down;
63 struct _Entry* up;
64
65 BOOL expanded;
66 BOOL scanned;
67 int level;
68
69 WIN32_FIND_DATA data;
70
71 #ifndef _NO_EXTENSIONS
72 BY_HANDLE_FILE_INFORMATION bhfi;
73 BOOL bhfi_valid;
74 enum ENTRY_TYPE etype;
75 #endif
76 #ifdef _SHELL_FOLDERS
77 LPITEMIDLIST pidl;
78 IShellFolder* folder;
79 HICON hicon;
80 #endif
81 } Entry;
82
83 typedef struct {
84 Entry entry;
85 TCHAR path[MAX_PATH];
86 TCHAR volname[_MAX_FNAME];
87 TCHAR fs[_MAX_DIR];
88 DWORD drive_type;
89 DWORD fs_flags;
90 } Root;
91
92 enum COLUMN_FLAGS {
93 COL_SIZE = 0x01,
94 COL_DATE = 0x02,
95 COL_TIME = 0x04,
96 COL_ATTRIBUTES = 0x08,
97 COL_DOSNAMES = 0x10,
98 #ifdef _NO_EXTENSIONS
99 COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES
100 #else
101 COL_INDEX = 0x20,
102 COL_LINKS = 0x40,
103 COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES|COL_INDEX|COL_LINKS
104 #endif
105 };
106
107 typedef enum {
108 SORT_NAME,
109 SORT_EXT,
110 SORT_SIZE,
111 SORT_DATE
112 } SORT_ORDER;
113
114 typedef struct {
115 HWND hwnd;
116 #ifndef _NO_EXTENSIONS
117 HWND hwndHeader;
118 #endif
119
120 #ifndef _NO_EXTENSIONS
121 #define COLUMNS 10
122 #else
123 #define COLUMNS 5
124 #endif
125 int widths[COLUMNS];
126 int positions[COLUMNS+1];
127
128 BOOL treePane;
129 int visible_cols;
130 Entry* root;
131 Entry* cur;
132 } Pane;
133
134 typedef struct {
135 HWND hwnd;
136 Pane left;
137 Pane right;
138 int focus_pane; /* 0: left 1: right */
139 WINDOWPLACEMENT pos;
140 int split_pos;
141 BOOL header_wdths_ok;
142
143 TCHAR path[MAX_PATH];
144 Root root;
145
146 SORT_ORDER sortOrder;
147 } ChildWnd;
148
149
150 extern void WineLicense(HWND hwnd);
151 extern void WineWarranty(HWND hwnd);
152
153
154 #ifdef __WINE__
155
156 /* functions in unixcalls.c */
157
158 extern void call_getcwd(char* buffer, size_t len);
159 extern void* call_opendir(const char* path);
160 extern int call_readdir(void* pdir, char* name, unsigned* pinode);
161 extern void call_closedir(void* pdir);
162
163 extern int call_stat(
164 const char* path, int* pis_dir,
165 unsigned long* psize_low, unsigned long* psize_high,
166 time_t* patime, time_t* pmtime,
167 unsigned long* plinks
168 );
169
170 /* call vswprintf() in msvcrt.dll */
171 int swprintf(wchar_t* buffer, const wchar_t* fmt, ...)
172 {
173 static int (__cdecl *vswprintf)(wchar_t*, const wchar_t*, va_list);
174
175 va_list ap;
176 int ret;
177
178 if (!vswprintf) {
179 HMODULE hmod = LoadLibraryA("msvcrt");
180 vswprintf = (int(__cdecl*)(wchar_t*,const wchar_t*,va_list)) GetProcAddress(hmod, "vswprintf");
181 }
182
183 va_start(ap, fmt);
184 ret = vswprintf(buffer, fmt, ap);
185 va_end(ap);
186
187 return 0;
188 }
189
190 #endif
191
192
193 static void read_directory(Entry* dir, LPCTSTR path, SORT_ORDER sortOrder, HWND hwnd);
194 static void set_curdir(ChildWnd* child, Entry* entry, HWND hwnd);
195 static void get_path(Entry* dir, PTSTR path);
196
197 LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
198 LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
199 LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
200
201
202 /* globals */
203 WINEFILE_GLOBALS Globals;
204
205
206 /* some common string constants */
207 const static TCHAR sEmpty[] = {'\0'};
208 const static TCHAR sSpace[] = {' ', '\0'};
209 const static TCHAR sNumFmt[] = {'%','d','\0'};
210 const static TCHAR sQMarks[] = {'?','?','?','\0'};
211
212 /* window class names */
213 const static TCHAR sWINEFILEFRAME[] = {'W','F','S','_','F','r','a','m','e','\0'};
214 const static TCHAR sWINEFILETREE[] = {'W','F','S','_','T','r','e','e','\0'};
215
216 #ifdef _MSC_VER
217 /* #define LONGLONGARG _T("I64") */
218 const static TCHAR sLongHexFmt[] = {'%','I','6','4','X','\0'};
219 const static TCHAR sLongNumFmt[] = {'%','I','6','4','d','\0'};
220 #else
221 /* #define LONGLONGARG _T("L") */
222 const static TCHAR sLongHexFmt[] = {'%','L','X','\0'};
223 const static TCHAR sLongNumFmt[] = {'%','L','d','\0'};
224 #endif
225
226
227 /* load resource string */
228 static LPTSTR load_string(LPTSTR buffer, UINT id)
229 {
230 LoadString(Globals.hInstance, id, buffer, BUFFER_LEN);
231
232 return buffer;
233 }
234
235 #define RS(b, i) load_string(b, i)
236
237
238 /* display error message for the specified WIN32 error code */
239 static void display_error(HWND hwnd, DWORD error)
240 {
241 TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
242 PTSTR msg;
243
244 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
245 0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PTSTR)&msg, 0, NULL))
246 MessageBox(hwnd, msg, RS(b2,IDS_WINEFILE), MB_OK);
247 else
248 MessageBox(hwnd, RS(b1,IDS_ERROR), RS(b2,IDS_WINEFILE), MB_OK);
249
250 LocalFree(msg);
251 }
252
253
254 /* allocate and initialise a directory entry */
255 static Entry* alloc_entry()
256 {
257 Entry* entry = (Entry*) malloc(sizeof(Entry));
258
259 #ifdef _SHELL_FOLDERS
260 entry->pidl = NULL;
261 entry->folder = NULL;
262 entry->hicon = 0;
263 #endif
264
265 return entry;
266 }
267
268 /* free a directory entry */
269 static void free_entry(Entry* entry)
270 {
271 #ifdef _SHELL_FOLDERS
272 if (entry->hicon && entry->hicon!=(HICON)-1)
273 DestroyIcon(entry->hicon);
274
275 if (entry->folder && entry->folder!=Globals.iDesktop)
276 (*entry->folder->lpVtbl->Release)(entry->folder);
277
278 if (entry->pidl)
279 (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, entry->pidl);
280 #endif
281
282 free(entry);
283 }
284
285 /* recursively free all child entries */
286 static void free_entries(Entry* dir)
287 {
288 Entry *entry, *next=dir->down;
289
290 if (next) {
291 dir->down = 0;
292
293 do {
294 entry = next;
295 next = entry->next;
296
297 free_entries(entry);
298 free_entry(entry);
299 } while(next);
300 }
301 }
302
303
304 static void read_directory_win(Entry* dir, LPCTSTR path)
305 {
306 Entry* first_entry = NULL;
307 Entry* last = NULL;
308 Entry* entry;
309
310 int level = dir->level + 1;
311 WIN32_FIND_DATA w32fd;
312 HANDLE hFind;
313 #ifndef _NO_EXTENSIONS
314 HANDLE hFile;
315 #endif
316
317 TCHAR buffer[MAX_PATH], *p;
318 for(p=buffer; *path; )
319 *p++ = *path++;
320
321 *p++ = '\\';
322 p[0] = '*';
323 p[1] = '\0';
324
325 hFind = FindFirstFile(buffer, &w32fd);
326
327 if (hFind != INVALID_HANDLE_VALUE) {
328 do {
329 entry = alloc_entry();
330
331 if (!first_entry)
332 first_entry = entry;
333
334 if (last)
335 last->next = entry;
336
337 memcpy(&entry->data, &w32fd, sizeof(WIN32_FIND_DATA));
338 entry->down = NULL;
339 entry->up = dir;
340 entry->expanded = FALSE;
341 entry->scanned = FALSE;
342 entry->level = level;
343
344 #ifdef _NO_EXTENSIONS
345 /* hide directory entry "." */
346 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
347 LPCTSTR name = entry->data.cFileName;
348
349 if (name[0]=='.' && name[1]=='\0')
350 continue;
351 }
352 #else
353 entry->etype = ET_WINDOWS;
354 entry->bhfi_valid = FALSE;
355
356 lstrcpy(p, entry->data.cFileName);
357
358 hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
359 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
360
361 if (hFile != INVALID_HANDLE_VALUE) {
362 if (GetFileInformationByHandle(hFile, &entry->bhfi))
363 entry->bhfi_valid = TRUE;
364
365 CloseHandle(hFile);
366 }
367 #endif
368
369 last = entry;
370 } while(FindNextFile(hFind, &entry->data));
371
372 last->next = NULL;
373
374 FindClose(hFind);
375 }
376
377 dir->down = first_entry;
378 dir->scanned = TRUE;
379 }
380
381
382 static Entry* find_entry_win(Entry* dir, LPCTSTR name)
383 {
384 Entry* entry;
385
386 for(entry=dir->down; entry; entry=entry->next) {
387 LPCTSTR p = name;
388 LPCTSTR q = entry->data.cFileName;
389
390 do {
391 if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
392 return entry;
393 } while(tolower(*p++) == tolower(*q++));
394
395 p = name;
396 q = entry->data.cAlternateFileName;
397
398 do {
399 if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
400 return entry;
401 } while(tolower(*p++) == tolower(*q++));
402 }
403
404 return 0;
405 }
406
407
408 static Entry* read_tree_win(Root* root, LPCTSTR path, SORT_ORDER sortOrder, HWND hwnd)
409 {
410 TCHAR buffer[MAX_PATH];
411 Entry* entry = &root->entry;
412 LPCTSTR s = path;
413 PTSTR d = buffer;
414
415 HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
416
417 #ifndef _NO_EXTENSIONS
418 entry->etype = ET_WINDOWS;
419 #endif
420
421 while(entry) {
422 while(*s && *s!=TEXT('\\') && *s!=TEXT('/'))
423 *d++ = *s++;
424
425 while(*s==TEXT('\\') || *s==TEXT('/'))
426 s++;
427
428 *d++ = TEXT('\\');
429 *d = TEXT('\0');
430
431 read_directory(entry, buffer, sortOrder, hwnd);
432
433 if (entry->down)
434 entry->expanded = TRUE;
435
436 if (!*s)
437 break;
438
439 entry = find_entry_win(entry, s);
440 }
441
442 SetCursor(old_cursor);
443
444 return entry;
445 }
446
447
448 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
449
450 static BOOL time_to_filetime(const time_t* t, FILETIME* ftime)
451 {
452 struct tm* tm = gmtime(t);
453 SYSTEMTIME stime;
454
455 if (!tm)
456 return FALSE;
457
458 stime.wYear = tm->tm_year+1900;
459 stime.wMonth = tm->tm_mon+1;
460 /* stime.wDayOfWeek */
461 stime.wDay = tm->tm_mday;
462 stime.wHour = tm->tm_hour;
463 stime.wMinute = tm->tm_min;
464 stime.wSecond = tm->tm_sec;
465
466 return SystemTimeToFileTime(&stime, ftime);
467 }
468
469 static void read_directory_unix(Entry* dir, LPCTSTR path)
470 {
471 Entry* first_entry = NULL;
472 Entry* last = NULL;
473 Entry* entry;
474 void* pdir;
475
476 #ifdef UNICODE
477 char cpath[MAX_PATH];
478
479 WideCharToMultiByte(CP_UNIXCP, 0, path, -1, cpath, MAX_PATH, NULL, NULL);
480 #else
481 const char* cpath = path;
482 #endif
483
484 pdir = call_opendir(cpath);
485
486 int level = dir->level + 1;
487
488 if (pdir) {
489 char buffer[MAX_PATH];
490 time_t atime, mtime;
491 unsigned inode;
492 int is_dir;
493 const char* s;
494 char* p;
495
496 for(p=buffer,s=cpath; *s; )
497 *p++ = *s++;
498
499 if (p==buffer || p[-1]!='/')
500 *p++ = '/';
501
502 while(call_readdir(pdir, p, &inode)) {
503 entry = alloc_entry();
504
505 if (!first_entry)
506 first_entry = entry;
507
508 if (last)
509 last->next = entry;
510
511 entry->etype = ET_UNIX;
512
513 #ifdef UNICODE
514 MultiByteToWideChar(CP_UNIXCP, 0, p, -1, entry->data.cFileName, MAX_PATH);
515 #else
516 lstrcpy(entry->data.cFileName, p);
517 #endif
518
519 entry->data.dwFileAttributes = p[0]=='.'? FILE_ATTRIBUTE_HIDDEN: 0;
520
521 if (!call_stat(buffer, &is_dir,
522 &entry->data.nFileSizeLow, &entry->data.nFileSizeHigh,
523 &atime, &mtime, &entry->bhfi.nNumberOfLinks))
524 {
525 if (is_dir)
526 entry->data.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
527
528 memset(&entry->data.ftCreationTime, 0, sizeof(FILETIME));
529 time_to_filetime(&atime, &entry->data.ftLastAccessTime);
530 time_to_filetime(&mtime, &entry->data.ftLastWriteTime);
531
532 entry->bhfi.nFileIndexLow = inode;
533 entry->bhfi.nFileIndexHigh = 0;
534
535 entry->bhfi_valid = TRUE;
536 } else {
537 entry->data.nFileSizeLow = 0;
538 entry->data.nFileSizeHigh = 0;
539 entry->bhfi_valid = FALSE;
540 }
541
542 entry->down = NULL;
543 entry->up = dir;
544 entry->expanded = FALSE;
545 entry->scanned = FALSE;
546 entry->level = level;
547
548 last = entry;
549 }
550
551 last->next = NULL;
552
553 call_closedir(pdir);
554 }
555
556 dir->down = first_entry;
557 dir->scanned = TRUE;
558 }
559
560 static Entry* find_entry_unix(Entry* dir, LPCTSTR name)
561 {
562 Entry* entry;
563
564 for(entry=dir->down; entry; entry=entry->next) {
565 LPCTSTR p = name;
566 LPCTSTR q = entry->data.cFileName;
567
568 do {
569 if (!*p || *p==TEXT('/'))
570 return entry;
571 } while(*p++ == *q++);
572 }
573
574 return 0;
575 }
576
577 static Entry* read_tree_unix(Root* root, LPCTSTR path, SORT_ORDER sortOrder, HWND hwnd)
578 {
579 TCHAR buffer[MAX_PATH];
580 Entry* entry = &root->entry;
581 LPCTSTR s = path;
582 PTSTR d = buffer;
583
584 HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
585
586 entry->etype = ET_UNIX;
587
588 while(entry) {
589 while(*s && *s!=TEXT('/'))
590 *d++ = *s++;
591
592 while(*s == TEXT('/'))
593 s++;
594
595 *d++ = TEXT('/');
596 *d = TEXT('\0');
597
598 read_directory(entry, buffer, sortOrder, hwnd);
599
600 if (entry->down)
601 entry->expanded = TRUE;
602
603 if (!*s)
604 break;
605
606 entry = find_entry_unix(entry, s);
607 }
608
609 SetCursor(old_cursor);
610
611 return entry;
612 }
613
614 #endif /* !defined(_NO_EXTENSIONS) && defined(__WINE__) */
615
616
617 #ifdef _SHELL_FOLDERS
618
619 #ifdef UNICODE
620 #define tcscpyn strcpyn
621 #define get_strret get_strretW
622 #define path_from_pidl path_from_pidlW
623 #else
624 #define tcscpyn wcscpyn
625 #define get_strret get_strretA
626 #define path_from_pidl path_from_pidlA
627 #endif
628
629
630 static LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count)
631 {
632 LPCSTR s;
633 LPSTR d = dest;
634
635 for(s=source; count&&(*d++=*s++); )
636 count--;
637
638 return dest;
639 }
640
641 static LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count)
642 {
643 LPCWSTR s;
644 LPWSTR d = dest;
645
646 for(s=source; count&&(*d++=*s++); )
647 count--;
648
649 return dest;
650 }
651
652
653 static void get_strretA(STRRET* str, const SHITEMID* shiid, LPSTR buffer, int len)
654 {
655 switch(str->uType) {
656 case STRRET_WSTR:
657 WideCharToMultiByte(CP_ACP, 0, str->UNION_MEMBER(pOleStr), -1, buffer, len, NULL, NULL);
658 break;
659
660 case STRRET_OFFSET:
661 strcpyn(buffer, (LPCSTR)shiid+str->UNION_MEMBER(uOffset), len);
662 break;
663
664 case STRRET_CSTR:
665 strcpyn(buffer, str->UNION_MEMBER(cStr), len);
666 }
667 }
668
669 static void get_strretW(STRRET* str, const SHITEMID* shiid, LPWSTR buffer, int len)
670 {
671 switch(str->uType) {
672 case STRRET_WSTR:
673 wcscpyn(buffer, str->UNION_MEMBER(pOleStr), len);
674 break;
675
676 case STRRET_OFFSET:
677 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)shiid+str->UNION_MEMBER(uOffset), -1, buffer, len);
678 break;
679
680 case STRRET_CSTR:
681 MultiByteToWideChar(CP_ACP, 0, str->UNION_MEMBER(cStr), -1, buffer, len);
682 }
683 }
684
685
686 static void free_strret(STRRET* str)
687 {
688 if (str->uType == STRRET_WSTR)
689 (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, str->UNION_MEMBER(pOleStr));
690 }
691
692
693 HRESULT name_from_pidl(IShellFolder* folder, LPITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags)
694 {
695 STRRET str;
696
697 HRESULT hr = (*folder->lpVtbl->GetDisplayNameOf)(folder, pidl, flags, &str);
698
699 if (SUCCEEDED(hr)) {
700 get_strret(&str, &pidl->mkid, buffer, len);
701 free_strret(&str);
702 } else
703 buffer[0] = '\0';
704
705 return hr;
706 }
707
708
709 HRESULT path_from_pidlA(IShellFolder* folder, LPITEMIDLIST pidl, LPSTR buffer, int len)
710 {
711 STRRET str;
712
713 /* SHGDN_FORPARSING: get full path of id list */
714 HRESULT hr = (*folder->lpVtbl->GetDisplayNameOf)(folder, pidl, SHGDN_FORPARSING, &str);
715
716 if (SUCCEEDED(hr)) {
717 get_strretA(&str, &pidl->mkid, buffer, len);
718 free_strret(&str);
719 } else
720 buffer[0] = '\0';
721
722 return hr;
723 }
724
725 HRESULT path_from_pidlW(IShellFolder* folder, LPITEMIDLIST pidl, LPWSTR buffer, int len)
726 {
727 STRRET str;
728
729 /* SHGDN_FORPARSING: get full path of id list */
730 HRESULT hr = (*folder->lpVtbl->GetDisplayNameOf)(folder, pidl, SHGDN_FORPARSING, &str);
731
732 if (SUCCEEDED(hr)) {
733 get_strretW(&str, &pidl->mkid, buffer, len);
734 free_strret(&str);
735 } else
736 buffer[0] = '\0';
737
738 return hr;
739 }
740
741
742 /* create an item id list from a file system path */
743
744 static LPITEMIDLIST get_path_pidl(LPTSTR path, HWND hwnd)
745 {
746 LPITEMIDLIST pidl;
747 HRESULT hr;
748 ULONG len;
749
750 #ifdef UNICODE
751 LPWSTR buffer = path;
752 #else
753 WCHAR buffer[MAX_PATH];
754 MultiByteToWideChar(CP_ACP, 0, path, -1, buffer, MAX_PATH);
755 #endif
756
757 hr = (*Globals.iDesktop->lpVtbl->ParseDisplayName)(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL);
758 if (FAILED(hr))
759 return NULL;
760
761 return pidl;
762 }
763
764
765 /* convert an item id list from relative to absolute (=relative to the desktop) format */
766
767 static LPITEMIDLIST get_to_absolute_pidl(Entry* entry, HWND hwnd)
768 {
769 if (entry->up && entry->up->etype==ET_SHELL) {
770 IShellFolder* folder = entry->up->folder;
771 WCHAR buffer[MAX_PATH];
772
773 HRESULT hr = path_from_pidlW(folder, entry->pidl, buffer, MAX_PATH);
774
775 if (SUCCEEDED(hr)) {
776 LPITEMIDLIST pidl;
777 ULONG len;
778
779 hr = (*Globals.iDesktop->lpVtbl->ParseDisplayName)(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL);
780
781 if (SUCCEEDED(hr))
782 return pidl;
783 }
784 } else if (entry->etype == ET_WINDOWS) {
785 TCHAR path[MAX_PATH];
786
787 get_path(entry, path);
788
789 return get_path_pidl(path, hwnd);
790 } else if (entry->pidl)
791 return ILClone(entry->pidl);
792
793 return NULL;
794 }
795
796
797 HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
798 {
799 IExtractIcon* pExtract;
800
801 if (SUCCEEDED((*folder->lpVtbl->GetUIObjectOf)(folder, 0, 1, (LPCITEMIDLIST*)&pidl, &IID_IExtractIcon, 0, (LPVOID*)&pExtract))) {
802 TCHAR path[_MAX_PATH];
803 unsigned flags;
804 HICON hicon;
805 int idx;
806
807 if (SUCCEEDED((*pExtract->lpVtbl->GetIconLocation)(pExtract, GIL_FORSHELL, path, _MAX_PATH, &idx, &flags))) {
808 if (!(flags & GIL_NOTFILENAME)) {
809 if (idx == -1)
810 idx = 0; /* special case for some control panel applications */
811
812 if ((int)ExtractIconEx(path, idx, 0, &hicon, 1) > 0)
813 flags &= ~GIL_DONTCACHE;
814 } else {
815 HICON hIconLarge = 0;
816
817 HRESULT hr = (*pExtract->lpVtbl->Extract)(pExtract, path, idx, &hIconLarge, &hicon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON)));
818
819 if (SUCCEEDED(hr))
820 DestroyIcon(hIconLarge);
821 }
822
823 return hicon;
824 }
825 }
826
827 return 0;
828 }
829
830
831 static Entry* find_entry_shell(Entry* dir, LPITEMIDLIST pidl)
832 {
833 Entry* entry;
834
835 for(entry=dir->down; entry; entry=entry->next) {
836 if (entry->pidl->mkid.cb == pidl->mkid.cb &&
837 !memcmp(entry->pidl, pidl, entry->pidl->mkid.cb))
838 return entry;
839 }
840
841 return 0;
842 }
843
844 static Entry* read_tree_shell(Root* root, LPITEMIDLIST pidl, SORT_ORDER sortOrder, HWND hwnd)
845 {
846 Entry* entry = &root->entry;
847 Entry* next;
848 LPITEMIDLIST next_pidl = pidl;
849 IShellFolder* folder;
850 IShellFolder* child = NULL;
851 HRESULT hr;
852
853 HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
854
855 #ifndef _NO_EXTENSIONS
856 entry->etype = ET_SHELL;
857 #endif
858
859 folder = Globals.iDesktop;
860
861 while(entry) {
862 entry->pidl = next_pidl;
863 entry->folder = folder;
864
865 if (!pidl->mkid.cb)
866 break;
867
868 /* copy first element of item idlist -> could be replaced by SHBindToParent() */
869 next_pidl = (*Globals.iMalloc->lpVtbl->Alloc)(Globals.iMalloc, pidl->mkid.cb+sizeof(USHORT));
870 memcpy(next_pidl, pidl, pidl->mkid.cb);
871 ((LPITEMIDLIST)((LPBYTE)next_pidl+pidl->mkid.cb))->mkid.cb = 0;
872
873 hr = (*folder->lpVtbl->BindToObject)(folder, next_pidl, 0, &IID_IShellFolder, (void**)&child);
874 if (!SUCCEEDED(hr))
875 break;
876
877 read_directory(entry, NULL, sortOrder, hwnd);
878
879 if (entry->down)
880 entry->expanded = TRUE;
881
882 next = find_entry_shell(entry, next_pidl);
883 if (!next)
884 break;
885
886 folder = child;
887 entry = next;
888
889 /* go to next element */
890 pidl = (LPITEMIDLIST) ((LPBYTE)pidl+pidl->mkid.cb);
891 }
892
893 SetCursor(old_cursor);
894
895 return entry;
896 }
897
898
899 static void fill_w32fdata_shell(IShellFolder* folder, LPCITEMIDLIST pidl, SFGAOF attribs, WIN32_FIND_DATA* w32fdata)
900 {
901 if (!(attribs & SFGAO_FILESYSTEM) ||
902 FAILED(SHGetDataFromIDList(folder, pidl, SHGDFIL_FINDDATA, w32fdata, sizeof(WIN32_FIND_DATA)))) {
903 WIN32_FILE_ATTRIBUTE_DATA fad;
904 IDataObject* pDataObj;
905
906 STGMEDIUM medium = {0, {0}, 0};
907 FORMATETC fmt = {Globals.cfStrFName, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
908
909 HRESULT hr = (*folder->lpVtbl->GetUIObjectOf)(folder, 0, 1, &pidl, &IID_IDataObject, 0, (LPVOID*)&pDataObj);
910
911 if (SUCCEEDED(hr)) {
912 hr = (*pDataObj->lpVtbl->GetData)(pDataObj, &fmt, &medium);
913
914 (*pDataObj->lpVtbl->Release)(pDataObj);
915
916 if (SUCCEEDED(hr)) {
917 LPCTSTR path = (LPCTSTR)GlobalLock(medium.UNION_MEMBER(hGlobal));
918 UINT sem_org = SetErrorMode(SEM_FAILCRITICALERRORS);
919
920 if (GetFileAttributesEx(path, GetFileExInfoStandard, &fad)) {
921 w32fdata->dwFileAttributes = fad.dwFileAttributes;
922 w32fdata->ftCreationTime = fad.ftCreationTime;
923 w32fdata->ftLastAccessTime = fad.ftLastAccessTime;
924 w32fdata->ftLastWriteTime = fad.ftLastWriteTime;
925
926 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
927 w32fdata->nFileSizeLow = fad.nFileSizeLow;
928 w32fdata->nFileSizeHigh = fad.nFileSizeHigh;
929 }
930 }
931
932 SetErrorMode(sem_org);
933
934 GlobalUnlock(medium.UNION_MEMBER(hGlobal));
935 GlobalFree(medium.UNION_MEMBER(hGlobal));
936 }
937 }
938 }
939
940 if (attribs & (SFGAO_FOLDER|SFGAO_HASSUBFOLDER))
941 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
942
943 if (attribs & SFGAO_READONLY)
944 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
945
946 if (attribs & SFGAO_COMPRESSED)
947 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
948 }
949
950
951 static void read_directory_shell(Entry* dir, HWND hwnd)
952 {
953 IShellFolder* folder = dir->folder;
954 int level = dir->level + 1;
955 HRESULT hr;
956
957 IShellFolder* child;
958 IEnumIDList* idlist;
959
960 Entry* first_entry = NULL;
961 Entry* last = NULL;
962 Entry* entry;
963
964 if (!folder)
965 return;
966
967 hr = (*folder->lpVtbl->EnumObjects)(folder, hwnd, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE, &idlist);
968
969 if (SUCCEEDED(hr)) {
970 for(;;) {
971 #define FETCH_ITEM_COUNT 32
972 LPITEMIDLIST pidls[FETCH_ITEM_COUNT];
973 SFGAOF attribs;
974 ULONG cnt = 0;
975 ULONG n;
976
977 memset(pidls, 0, sizeof(pidls));
978
979 hr = (*idlist->lpVtbl->Next)(idlist, FETCH_ITEM_COUNT, pidls, &cnt);
980 if (!SUCCEEDED(hr))
981 break;
982
983 if (hr == S_FALSE)
984 break;
985
986 for(n=0; n<cnt; ++n) {
987 entry = alloc_entry();
988
989 if (!first_entry)
990 first_entry = entry;
991
992 if (last)
993 last->next = entry;
994
995 memset(&entry->data, 0, sizeof(WIN32_FIND_DATA));
996 entry->bhfi_valid = FALSE;
997
998 attribs = ~SFGAO_FILESYSTEM; /*SFGAO_HASSUBFOLDER|SFGAO_FOLDER; SFGAO_FILESYSTEM sorgt dafür, daß "My Documents" anstatt von "Martin's Documents" angezeigt wird */
999
1000 hr = (*folder->lpVtbl->GetAttributesOf)(folder, 1, (LPCITEMIDLIST*)&pidls[n], &attribs);
1001
1002 if (SUCCEEDED(hr)) {
1003 if (attribs != (SFGAOF)~SFGAO_FILESYSTEM) {
1004 fill_w32fdata_shell(folder, pidls[n], attribs, &entry->data);
1005
1006 entry->bhfi_valid = TRUE;
1007 } else
1008 attribs = 0;
1009 } else
1010 attribs = 0;
1011
1012 entry->pidl = pidls[n];
1013
1014 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1015 hr = (*folder->lpVtbl->BindToObject)(folder, pidls[n], 0, &IID_IShellFolder, (void**)&child);
1016
1017 if (SUCCEEDED(hr))
1018 entry->folder = child;
1019 else
1020 entry->folder = NULL;
1021 }
1022 else
1023 entry->folder = NULL;
1024
1025 if (!entry->data.cFileName[0])
1026 /*hr = */name_from_pidl(folder, pidls[n], entry->data.cFileName, MAX_PATH, /*SHGDN_INFOLDER*/0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/);
1027
1028 /* get display icons for files and virtual objects */
1029 if (!(entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1030 !(attribs & SFGAO_FILESYSTEM)) {
1031 entry->hicon = extract_icon(folder, pidls[n]);
1032
1033 if (!entry->hicon)
1034 entry->hicon = (HICON)-1; /* don't try again later */
1035 }
1036
1037 entry->down = NULL;
1038 entry->up = dir;
1039 entry->expanded = FALSE;
1040 entry->scanned = FALSE;
1041 entry->level = level;
1042
1043 #ifndef _NO_EXTENSIONS
1044 entry->etype = ET_SHELL;
1045 entry->bhfi_valid = FALSE;
1046 #endif
1047
1048 last = entry;
1049 }
1050 }
1051
1052 (*idlist->lpVtbl->Release)(idlist);
1053 }
1054
1055 if (last)
1056 last->next = NULL;
1057
1058 dir->down = first_entry;
1059 dir->scanned = TRUE;
1060 }
1061
1062 #endif /* _SHELL_FOLDERS */
1063
1064
1065 /* sort order for different directory/file types */
1066 enum TYPE_ORDER {
1067 TO_DIR = 0,
1068 TO_DOT = 1,
1069 TO_DOTDOT = 2,
1070 TO_OTHER_DIR = 3,
1071 TO_FILE = 4
1072 };
1073
1074 /* distinguish between ".", ".." and any other directory names */
1075 static int TypeOrderFromDirname(LPCTSTR name)
1076 {
1077 if (name[0] == '.') {
1078 if (name[1] == '\0')
1079 return TO_DOT; /* "." */
1080
1081 if (name[1]=='.' && name[2]=='\0')
1082 return TO_DOTDOT; /* ".." */
1083 }
1084
1085 return TO_OTHER_DIR; /* anything else */
1086 }
1087
1088 /* directories first... */
1089 static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
1090 {
1091 int order1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
1092 int order2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
1093
1094 /* Handle "." and ".." as special case and move them at the very first beginning. */
1095 if (order1==TO_DIR && order2==TO_DIR) {
1096 order1 = TypeOrderFromDirname(fd1->cFileName);
1097 order2 = TypeOrderFromDirname(fd2->cFileName);
1098 }
1099
1100 return order2==order1? 0: order1<order2? -1: 1;
1101 }
1102
1103
1104 static int compareName(const void* arg1, const void* arg2)
1105 {
1106 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
1107 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
1108
1109 int cmp = compareType(fd1, fd2);
1110 if (cmp)
1111 return cmp;
1112
1113 return lstrcmpi(fd1->cFileName, fd2->cFileName);
1114 }
1115
1116 static int compareExt(const void* arg1, const void* arg2)
1117 {
1118 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
1119 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
1120 const TCHAR *name1, *name2, *ext1, *ext2;
1121
1122 int cmp = compareType(fd1, fd2);
1123 if (cmp)
1124 return cmp;
1125
1126 name1 = fd1->cFileName;
1127 name2 = fd2->cFileName;
1128
1129 ext1 = _tcsrchr(name1, TEXT('.'));
1130 ext2 = _tcsrchr(name2, TEXT('.'));
1131
1132 if (ext1)
1133 ext1++;
1134 else
1135 ext1 = sEmpty;
1136
1137 if (ext2)
1138 ext2++;
1139 else
1140 ext2 = sEmpty;
1141
1142 cmp = lstrcmpi(ext1, ext2);
1143 if (cmp)
1144 return cmp;
1145
1146 return lstrcmpi(name1, name2);
1147 }
1148
1149 static int compareSize(const void* arg1, const void* arg2)
1150 {
1151 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
1152 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
1153
1154 int cmp = compareType(fd1, fd2);
1155 if (cmp)
1156 return cmp;
1157
1158 cmp = fd2->nFileSizeHigh - fd1->nFileSizeHigh;
1159
1160 if (cmp < 0)
1161 return -1;
1162 else if (cmp > 0)
1163 return 1;
1164
1165 cmp = fd2->nFileSizeLow - fd1->nFileSizeLow;
1166
1167 return cmp<0? -1: cmp>0? 1: 0;
1168 }
1169
1170 static int compareDate(const void* arg1, const void* arg2)
1171 {
1172 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
1173 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
1174
1175 int cmp = compareType(fd1, fd2);
1176 if (cmp)
1177 return cmp;
1178
1179 return CompareFileTime(&fd2->ftLastWriteTime, &fd1->ftLastWriteTime);
1180 }
1181
1182
1183 static int (*sortFunctions[])(const void* arg1, const void* arg2) = {
1184 compareName, /* SORT_NAME */
1185 compareExt, /* SORT_EXT */
1186 compareSize, /* SORT_SIZE */
1187 compareDate /* SORT_DATE */
1188 };
1189
1190
1191 static void SortDirectory(Entry* dir, SORT_ORDER sortOrder)
1192 {
1193 Entry* entry = dir->down;
1194 Entry** array, **p;
1195 int len;
1196
1197 len = 0;
1198 for(entry=dir->down; entry; entry=entry->next)
1199 len++;
1200
1201 if (len) {
1202 array = (Entry**) alloca(len*sizeof(Entry*));
1203
1204 p = array;
1205 for(entry=dir->down; entry; entry=entry->next)
1206 *p++ = entry;
1207
1208 /* call qsort with the appropriate compare function */
1209 qsort(array, len, sizeof(array[0]), sortFunctions[sortOrder]);
1210
1211 dir->down = array[0];
1212
1213 for(p=array; --len; p++)
1214 p[0]->next = p[1];
1215
1216 (*p)->next = 0;
1217 }
1218 }
1219
1220
1221 static void read_directory(Entry* dir, LPCTSTR path, SORT_ORDER sortOrder, HWND hwnd)
1222 {
1223 TCHAR buffer[MAX_PATH];
1224 Entry* entry;
1225 LPCTSTR s;
1226 PTSTR d;
1227
1228 #ifdef _SHELL_FOLDERS
1229 if (dir->etype == ET_SHELL)
1230 {
1231 read_directory_shell(dir, hwnd);
1232
1233 if (Globals.prescan_node) {
1234 s = path;
1235 d = buffer;
1236
1237 while(*s)
1238 *d++ = *s++;
1239
1240 *d++ = TEXT('\\');
1241
1242 for(entry=dir->down; entry; entry=entry->next)
1243 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1244 read_directory_shell(entry, hwnd);
1245 SortDirectory(entry, sortOrder);
1246 }
1247 }
1248 }
1249 else
1250 #endif
1251 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
1252 if (dir->etype == ET_UNIX)
1253 {
1254 read_directory_unix(dir, path);
1255
1256 if (Globals.prescan_node) {
1257 s = path;
1258 d = buffer;
1259
1260 while(*s)
1261 *d++ = *s++;
1262
1263 *d++ = TEXT('/');
1264
1265 for(entry=dir->down; entry; entry=entry->next)
1266 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1267 lstrcpy(d, entry->data.cFileName);
1268 read_directory_unix(entry, buffer);
1269 SortDirectory(entry, sortOrder);
1270 }
1271 }
1272 }
1273 else
1274 #endif
1275 {
1276 read_directory_win(dir, path);
1277
1278 if (Globals.prescan_node) {
1279 s = path;
1280 d = buffer;
1281
1282 while(*s)
1283 *d++ = *s++;
1284
1285 *d++ = TEXT('\\');
1286
1287 for(entry=dir->down; entry; entry=entry->next)
1288 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1289 lstrcpy(d, entry->data.cFileName);
1290 read_directory_win(entry, buffer);
1291 SortDirectory(entry, sortOrder);
1292 }
1293 }
1294 }
1295
1296 SortDirectory(dir, sortOrder);
1297 }
1298
1299
1300 static ChildWnd* alloc_child_window(LPCTSTR path, LPITEMIDLIST pidl, HWND hwnd)
1301 {
1302 const static TCHAR sBackslash[] = {'\\', '\0'};
1303 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
1304 const static TCHAR sSlash[] = {'/', '\0'};
1305 #endif
1306
1307 TCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
1308 TCHAR b1[BUFFER_LEN];
1309
1310 ChildWnd* child = (ChildWnd*) malloc(sizeof(ChildWnd));
1311 Root* root = &child->root;
1312 Entry* entry;
1313
1314 memset(child, 0, sizeof(ChildWnd));
1315
1316 child->left.treePane = TRUE;
1317 child->left.visible_cols = 0;
1318
1319 child->right.treePane = FALSE;
1320 #ifndef _NO_EXTENSIONS
1321 child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_INDEX|COL_LINKS;
1322 #else
1323 child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES;
1324 #endif
1325
1326 child->pos.length = sizeof(WINDOWPLACEMENT);
1327 child->pos.flags = 0;
1328 child->pos.showCmd = SW_SHOWNORMAL;
1329 child->pos.rcNormalPosition.left = CW_USEDEFAULT;
1330 child->pos.rcNormalPosition.top = CW_USEDEFAULT;
1331 child->pos.rcNormalPosition.right = CW_USEDEFAULT;
1332 child->pos.rcNormalPosition.bottom = CW_USEDEFAULT;
1333
1334 child->focus_pane = 0;
1335 child->split_pos = DEFAULT_SPLIT_POS;
1336 child->sortOrder = SORT_NAME;
1337 child->header_wdths_ok = FALSE;
1338
1339 if (path)
1340 {
1341 lstrcpy(child->path, path);
1342
1343 _tsplitpath(path, drv, dir, name, ext);
1344 }
1345
1346 root->entry.level = 0;
1347
1348 #ifdef _SHELL_FOLDERS
1349 if (pidl)
1350 {
1351 root->drive_type = DRIVE_UNKNOWN;
1352 drv[0] = '\\';
1353 drv[1] = '\0';
1354 load_string(root->volname, IDS_DESKTOP);
1355 root->fs_flags = 0;
1356 load_string(root->fs, IDS_SHELL);
1357
1358 entry = read_tree_shell(root, pidl, child->sortOrder, hwnd);
1359 }
1360 else
1361 #endif
1362 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
1363 if (*path == '/')
1364 {
1365 root->drive_type = GetDriveType(path);
1366
1367 lstrcat(drv, sSlash);
1368 load_string(root->volname, IDS_ROOT_FS);
1369 root->fs_flags = 0;
1370 load_string(root->fs, IDS_UNIXFS);
1371
1372 lstrcpy(root->path, sSlash);
1373 entry = read_tree_unix(root, path, child->sortOrder, hwnd);
1374 }
1375 else
1376 #endif
1377 {
1378 root->drive_type = GetDriveType(path);
1379
1380 lstrcat(drv, sBackslash);
1381 GetVolumeInformation(drv, root->volname, _MAX_FNAME, 0, 0, &root->fs_flags, root->fs, _MAX_DIR);
1382
1383 lstrcpy(root->path, drv);
1384 entry = read_tree_win(root, path, child->sortOrder, hwnd);
1385 }
1386
1387 #ifdef _SHELL_FOLDERS
1388 if (root->entry.etype == ET_SHELL)
1389 load_string(root->entry.data.cFileName, IDS_DESKTOP);
1390 else
1391 #endif
1392 wsprintf(root->entry.data.cFileName, RS(b1,IDS_TITLEFMT), drv, root->fs);
1393
1394 root->entry.data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1395
1396 child->left.root = &root->entry;
1397 child->right.root = NULL;
1398
1399 set_curdir(child, entry, hwnd);
1400
1401 return child;
1402 }
1403
1404
1405 /* free all memory associated with a child window */
1406 static void free_child_window(ChildWnd* child)
1407 {
1408 free_entries(&child->root.entry);
1409 free(child);
1410 }
1411
1412
1413 /* get full path of specified directory entry */
1414 static void get_path(Entry* dir, PTSTR path)
1415 {
1416 Entry* entry;
1417 int len = 0;
1418 int level = 0;
1419
1420 #ifdef _SHELL_FOLDERS
1421 if (dir->etype == ET_SHELL)
1422 {
1423 SFGAOF attribs;
1424 HRESULT hr = S_OK;
1425
1426 path[0] = TEXT('\0');
1427
1428 attribs = 0;
1429
1430 if (dir->folder)
1431 hr = (*dir->folder->lpVtbl->GetAttributesOf)(dir->folder, 1, (LPCITEMIDLIST*)&dir->pidl, &attribs);
1432
1433 if (SUCCEEDED(hr) && (attribs&SFGAO_FILESYSTEM)) {
1434 IShellFolder* parent = dir->up? dir->up->folder: Globals.iDesktop;
1435
1436 hr = path_from_pidl(parent, dir->pidl, path, MAX_PATH);
1437 }
1438 }
1439 else
1440 #endif
1441 {
1442 for(entry=dir; entry; level++) {
1443 LPCTSTR name;
1444 int l;
1445
1446 {
1447 LPCTSTR s;
1448 name = entry->data.cFileName;
1449 s = name;
1450
1451 for(l=0; *s && *s!=TEXT('/') && *s!=TEXT('\\'); s++)
1452 l++;
1453 }
1454
1455 if (entry->up) {
1456 if (l > 0) {
1457 memmove(path+l+1, path, len*sizeof(TCHAR));
1458 memcpy(path+1, name, l*sizeof(TCHAR));
1459 len += l+1;
1460
1461 #ifndef _NO_EXTENSIONS
1462 if (entry->etype == ET_UNIX)
1463 path[0] = TEXT('/');
1464 else
1465 #endif
1466 path[0] = TEXT('\\');
1467 }
1468
1469 entry = entry->up;
1470 } else {
1471 memmove(path+l, path, len*sizeof(TCHAR));
1472 memcpy(path, name, l*sizeof(TCHAR));
1473 len += l;
1474 break;
1475 }
1476 }
1477
1478 if (!level) {
1479 #ifndef _NO_EXTENSIONS
1480 if (entry->etype == ET_UNIX)
1481 path[len++] = TEXT('/');
1482 else
1483 #endif
1484 path[len++] = TEXT('\\');
1485 }
1486
1487 path[len] = TEXT('\0');
1488 }
1489 }
1490
1491
1492 static void resize_frame_rect(HWND hwnd, PRECT prect)
1493 {
1494 int new_top;
1495 RECT rt;
1496
1497 if (IsWindowVisible(Globals.htoolbar)) {
1498 SendMessage(Globals.htoolbar, WM_SIZE, 0, 0);
1499 GetClientRect(Globals.htoolbar, &rt);
1500 prect->top = rt.bottom+3;
1501 prect->bottom -= rt.bottom+3;
1502 }
1503
1504 if (IsWindowVisible(Globals.hdrivebar)) {
1505 SendMessage(Globals.hdrivebar, WM_SIZE, 0, 0);
1506 GetClientRect(Globals.hdrivebar, &rt);
1507 new_top = --prect->top + rt.bottom+3;
1508 MoveWindow(Globals.hdrivebar, 0, prect->top, rt.right, new_top, TRUE);
1509 prect->top = new_top;
1510 prect->bottom -= rt.bottom+2;
1511 }
1512
1513 if (IsWindowVisible(Globals.hstatusbar)) {
1514 int parts[] = {300, 500};
1515
1516 SendMessage(Globals.hstatusbar, WM_SIZE, 0, 0);
1517 SendMessage(Globals.hstatusbar, SB_SETPARTS, 2, (LPARAM)&parts);
1518 GetClientRect(Globals.hstatusbar, &rt);
1519 prect->bottom -= rt.bottom;
1520 }
1521
1522 MoveWindow(Globals.hmdiclient, prect->left-1,prect->top-1,prect->right+2,prect->bottom+1, TRUE);
1523 }
1524
1525 static void resize_frame(HWND hwnd, int cx, int cy)
1526 {
1527 RECT rect;
1528
1529 rect.left = 0;
1530 rect.top = 0;
1531 rect.right = cx;
1532 rect.bottom = cy;
1533
1534 resize_frame_rect(hwnd, &rect);
1535 }
1536
1537 static void resize_frame_client(HWND hwnd)
1538 {
1539 RECT rect;
1540
1541 GetClientRect(hwnd, &rect);
1542
1543 resize_frame_rect(hwnd, &rect);
1544 }
1545
1546
1547 static HHOOK hcbthook;
1548 static ChildWnd* newchild = NULL;
1549
1550 LRESULT CALLBACK CBTProc(int code, WPARAM wparam, LPARAM lparam)
1551 {
1552 if (code==HCBT_CREATEWND && newchild) {
1553 ChildWnd* child = newchild;
1554 newchild = NULL;
1555
1556 child->hwnd = (HWND) wparam;
1557 SetWindowLong(child->hwnd, GWL_USERDATA, (LPARAM)child);
1558 }
1559
1560 return CallNextHookEx(hcbthook, code, wparam, lparam);
1561 }
1562
1563 static HWND create_child_window(ChildWnd* child)
1564 {
1565 MDICREATESTRUCT mcs;
1566 int idx;
1567
1568 mcs.szClass = sWINEFILETREE;
1569 mcs.szTitle = (LPTSTR)child->path;
1570 mcs.hOwner = Globals.hInstance;
1571 mcs.x = child->pos.rcNormalPosition.left;
1572 mcs.y = child->pos.rcNormalPosition.top;
1573 mcs.cx = child->pos.rcNormalPosition.right-child->pos.rcNormalPosition.left;
1574 mcs.cy = child->pos.rcNormalPosition.bottom-child->pos.rcNormalPosition.top;
1575 mcs.style = 0;
1576 mcs.lParam = 0;
1577
1578 hcbthook = SetWindowsHookEx(WH_CBT, CBTProc, 0, GetCurrentThreadId());
1579
1580 newchild = child;
1581 child->hwnd = (HWND) SendMessage(Globals.hmdiclient, WM_MDICREATE, 0, (LPARAM)&mcs);
1582 if (!child->hwnd) {
1583 UnhookWindowsHookEx(hcbthook);
1584 return 0;
1585 }
1586
1587 UnhookWindowsHookEx(hcbthook);
1588
1589 ListBox_SetItemHeight(child->left.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
1590 ListBox_SetItemHeight(child->right.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
1591 idx = ListBox_FindItemData(child->left.hwnd, ListBox_GetCurSel(child->left.hwnd), child->left.cur);
1592 ListBox_SetCurSel(child->left.hwnd, idx);
1593
1594 return child->hwnd;
1595 }
1596
1597
1598 struct ExecuteDialog {
1599 TCHAR cmd[MAX_PATH];
1600 int cmdshow;
1601 };
1602
1603
1604 static INT_PTR CALLBACK ExecuteDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1605 {
1606 static struct ExecuteDialog* dlg;
1607
1608 switch(nmsg) {
1609 case WM_INITDIALOG:
1610 dlg = (struct ExecuteDialog*) lparam;
1611 return 1;
1612
1613 case WM_COMMAND: {
1614 int id = (int)wparam;
1615
1616 if (id == IDOK) {
1617 GetWindowText(GetDlgItem(hwnd, 201), dlg->cmd, MAX_PATH);
1618 dlg->cmdshow = Button_GetState(GetDlgItem(hwnd,214))&BST_CHECKED?
1619 SW_SHOWMINIMIZED: SW_SHOWNORMAL;
1620 EndDialog(hwnd, id);
1621 } else if (id == IDCANCEL)
1622 EndDialog(hwnd, id);
1623
1624 return 1;}
1625 }
1626
1627 return 0;
1628 }
1629
1630 static INT_PTR CALLBACK DestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1631 {
1632 TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
1633
1634 switch(nmsg) {
1635 case WM_INITDIALOG:
1636 SetWindowLong(hwnd, GWL_USERDATA, lparam);
1637 return 1;
1638
1639 case WM_COMMAND: {
1640 int id = (int)wparam;
1641
1642 switch(id) {
1643 case IDOK: {
1644 LPTSTR dest = (LPTSTR) GetWindowLong(hwnd, GWL_USERDATA);
1645 GetWindowText(GetDlgItem(hwnd, 201), dest, MAX_PATH);
1646 EndDialog(hwnd, id);
1647 break;}
1648
1649 case IDCANCEL:
1650 EndDialog(hwnd, id);
1651 break;
1652
1653 case 254:
1654 MessageBox(hwnd, RS(b1,IDS_NO_IMPL), RS(b2,IDS_WINEFILE), MB_OK);
1655 break;
1656 }
1657
1658 return 1;
1659 }
1660 }
1661
1662 return 0;
1663 }
1664
1665
1666 #ifndef _NO_EXTENSIONS
1667
1668 static struct FullScreenParameters {
1669 BOOL mode;
1670 RECT orgPos;
1671 BOOL wasZoomed;
1672 } g_fullscreen = {
1673 FALSE, /* mode */
1674 {0, 0, 0, 0},
1675 FALSE
1676 };
1677
1678 void frame_get_clientspace(HWND hwnd, PRECT prect)
1679 {
1680 RECT rt;
1681
1682 if (!IsIconic(hwnd))
1683 GetClientRect(hwnd, prect);
1684 else {
1685 WINDOWPLACEMENT wp;
1686
1687 GetWindowPlacement(hwnd, &wp);
1688
1689 prect->left = prect->top = 0;
1690 prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left-
1691 2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE));
1692 prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top-
1693 2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))-
1694 GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE);
1695 }
1696
1697 if (IsWindowVisible(Globals.htoolbar)) {
1698 GetClientRect(Globals.htoolbar, &rt);
1699 prect->top += rt.bottom+2;
1700 }
1701
1702 if (IsWindowVisible(Globals.hdrivebar)) {
1703 GetClientRect(Globals.hdrivebar, &rt);
1704 prect->top += rt.bottom+2;
1705 }
1706
1707 if (IsWindowVisible(Globals.hstatusbar)) {
1708 GetClientRect(Globals.hstatusbar, &rt);
1709 prect->bottom -= rt.bottom;
1710 }
1711 }
1712
1713 static BOOL toggle_fullscreen(HWND hwnd)
1714 {
1715 RECT rt;
1716
1717 if ((g_fullscreen.mode=!g_fullscreen.mode)) {
1718 GetWindowRect(hwnd, &g_fullscreen.orgPos);
1719 g_fullscreen.wasZoomed = IsZoomed(hwnd);
1720
1721 Frame_CalcFrameClient(hwnd, &rt);
1722 ClientToScreen(hwnd, (LPPOINT)&rt.left);
1723 ClientToScreen(hwnd, (LPPOINT)&rt.right);
1724
1725 rt.left = g_fullscreen.orgPos.left-rt.left;
1726 rt.top = g_fullscreen.orgPos.top-rt.top;
1727 rt.right = GetSystemMetrics(SM_CXSCREEN)+g_fullscreen.orgPos.right-rt.right;
1728 rt.bottom = GetSystemMetrics(SM_CYSCREEN)+g_fullscreen.orgPos.bottom-rt.bottom;
1729
1730 MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
1731 } else {
1732 MoveWindow(hwnd, g_fullscreen.orgPos.left, g_fullscreen.orgPos.top,
1733 g_fullscreen.orgPos.right-g_fullscreen.orgPos.left,
1734 g_fullscreen.orgPos.bottom-g_fullscreen.orgPos.top, TRUE);
1735
1736 if (g_fullscreen.wasZoomed)
1737 ShowWindow(hwnd, WS_MAXIMIZE);
1738 }
1739
1740 return g_fullscreen.mode;
1741 }
1742
1743 static void fullscreen_move(HWND hwnd)
1744 {
1745 RECT rt, pos;
1746 GetWindowRect(hwnd, &pos);
1747
1748 Frame_CalcFrameClient(hwnd, &rt);
1749 ClientToScreen(hwnd, (LPPOINT)&rt.left);
1750 ClientToScreen(hwnd, (LPPOINT)&rt.right);
1751
1752 rt.left = pos.left-rt.left;
1753 rt.top = pos.top-rt.top;
1754 rt.right = GetSystemMetrics(SM_CXSCREEN)+pos.right-rt.right;
1755 rt.bottom = GetSystemMetrics(SM_CYSCREEN)+pos.bottom-rt.bottom;
1756
1757 MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
1758 }
1759
1760 #endif
1761
1762
1763 static void toggle_child(HWND hwnd, UINT cmd, HWND hchild)
1764 {
1765 BOOL vis = IsWindowVisible(hchild);
1766
1767 CheckMenuItem(Globals.hMenuOptions, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
1768
1769 ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
1770
1771 #ifndef _NO_EXTENSIONS
1772 if (g_fullscreen.mode)
1773 fullscreen_move(hwnd);
1774 #endif
1775
1776 resize_frame_client(hwnd);
1777 }
1778
1779 BOOL activate_drive_window(LPCTSTR path)
1780 {
1781 TCHAR drv1[_MAX_DRIVE], drv2[_MAX_DRIVE];
1782 HWND child_wnd;
1783
1784 _tsplitpath(path, drv1, 0, 0, 0);
1785
1786 /* search for a already open window for the same drive */
1787 for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
1788 ChildWnd* child = (ChildWnd*) GetWindowLong(child_wnd, GWL_USERDATA);
1789
1790 if (child) {
1791 _tsplitpath(child->root.path, drv2, 0, 0, 0);
1792
1793 if (!lstrcmpi(drv2, drv1)) {
1794 SendMessage(Globals.hmdiclient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
1795
1796 if (IsMinimized(child_wnd))
1797 ShowWindow(child_wnd, SW_SHOWNORMAL);
1798
1799 return TRUE;
1800 }
1801 }
1802 }
1803
1804 return FALSE;
1805 }
1806
1807 BOOL activate_fs_window(LPCTSTR filesys)
1808 {
1809 HWND child_wnd;
1810
1811 /* search for a already open window of the given file system name */
1812 for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
1813 ChildWnd* child = (ChildWnd*) GetWindowLong(child_wnd, GWL_USERDATA);
1814
1815 if (child) {
1816 if (!lstrcmpi(child->root.fs, filesys)) {
1817 SendMessage(Globals.hmdiclient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
1818
1819 if (IsMinimized(child_wnd))
1820 ShowWindow(child_wnd, SW_SHOWNORMAL);
1821
1822 return TRUE;
1823 }
1824 }
1825 }
1826
1827 return FALSE;
1828 }
1829
1830 LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1831 {
1832 TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
1833
1834 switch(nmsg) {
1835 case WM_CLOSE:
1836 DestroyWindow(hwnd);
1837
1838 /* clear handle variables */
1839 Globals.hMenuFrame = 0;
1840 Globals.hMenuView = 0;
1841 Globals.hMenuOptions = 0;
1842 Globals.hMainWnd = 0;
1843 Globals.hmdiclient = 0;
1844 Globals.hdrivebar = 0;
1845 break;
1846
1847 case WM_DESTROY:
1848 /* don't exit desktop when closing file manager window */
1849 if (!Globals.hwndParent)
1850 PostQuitMessage(0);
1851 break;
1852
1853 case WM_COMMAND: {
1854 UINT cmd = LOWORD(wparam);
1855 HWND hwndClient = (HWND) SendMessage(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
1856
1857 if (SendMessage(hwndClient, WM_DISPATCH_COMMAND, wparam, lparam))
1858 break;
1859
1860 if (cmd>=ID_DRIVE_FIRST && cmd<=ID_DRIVE_FIRST+0xFF) {
1861 TCHAR drv[_MAX_DRIVE], path[MAX_PATH];
1862 ChildWnd* child;
1863 LPCTSTR root = Globals.drives;
1864 int i;
1865
1866 for(i=cmd-ID_DRIVE_FIRST; i--; root++)
1867 while(*root)
1868 root++;
1869
1870 if (activate_drive_window(root))
1871 return 0;
1872
1873 _tsplitpath(root, drv, 0, 0, 0);
1874
1875 if (!SetCurrentDirectory(drv)) {
1876 display_error(hwnd, GetLastError());
1877 return 0;
1878 }
1879
1880 GetCurrentDirectory(MAX_PATH, path); /*TODO: store last directory per drive */
1881 child = alloc_child_window(path, NULL, hwnd);
1882
1883 if (!create_child_window(child))
1884 free(child);
1885 } else switch(cmd) {
1886 case ID_FILE_EXIT:
1887 SendMessage(hwnd, WM_CLOSE, 0, 0);
1888 break;
1889
1890 case ID_WINDOW_NEW: {
1891 TCHAR path[MAX_PATH];
1892 ChildWnd* child;
1893
1894 GetCurrentDirectory(MAX_PATH, path);
1895 child = alloc_child_window(path, NULL, hwnd);
1896
1897 if (!create_child_window(child))
1898 free(child);
1899 break;}
1900
1901 case ID_WINDOW_CASCADE:
1902 SendMessage(Globals.hmdiclient, WM_MDICASCADE, 0, 0);
1903 break;
1904
1905 case ID_WINDOW_TILE_HORZ:
1906 SendMessage(Globals.hmdiclient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
1907 break;
1908
1909 case ID_WINDOW_TILE_VERT:
1910 SendMessage(Globals.hmdiclient, WM_MDITILE, MDITILE_VERTICAL, 0);
1911 break;
1912
1913 case ID_WINDOW_ARRANGE:
1914 SendMessage(Globals.hmdiclient, WM_MDIICONARRANGE, 0, 0);
1915 break;
1916
1917 case ID_SELECT_FONT: {
1918 TCHAR dlg_name[BUFFER_LEN], dlg_info[BUFFER_LEN];
1919 CHOOSEFONT chFont;
1920 LOGFONT lFont;
1921
1922 HDC hdc = GetDC(hwnd);
1923 chFont.lStructSize = sizeof(CHOOSEFONT);
1924 chFont.hwndOwner = hwnd;
1925 chFont.hDC = NULL;
1926 chFont.lpLogFont = &lFont;
1927 chFont.Flags = CF_SCREENFONTS | CF_FORCEFONTEXIST | CF_LIMITSIZE | CF_NOSCRIPTSEL;
1928 chFont.rgbColors = RGB(0,0,0);
1929 chFont.lCustData = 0;
1930 chFont.lpfnHook = NULL;
1931 chFont.lpTemplateName = NULL;
1932 chFont.hInstance = Globals.hInstance;
1933 chFont.lpszStyle = NULL;
1934 chFont.nFontType = SIMULATED_FONTTYPE;
1935 chFont.nSizeMin = 0;
1936 chFont.nSizeMax = 24;
1937
1938 if (ChooseFont(&chFont)) {
1939 HWND childWnd;
1940
1941 Globals.hfont = CreateFontIndirect(&lFont);
1942 SelectFont(hdc, Globals.hfont);
1943 GetTextExtentPoint32(hdc, sSpace, 1, &Globals.spaceSize);
1944
1945 /* change font in all open child windows */
1946 for(childWnd=GetWindow(Globals.hmdiclient,GW_CHILD); childWnd; childWnd=GetNextWindow(childWnd,GW_HWNDNEXT)) {
1947 ChildWnd* child = (ChildWnd*) GetWindowLong(childWnd, GWL_USERDATA);
1948 SetWindowFont(child->left.hwnd, Globals.hfont, TRUE);
1949 SetWindowFont(child->right.hwnd, Globals.hfont, TRUE);
1950 ListBox_SetItemHeight(child->left.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
1951 ListBox_SetItemHeight(child->right.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
1952 InvalidateRect(child->left.hwnd, NULL, TRUE);
1953 InvalidateRect(child->right.hwnd, NULL, TRUE);
1954 }
1955 }
1956 else if (CommDlgExtendedError()) {
1957 LoadString(Globals.hInstance, IDS_FONT_SEL_DLG_NAME, dlg_name, BUFFER_LEN);
1958 LoadString(Globals.hInstance, IDS_FONT_SEL_ERROR, dlg_info, BUFFER_LEN);
1959 MessageBox(hwnd, dlg_info, dlg_name, MB_OK);
1960 }
1961
1962 ReleaseDC(hwnd, hdc);
1963 break;
1964 }
1965
1966 case ID_VIEW_TOOL_BAR:
1967 toggle_child(hwnd, cmd, Globals.htoolbar);
1968 break;
1969
1970 case ID_VIEW_DRIVE_BAR:
1971 toggle_child(hwnd, cmd, Globals.hdrivebar);
1972 break;
1973
1974 case ID_VIEW_STATUSBAR:
1975 toggle_child(hwnd, cmd, Globals.hstatusbar);
1976 break;
1977
1978 case ID_EXECUTE: {
1979 struct ExecuteDialog dlg;
1980
1981 memset(&dlg, 0, sizeof(struct ExecuteDialog));
1982
1983 if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_EXECUTE), hwnd, ExecuteDialogDlgProc, (LPARAM)&dlg) == IDOK) {
1984 HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, dlg.cmd/*file*/, NULL/*parameters*/, NULL/*dir*/, dlg.cmdshow);
1985
1986 if ((int)hinst <= 32)
1987 display_error(hwnd, GetLastError());
1988 }
1989 break;}
1990
1991 case ID_HELP:
1992 WinHelp(hwnd, RS(b1,IDS_WINEFILE), HELP_INDEX, 0);
1993 break;
1994
1995 #ifndef _NO_EXTENSIONS
1996 case ID_VIEW_FULLSCREEN:
1997 CheckMenuItem(Globals.hMenuOptions, cmd, toggle_fullscreen(hwnd)?MF_CHECKED:0);
1998 break;
1999
2000 #ifdef __WINE__
2001 case ID_DRIVE_UNIX_FS: {
2002 TCHAR path[MAX_PATH];
2003 #ifdef UNICODE
2004 char cpath[MAX_PATH];
2005 #endif
2006 ChildWnd* child;
2007
2008 if (activate_fs_window(RS(b1,IDS_UNIXFS)))
2009 break;
2010
2011
2012 #ifdef UNICODE
2013 call_getcwd(cpath, MAX_PATH);
2014 MultiByteToWideChar(CP_UNIXCP, 0, cpath, -1, path, MAX_PATH);
2015 #else
2016 call_getcwd(path, MAX_PATH);
2017 #endif
2018 child = alloc_child_window(path, NULL, hwnd);
2019
2020 if (!create_child_window(child))
2021 free(child);
2022 break;}
2023 #endif
2024
2025 #ifdef _SHELL_FOLDERS
2026 case ID_DRIVE_SHELL_NS: {
2027 TCHAR path[MAX_PATH];
2028 ChildWnd* child;
2029
2030 if (activate_fs_window(RS(b1,IDS_SHELL)))
2031 break;
2032
2033 GetCurrentDirectory(MAX_PATH, path);
2034 child = alloc_child_window(path, get_path_pidl(path,hwnd), hwnd);
2035
2036 if (!create_child_window(child))
2037 free(child);
2038 break;}
2039 #endif
2040 #endif
2041
2042 /*TODO: There are even more menu items! */
2043
2044 #ifndef _NO_EXTENSIONS
2045 #ifdef __WINE__
2046 case ID_LICENSE:
2047 WineLicense(Globals.hMainWnd);
2048 break;
2049
2050 case ID_NO_WARRANTY:
2051 WineWarranty(Globals.hMainWnd);
2052 break;
2053 #endif
2054
2055 case ID_ABOUT_WINE:
2056 ShellAbout(hwnd, RS(b2,IDS_WINE), RS(b1,IDS_WINEFILE), 0);
2057 break;
2058
2059 case ID_ABOUT:
2060 ShellAbout(hwnd, RS(b1,IDS_WINEFILE), NULL, 0);
2061 break;
2062 #endif /* _NO_EXTENSIONS */
2063
2064 default:
2065 /*TODO: if (wParam >= PM_FIRST_LANGUAGE && wParam <= PM_LAST_LANGUAGE)
2066 STRING_SelectLanguageByNumber(wParam - PM_FIRST_LANGUAGE);
2067 else */if ((cmd<IDW_FIRST_CHILD || cmd>=IDW_FIRST_CHILD+0x100) &&
2068 (cmd<SC_SIZE || cmd>SC_RESTORE))
2069 MessageBox(hwnd, RS(b2,IDS_NO_IMPL), RS(b1,IDS_WINEFILE), MB_OK);
2070
2071 return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
2072 }
2073 break;}
2074
2075 case WM_SIZE:
2076 resize_frame(hwnd, LOWORD(lparam), HIWORD(lparam));
2077 break; /* do not pass message to DefFrameProc */
2078
2079 #ifndef _NO_EXTENSIONS
2080 case WM_GETMINMAXINFO: {
2081 LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
2082
2083 lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
2084 lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
2085 break;}
2086
2087 case FRM_CALC_CLIENT:
2088 frame_get_clientspace(hwnd, (PRECT)lparam);
2089 return TRUE;
2090 #endif /* _NO_EXTENSIONS */
2091
2092 default:
2093 return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
2094 }
2095
2096 return 0;
2097 }
2098
2099
2100 static TCHAR g_pos_names[COLUMNS][20] = {
2101 {'\0'} /* symbol */
2102 };
2103
2104 static const int g_pos_align[] = {
2105 0,
2106 HDF_LEFT, /* Name */
2107 HDF_RIGHT, /* Size */
2108 HDF_LEFT, /* CDate */
2109 #ifndef _NO_EXTENSIONS
2110 HDF_LEFT, /* ADate */
2111 HDF_LEFT, /* MDate */
2112 HDF_LEFT, /* Index */
2113 HDF_CENTER, /* Links */
2114 #endif
2115 HDF_CENTER, /* Attributes */
2116 #ifndef _NO_EXTENSIONS
2117 HDF_LEFT /* Security */
2118 #endif
2119 };
2120
2121 static void resize_tree(ChildWnd* child, int cx, int cy)
2122 {
2123 HDWP hdwp = BeginDeferWindowPos(4);
2124 RECT rt;
2125
2126 rt.left = 0;
2127 rt.top = 0;
2128 rt.right = cx;
2129 rt.bottom = cy;
2130
2131 cx = child->split_pos + SPLIT_WIDTH/2;
2132
2133 #ifndef _NO_EXTENSIONS
2134 {
2135 WINDOWPOS wp;
2136 HD_LAYOUT hdl;
2137
2138 hdl.prc = &rt;
2139 hdl.pwpos = &wp;
2140
2141 Header_Layout(child->left.hwndHeader, &hdl);
2142
2143 DeferWindowPos(hdwp, child->left.hwndHeader, wp.hwndInsertAfter,
2144 wp.x-1, wp.y, child->split_pos-SPLIT_WIDTH/2+1, wp.cy, wp.flags);
2145 DeferWindowPos(hdwp, child->right.hwndHeader, wp.hwndInsertAfter,
2146 rt.left+cx+1, wp.y, wp.cx-cx+2, wp.cy, wp.flags);
2147 }
2148 #endif /* _NO_EXTENSIONS */
2149
2150 DeferWindowPos(hdwp, child->left.hwnd, 0, rt.left, rt.top, child->split_pos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
2151 DeferWindowPos(hdwp, child->right.hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
2152
2153 EndDeferWindowPos(hdwp);
2154 }
2155
2156
2157 #ifndef _NO_EXTENSIONS
2158
2159 static HWND create_header(HWND parent, Pane* pane, int id)
2160 {
2161 HD_ITEM hdi;
2162 int idx;
2163
2164 HWND hwnd = CreateWindow(WC_HEADER, 0, WS_CHILD|WS_VISIBLE|HDS_HORZ/*TODO: |HDS_BUTTONS + sort orders*/,
2165 0, 0, 0, 0, parent, (HMENU)id, Globals.hInstance, 0);
2166 if (!hwnd)
2167 return 0;
2168
2169 SetWindowFont(hwnd, GetStockObject(DEFAULT_GUI_FONT), FALSE);
2170
2171 hdi.mask = HDI_TEXT|HDI_WIDTH|HDI_FORMAT;
2172
2173 for(idx=0; idx<COLUMNS; idx++) {
2174 hdi.pszText = g_pos_names[idx];
2175 hdi.fmt = HDF_STRING | g_pos_align[idx];
2176 hdi.cxy = pane->widths[idx];
2177 Header_InsertItem(hwnd, idx, &hdi);
2178 }
2179
2180 return hwnd;
2181 }
2182
2183 #endif /* _NO_EXTENSIONS */
2184
2185
2186 static void init_output(HWND hwnd)
2187 {
2188 const static TCHAR s1000[] = {'1','0','0','0','\0'};
2189
2190 TCHAR b[16];
2191 HFONT old_font;
2192 HDC hdc = GetDC(hwnd);
2193
2194 if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, s1000, 0, b, 16) > 4)
2195 Globals.num_sep = b[1];
2196 else
2197 Globals.num_sep = TEXT('.');
2198
2199 old_font = SelectFont(hdc, Globals.hfont);
2200 GetTextExtentPoint32(hdc, sSpace, 1, &Globals.spaceSize);
2201 SelectFont(hdc, old_font);
2202 ReleaseDC(hwnd, hdc);
2203 }
2204
2205 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol);
2206
2207
2208 /* calculate prefered width for all visible columns */
2209
2210 static BOOL calc_widths(Pane* pane, BOOL anyway)
2211 {
2212 int col, x, cx, spc=3*Globals.spaceSize.cx;
2213 int entries = ListBox_GetCount(pane->hwnd);
2214 int orgWidths[COLUMNS];
2215 int orgPositions[COLUMNS+1];
2216 HFONT hfontOld;
2217 HDC hdc;
2218 int cnt;
2219
2220 if (!anyway) {
2221 memcpy(orgWidths, pane->widths, sizeof(orgWidths));
2222 memcpy(orgPositions, pane->positions, sizeof(orgPositions));
2223 }
2224
2225 for(col=0; col<COLUMNS; col++)
2226 pane->widths[col] = 0;
2227
2228 hdc = GetDC(pane->hwnd);
2229 hfontOld = SelectFont(hdc, Globals.hfont);
2230
2231 for(cnt=0; cnt<entries; cnt++) {
2232 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, cnt);
2233
2234 DRAWITEMSTRUCT dis;
2235
2236 dis.CtlType = 0;
2237 dis.CtlID = 0;
2238 dis.itemID = 0;
2239 dis.itemAction = 0;
2240 dis.itemState = 0;
2241 dis.hwndItem = pane->hwnd;
2242 dis.hDC = hdc;
2243 dis.rcItem.left = 0;
2244 dis.rcItem.top = 0;
2245 dis.rcItem.right = 0;
2246 dis.rcItem.bottom = 0;
2247 /*dis.itemData = 0; */
2248
2249 draw_item(pane, &dis, entry, COLUMNS);
2250 }
2251
2252 SelectObject(hdc, hfontOld);
2253 ReleaseDC(pane->hwnd, hdc);
2254
2255 x = 0;
2256 for(col=0; col<COLUMNS; col++) {
2257 pane->positions[col] = x;
2258 cx = pane->widths[col];
2259
2260 if (cx) {
2261 cx += spc;
2262
2263 if (cx < IMAGE_WIDTH)
2264 cx = IMAGE_WIDTH;
2265
2266 pane->widths[col] = cx;
2267 }
2268
2269 x += cx;
2270 }
2271
2272 pane->positions[COLUMNS] = x;
2273
2274 ListBox_SetHorizontalExtent(pane->hwnd, x);
2275
2276 /* no change? */
2277 if (!memcmp(orgWidths, pane->widths, sizeof(orgWidths)))
2278 return FALSE;
2279
2280 /* don't move, if only collapsing an entry */
2281 if (!anyway && pane->widths[0]<orgWidths[0] &&
2282 !memcmp(orgWidths+1, pane->widths+1, sizeof(orgWidths)-sizeof(int))) {
2283 pane->widths[0] = orgWidths[0];
2284 memcpy(pane->positions, orgPositions, sizeof(orgPositions));
2285
2286 return FALSE;
2287 }
2288
2289 InvalidateRect(pane->hwnd, 0, TRUE);
2290
2291 return TRUE;
2292 }
2293
2294
2295 /* calculate one prefered column width */
2296
2297 static void calc_single_width(Pane* pane, int col)
2298 {
2299 HFONT hfontOld;
2300 int x, cx;
2301 int entries = ListBox_GetCount(pane->hwnd);
2302 int cnt;
2303 HDC hdc;
2304
2305 pane->widths[col] = 0;
2306
2307 hdc = GetDC(pane->hwnd);
2308 hfontOld = SelectFont(hdc, Globals.hfont);
2309
2310 for(cnt=0; cnt<entries; cnt++) {
2311 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, cnt);
2312 DRAWITEMSTRUCT dis;
2313
2314 dis.CtlType = 0;
2315 dis.CtlID = 0;
2316 dis.itemID = 0;
2317 dis.itemAction = 0;
2318 dis.itemState = 0;
2319 dis.hwndItem = pane->hwnd;
2320 dis.hDC = hdc;
2321 dis.rcItem.left = 0;
2322 dis.rcItem.top = 0;
2323 dis.rcItem.right = 0;
2324 dis.rcItem.bottom = 0;
2325 /*dis.itemData = 0; */
2326
2327 draw_item(pane, &dis, entry, col);
2328 }
2329
2330 SelectObject(hdc, hfontOld);
2331 ReleaseDC(pane->hwnd, hdc);
2332
2333 cx = pane->widths[col];
2334
2335 if (cx) {
2336 cx += 3*Globals.spaceSize.cx;
2337
2338 if (cx < IMAGE_WIDTH)
2339 cx = IMAGE_WIDTH;
2340 }
2341
2342 pane->widths[col] = cx;
2343
2344 x = pane->positions[col] + cx;
2345
2346 for(; col<COLUMNS; ) {
2347 pane->positions[++col] = x;
2348 x += pane->widths[col];
2349 }
2350
2351 ListBox_SetHorizontalExtent(pane->hwnd, x);
2352 }
2353
2354
2355 /* insert listbox entries after index idx */
2356
2357 static void insert_entries(Pane* pane, Entry* dir, int idx)
2358 {
2359 Entry* entry = dir;
2360
2361 if (!entry)
2362 return;
2363
2364 ShowWindow(pane->hwnd, SW_HIDE);
2365
2366 for(; entry; entry=entry->next) {
2367 #ifndef _LEFT_FILES
2368 if (pane->treePane && !(entry->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
2369 continue;
2370 #endif
2371
2372 /* don't display entries "." and ".." in the left pane */
2373 if (pane->treePane && (entry->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
2374 && entry->data.cFileName[0]==TEXT('.'))
2375 if (
2376 #ifndef _NO_EXTENSIONS
2377 entry->data.cFileName[1]==TEXT('\0') ||
2378 #endif
2379 (entry->data.cFileName[1]==TEXT('.') && entry->data.cFileName[2]==TEXT('\0')))
2380 continue;
2381
2382 if (idx != -1)
2383 idx++;
2384
2385 ListBox_InsertItemData(pane->hwnd, idx, entry);
2386
2387 if (pane->treePane && entry->expanded)
2388 insert_entries(pane, entry->down, idx);
2389 }
2390
2391 ShowWindow(pane->hwnd, SW_SHOW);
2392 }
2393
2394
2395 static WNDPROC g_orgTreeWndProc;
2396
2397 static void create_tree_window(HWND parent, Pane* pane, int id, int id_header)
2398 {
2399 const static TCHAR sListBox[] = {'L','i','s','t','B','o','x','\0'};
2400
2401 static int s_init = 0;
2402 Entry* entry = pane->root;
2403
2404 pane->hwnd = CreateWindow(sListBox, sEmpty, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
2405 LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED|LBS_NOTIFY,
2406 0, 0, 0, 0, parent, (HMENU)id, Globals.hInstance, 0);
2407
2408 SetWindowLong(pane->hwnd, GWL_USERDATA, (LPARAM)pane);
2409 g_orgTreeWndProc = SubclassWindow(pane->hwnd, TreeWndProc);
2410
2411 SetWindowFont(pane->hwnd, Globals.hfont, FALSE);
2412
2413 /* insert entries into listbox */
2414 if (entry)
2415 insert_entries(pane, entry, -1);
2416
2417 /* calculate column widths */
2418 if (!s_init) {
2419 s_init = 1;
2420 init_output(pane->hwnd);
2421 }
2422
2423 calc_widths(pane, TRUE);
2424
2425 #ifndef _NO_EXTENSIONS
2426 pane->hwndHeader = create_header(parent, pane, id_header);
2427 #endif
2428 }
2429
2430
2431 static void InitChildWindow(ChildWnd* child)
2432 {
2433 create_tree_window(child->hwnd, &child->left, IDW_TREE_LEFT, IDW_HEADER_LEFT);
2434 create_tree_window(child->hwnd, &child->right, IDW_TREE_RIGHT, IDW_HEADER_RIGHT);
2435 }
2436
2437
2438 static void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols)
2439 {
2440 SYSTEMTIME systime;
2441 FILETIME lft;
2442 int len = 0;
2443
2444 *buffer = TEXT('\0');
2445
2446 if (!ft->dwLowDateTime && !ft->dwHighDateTime)
2447 return;
2448
2449 if (!FileTimeToLocalFileTime(ft, &lft))
2450 {err: _tcscpy(buffer,sQMarks); return;}
2451
2452 if (!FileTimeToSystemTime(&lft, &systime))
2453 goto err;
2454
2455 if (visible_cols & COL_DATE) {
2456 len = GetDateFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer, BUFFER_LEN);
2457 if (!len)
2458 goto err;
2459 }
2460
2461 if (visible_cols & COL_TIME) {
2462 if (len)
2463 buffer[len-1] = ' ';
2464
2465 buffer[len++] = ' ';
2466
2467 if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer+len, BUFFER_LEN-len))
2468 buffer[len] = TEXT('\0');
2469 }
2470 }
2471
2472
2473 static void calc_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
2474 {
2475 RECT rt = {0, 0, 0, 0};
2476
2477 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
2478
2479 if (rt.right > pane->widths[col])
2480 pane->widths[col] = rt.right;
2481 }
2482
2483 static void calc_tabbed_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
2484 {
2485 RECT rt = {0, 0, 0, 0};
2486
2487 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
2488 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
2489
2490 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
2491 /*FIXME rt (0,0) ??? */
2492
2493 if (rt.right > pane->widths[col])
2494 pane->widths[col] = rt.right;
2495 }
2496
2497
2498 static void output_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str, DWORD flags)
2499 {
2500 int x = dis->rcItem.left;
2501 RECT rt;
2502
2503 rt.left = x+pane->positions[col]+Globals.spaceSize.cx;
2504 rt.top = dis->rcItem.top;
2505 rt.right = x+pane->positions[col+1]-Globals.spaceSize.cx;
2506 rt.bottom = dis->rcItem.bottom;
2507
2508 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|flags);
2509 }
2510
2511 static void output_tabbed_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
2512 {
2513 int x = dis->rcItem.left;
2514 RECT rt;
2515
2516 rt.left = x+pane->positions[col]+Globals.spaceSize.cx;
2517 rt.top = dis->rcItem.top;
2518 rt.right = x+pane->positions[col+1]-Globals.spaceSize.cx;
2519 rt.bottom = dis->rcItem.bottom;
2520
2521 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
2522 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
2523
2524 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
2525 }
2526
2527 static void output_number(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
2528 {
2529 int x = dis->rcItem.left;
2530 RECT rt;
2531 LPCTSTR s = str;
2532 TCHAR b[128];
2533 LPTSTR d = b;
2534 int pos;
2535
2536 rt.left = x+pane->positions[col]+Globals.spaceSize.cx;
2537 rt.top = dis->rcItem.top;
2538 rt.right = x+pane->positions[col+1]-Globals.spaceSize.cx;
2539 rt.bottom = dis->rcItem.bottom;
2540
2541 if (*s)
2542 *d++ = *s++;
2543
2544 /* insert number separator characters */
2545 pos = lstrlen(s) % 3;
2546
2547 while(*s)
2548 if (pos--)
2549 *d++ = *s++;
2550 else {
2551 *d++ = Globals.num_sep;
2552 pos = 3;
2553 }
2554
2555 DrawText(dis->hDC, b, d-b, &rt, DT_RIGHT|DT_SINGLELINE|DT_NOPREFIX|DT_END_ELLIPSIS);
2556 }
2557
2558
2559 static int is_exe_file(LPCTSTR ext)
2560 {
2561 static const TCHAR executable_extensions[][4] = {
2562 {'C','O','M','\0'},
2563 {'E','X','E','\0'},
2564 {'B','A','T','\0'},
2565 {'C','M','D','\0'},
2566 #ifndef _NO_EXTENSIONS
2567 {'C','M','M','\0'},
2568 {'B','T','M','\0'},
2569 {'A','W','K','\0'},
2570 #endif /* _NO_EXTENSIONS */
2571 {'\0'}
2572 };
2573
2574 TCHAR ext_buffer[_MAX_EXT];
2575 const TCHAR (*p)[4];
2576 LPCTSTR s;
2577 LPTSTR d;
2578
2579 for(s=ext+1,d=ext_buffer; (*d=tolower(*s)); s++)
2580 d++;
2581
2582 for(p=executable_extensions; (*p)[0]; p++)
2583 if (!_tcscmp(ext_buffer, *p))
2584 return 1;
2585
2586 return 0;
2587 }
2588
2589 static int is_registered_type(LPCTSTR ext)
2590 {
2591 /* TODO */
2592
2593 return 1;
2594 }
2595
2596
2597 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
2598 {
2599 TCHAR buffer[BUFFER_LEN];
2600 DWORD attrs;
2601 int visible_cols = pane->visible_cols;
2602 COLORREF bkcolor, textcolor;
2603 RECT focusRect = dis->rcItem;
2604 HBRUSH hbrush;
2605 enum IMAGE img;
2606 int img_pos, cx;
2607 int col = 0;
2608
2609 if (entry) {
2610 attrs = entry->data.dwFileAttributes;
2611
2612 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
2613 if (entry->data.cFileName[0]==TEXT('.') && entry->data.cFileName[1]==TEXT('.')
2614 && entry->data.cFileName[2]==TEXT('\0'))
2615 img = IMG_FOLDER_UP;
2616 #ifndef _NO_EXTENSIONS
2617 else if (entry->data.cFileName[0]==TEXT('.') && entry->data.cFileName[1]==TEXT('\0'))
2618 img = IMG_FOLDER_CUR;
2619 #endif
2620 else if (
2621 #ifdef _NO_EXTENSIONS
2622 entry->expanded ||
2623 #endif
2624 (pane->treePane && (dis->itemState&ODS_FOCUS)))
2625 img = IMG_OPEN_FOLDER;
2626 else
2627 img = IMG_FOLDER;
2628 } else {
2629 LPCTSTR ext = _tcsrchr(entry->data.cFileName, '.');
2630 if (!ext)
2631 ext = sEmpty;
2632
2633 if (is_exe_file(ext))
2634 img = IMG_EXECUTABLE;
2635 else if (is_registered_type(ext))
2636 img = IMG_DOCUMENT;
2637 else
2638 img = IMG_FILE;
2639 }
2640 } else {
2641 attrs = 0;
2642 img = IMG_NONE;
2643 }
2644
2645 if (pane->treePane) {
2646 if (entry) {
2647 img_pos = dis->rcItem.left + entry->level*(IMAGE_WIDTH+TREE_LINE_DX);
2648
2649 if (calcWidthCol == -1) {
2650 int x;
2651 int y = dis->rcItem.top + IMAGE_HEIGHT/2;
2652 Entry* up;
2653 RECT rt_clip;
2654 HRGN hrgn_org = CreateRectRgn(0, 0, 0, 0);
2655 HRGN hrgn;
2656
2657 rt_clip.left = dis->rcItem.left;
2658 rt_clip.top = dis->rcItem.top;
2659 rt_clip.right = dis->rcItem.left+pane->widths[col];
2660 rt_clip.bottom = dis->rcItem.bottom;
2661
2662 hrgn = CreateRectRgnIndirect(&rt_clip);
2663
2664 if (!GetClipRgn(dis->hDC, hrgn_org)) {
2665 DeleteObject(hrgn_org);
2666 hrgn_org = 0;
2667 }
2668
2669 /* HGDIOBJ holdPen = SelectObject(dis->hDC, GetStockObject(BLACK_PEN)); */
2670 ExtSelectClipRgn(dis->hDC, hrgn, RGN_AND);
2671 DeleteObject(hrgn);
2672
2673 if ((up=entry->up) != NULL) {
2674 MoveToEx(dis->hDC, img_pos-IMAGE_WIDTH/2, y, 0);
2675 LineTo(dis->hDC, img_pos-2, y);
2676
2677 x = img_pos - IMAGE_WIDTH/2;
2678
2679 do {
2680 x -= IMAGE_WIDTH+TREE_LINE_DX;
2681
2682 if (up->next
2683 #ifndef _LEFT_FILES
2684 && (up->next->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2685 #endif
2686 ) {
2687 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
2688 LineTo(dis->hDC, x, dis->rcItem.bottom);
2689 }
2690 } while((up=up->up) != NULL);
2691 }
2692
2693 x = img_pos - IMAGE_WIDTH/2;
2694
2695 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
2696 LineTo(dis->hDC, x, y);
2697
2698 if (entry->next
2699 #ifndef _LEFT_FILES
2700 && (entry->next->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
2701 #endif
2702 )
2703 LineTo(dis->hDC, x, dis->rcItem.bottom);
2704
2705 if (entry->down && entry->expanded) {
2706 x += IMAGE_WIDTH+TREE_LINE_DX;
2707 MoveToEx(dis->hDC, x, dis->rcItem.top+IMAGE_HEIGHT, 0);
2708 LineTo(dis->hDC, x, dis->rcItem.bottom);
2709 }
2710
2711 SelectClipRgn(dis->hDC, hrgn_org);
2712 if (hrgn_org) DeleteObject(hrgn_org);
2713 /* SelectObject(dis->hDC, holdPen); */
2714 } else if (calcWidthCol==col || calcWidthCol==COLUMNS) {
2715 int right = img_pos + IMAGE_WIDTH - TREE_LINE_DX;
2716
2717 if (right > pane->widths[col])
2718 pane->widths[col] = right;
2719 }
2720 } else {
2721 img_pos = dis->rcItem.left;
2722 }
2723 } else {
2724 img_pos = dis->rcItem.left;
2725
2726 if (calcWidthCol==col || calcWidthCol==COLUMNS)
2727 pane->widths[col] = IMAGE_WIDTH;
2728 }
2729
2730 if (calcWidthCol == -1) {
2731 focusRect.left = img_pos - 2;
2732
2733 #ifdef _NO_EXTENSIONS
2734 if (pane->treePane && entry) {
2735 RECT rt = {0};
2736
2737 DrawText(dis->hDC, entry->data.cFileName, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
2738
2739 focusRect.right = dis->rcItem.left+pane->positions[col+1]+TREE_LINE_DX + rt.right +2;
2740 }
2741 #else
2742
2743 if (attrs & FILE_ATTRIBUTE_COMPRESSED)
2744 textcolor = COLOR_COMPRESSED;
2745 else
2746 #endif /* _NO_EXTENSIONS */
2747 textcolor = RGB(0,0,0);
2748
2749 if (dis->itemState & ODS_FOCUS) {
2750 textcolor = RGB(255,255,255);
2751 bkcolor = COLOR_SELECTION;
2752 } else {
2753 bkcolor = RGB(255,255,255);
2754 }
2755
2756 hbrush = CreateSolidBrush(bkcolor);
2757 FillRect(dis->hDC, &focusRect, hbrush);
2758 DeleteObject(hbrush);
2759
2760 SetBkMode(dis->hDC, TRANSPARENT);
2761 SetTextColor(dis->hDC, textcolor);
2762
2763 cx = pane->widths[col];
2764
2765 if (cx && img!=IMG_NONE) {
2766 if (cx > IMAGE_WIDTH)
2767 cx = IMAGE_WIDTH;
2768
2769 #ifdef _SHELL_FOLDERS
2770 if (entry->hicon && entry->hicon!=(HICON)-1)
2771 DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->hicon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
2772 else
2773 #endif
2774 ImageList_DrawEx(Globals.himl, img, dis->hDC,
2775 img_pos, dis->rcItem.top, cx,
2776 IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
2777 }
2778 }
2779
2780 if (!entry)
2781 return;
2782
2783 #ifdef _NO_EXTENSIONS
2784 if (img >= IMG_FOLDER_UP)
2785 return;
2786 #endif
2787
2788 col++;
2789
2790 /* ouput file name */
2791 if (calcWidthCol == -1)
2792 output_text(pane, dis, col, entry->data.cFileName, 0);
2793 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2794 calc_width(pane, dis, col, entry->data.cFileName);
2795
2796 col++;
2797
2798 #ifdef _NO_EXTENSIONS
2799 if (!pane->treePane) {
2800 #endif
2801
2802 /* display file size */
2803 if (visible_cols & COL_SIZE) {
2804 #ifdef _NO_EXTENSIONS
2805 if (!(attrs&FILE_ATTRIBUTE_DIRECTORY))
2806 #endif
2807 {
2808 ULONGLONG size;
2809
2810 size = ((ULONGLONG)entry->data.nFileSizeHigh << 32) | entry->data.nFileSizeLow;
2811
2812 _stprintf(buffer, sLongNumFmt, size);
2813
2814 if (calcWidthCol == -1)
2815 output_number(pane, dis, col, buffer);
2816 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2817 calc_width(pane, dis, col, buffer);/*TODO: not in every case time enough */
2818 }
2819
2820 col++;
2821 }
2822
2823 /* display file date */
2824 if (visible_cols & (COL_DATE|COL_TIME)) {
2825 #ifndef _NO_EXTENSIONS
2826 format_date(&entry->data.ftCreationTime, buffer, visible_cols);
2827 if (calcWidthCol == -1)
2828 output_text(pane, dis, col, buffer, 0);
2829 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2830 calc_width(pane, dis, col, buffer);
2831 col++;
2832
2833 format_date(&entry->data.ftLastAccessTime, buffer, visible_cols);
2834 if (calcWidthCol == -1)
2835 output_text(pane, dis, col, buffer, 0);
2836 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2837 calc_width(pane, dis, col, buffer);
2838 col++;
2839 #endif /* _NO_EXTENSIONS */
2840
2841 format_date(&entry->data.ftLastWriteTime, buffer, visible_cols);
2842 if (calcWidthCol == -1)
2843 output_text(pane, dis, col, buffer, 0);
2844 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2845 calc_width(pane, dis, col, buffer);
2846 col++;
2847 }
2848
2849 #ifndef _NO_EXTENSIONS
2850 if (entry->bhfi_valid) {
2851 ULONGLONG index = ((ULONGLONG)entry->bhfi.nFileIndexHigh << 32) | entry->bhfi.nFileIndexLow;
2852
2853 if (visible_cols & COL_INDEX) {
2854 _stprintf(buffer, sLongHexFmt, index);
2855
2856 if (calcWidthCol == -1)
2857 output_text(pane, dis, col, buffer, DT_RIGHT);
2858 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2859 calc_width(pane, dis, col, buffer);
2860
2861 col++;
2862 }
2863
2864 if (visible_cols & COL_LINKS) {
2865 wsprintf(buffer, sNumFmt, entry->bhfi.nNumberOfLinks);
2866
2867 if (calcWidthCol == -1)
2868 output_text(pane, dis, col, buffer, DT_CENTER);
2869 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2870 calc_width(pane, dis, col, buffer);
2871
2872 col++;
2873 }
2874 } else
2875 col += 2;
2876 #endif /* _NO_EXTENSIONS */
2877
2878 /* show file attributes */
2879 if (visible_cols & COL_ATTRIBUTES) {
2880 #ifdef _NO_EXTENSIONS
2881 const static TCHAR s4Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
2882 _tcscpy(buffer, s4Tabs);
2883 #else
2884 const static TCHAR s11Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
2885 _tcscpy(buffer, s11Tabs);
2886 #endif
2887
2888 if (attrs & FILE_ATTRIBUTE_NORMAL) buffer[ 0] = 'N';
2889 else {
2890 if (attrs & FILE_ATTRIBUTE_READONLY) buffer[ 2] = 'R';
2891 if (attrs & FILE_ATTRIBUTE_HIDDEN) buffer[ 4] = 'H';
2892 if (attrs & FILE_ATTRIBUTE_SYSTEM) buffer[ 6] = 'S';
2893 if (attrs & FILE_ATTRIBUTE_ARCHIVE) buffer[ 8] = 'A';
2894 if (attrs & FILE_ATTRIBUTE_COMPRESSED) buffer[10] = 'C';
2895 #ifndef _NO_EXTENSIONS
2896 if (attrs & FILE_ATTRIBUTE_DIRECTORY) buffer[12] = 'D';
2897 if (attrs & FILE_ATTRIBUTE_ENCRYPTED) buffer[14] = 'E';
2898 if (attrs & FILE_ATTRIBUTE_TEMPORARY) buffer[16] = 'T';
2899 if (attrs & FILE_ATTRIBUTE_SPARSE_FILE) buffer[18] = 'P';
2900 if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) buffer[20] = 'Q';
2901 if (attrs & FILE_ATTRIBUTE_OFFLINE) buffer[22] = 'O';
2902 if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) buffer[24] = 'X';
2903 #endif /* _NO_EXTENSIONS */
2904 }
2905
2906 if (calcWidthCol == -1)
2907 output_tabbed_text(pane, dis, col, buffer);
2908 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2909 calc_tabbed_width(pane, dis, col, buffer);
2910
2911 col++;
2912 }
2913
2914 /*TODO
2915 if (flags.security) {
2916 const static TCHAR sSecTabs[] = {
2917 ' ','\t',' ','\t',' ','\t',' ',
2918 ' ','\t',' ',
2919 ' ','\t',' ','\t',' ','\t',' ',
2920 ' ','\t',' ',
2921 ' ','\t',' ','\t',' ','\t',' ',
2922 '\0'
2923 };
2924
2925 DWORD rights = get_access_mask();
2926
2927 tcscpy(buffer, sSecTabs);
2928
2929 if (rights & FILE_READ_DATA) buffer[ 0] = 'R';
2930 if (rights & FILE_WRITE_DATA) buffer[ 2] = 'W';
2931 if (rights & FILE_APPEND_DATA) buffer[ 4] = 'A';
2932 if (rights & FILE_READ_EA) {buffer[6] = 'entry'; buffer[ 7] = 'R';}
2933 if (rights & FILE_WRITE_EA) {buffer[9] = 'entry'; buffer[10] = 'W';}
2934 if (rights & FILE_EXECUTE) buffer[12] = 'X';
2935 if (rights & FILE_DELETE_CHILD) buffer[14] = 'D';
2936 if (rights & FILE_READ_ATTRIBUTES) {buffer[16] = 'a'; buffer[17] = 'R';}
2937 if (rights & FILE_WRITE_ATTRIBUTES) {buffer[19] = 'a'; buffer[20] = 'W';}
2938 if (rights & WRITE_DAC) buffer[22] = 'C';
2939 if (rights & WRITE_OWNER) buffer[24] = 'O';
2940 if (rights & SYNCHRONIZE) buffer[26] = 'S';
2941
2942 output_text(dis, col++, buffer, DT_LEFT, 3, psize);
2943 }
2944
2945 if (flags.description) {
2946 get_description(buffer);
2947 output_text(dis, col++, buffer, 0, psize);
2948 }
2949 */
2950
2951 #ifdef _NO_EXTENSIONS
2952 }
2953
2954 /* draw focus frame */
2955 if ((dis->itemState&ODS_FOCUS) && calcWidthCol==-1) {
2956 /* Currently [04/2000] Wine neither behaves exactly the same */
2957 /* way as WIN 95 nor like Windows NT... */
2958 HGDIOBJ lastBrush;
2959 HPEN lastPen;
2960 HPEN hpen;
2961
2962 if (!(GetVersion() & 0x80000000)) { /* Windows NT? */
2963 LOGBRUSH lb = {PS_SOLID, RGB(255,255,255)};
2964 hpen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
2965 } else
2966 hpen = CreatePen(PS_DOT, 0, RGB(255,255,255));
2967
2968 lastPen = SelectPen(dis->hDC, hpen);
2969 lastBrush = SelectObject(dis->hDC, GetStockObject(HOLLOW_BRUSH));
2970 SetROP2(dis->hDC, R2_XORPEN);
2971 Rectangle(dis->hDC, focusRect.left, focusRect.top, focusRect.right, focusRect.bottom);
2972 SelectObject(dis->hDC, lastBrush);
2973 SelectObject(dis->hDC, lastPen);
2974 DeleteObject(hpen);
2975 }
2976 #endif /* _NO_EXTENSIONS */
2977 }
2978
2979
2980 #ifdef _NO_EXTENSIONS
2981
2982 static void draw_splitbar(HWND hwnd, int x)
2983 {
2984 RECT rt;
2985 HDC hdc = GetDC(hwnd);
2986
2987 GetClientRect(hwnd, &rt);
2988
2989 rt.left = x - SPLIT_WIDTH/2;
2990 rt.right = x + SPLIT_WIDTH/2+1;
2991
2992 InvertRect(hdc, &rt);
2993
2994 ReleaseDC(hwnd, hdc);
2995 }
2996
2997 #endif /* _NO_EXTENSIONS */
2998
2999
3000 #ifndef _NO_EXTENSIONS
3001
3002 static void set_header(Pane* pane)
3003 {
3004 HD_ITEM item;
3005 int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
3006 int i=0, x=0;
3007
3008 item.mask = HDI_WIDTH;
3009 item.cxy = 0;
3010
3011 for(; x+pane->widths[i]<scroll_pos && i<COLUMNS; i++) {
3012 x += pane->widths[i];
3013 Header_SetItem(pane->hwndHeader, i, &item);
3014 }
3015
3016 if (i < COLUMNS) {
3017 x += pane->widths[i];
3018 item.cxy = x - scroll_pos;
3019 Header_SetItem(pane->hwndHeader, i++, &item);
3020
3021 for(; i<COLUMNS; i++) {
3022 item.cxy = pane->widths[i];
3023 x += pane->widths[i];
3024 Header_SetItem(pane->hwndHeader, i, &item);
3025 }
3026 }
3027 }
3028
3029 static LRESULT pane_notify(Pane* pane, NMHDR* pnmh)
3030 {
3031 switch(pnmh->code) {
3032 case HDN_TRACK:
3033 case HDN_ENDTRACK: {
3034 HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
3035 int idx = phdn->iItem;
3036 int dx = phdn->pitem->cxy - pane->widths[idx];
3037 int i;
3038
3039 RECT clnt;
3040 GetClientRect(pane->hwnd, &clnt);
3041
3042 /* move immediate to simulate HDS_FULLDRAG (for now [04/2000] not really needed with WINELIB) */
3043 Header_SetItem(pane->hwndHeader, idx, phdn->pitem);
3044
3045 pane->widths[idx] += dx;
3046
3047 for(i=idx; ++i<=COLUMNS; )
3048 pane->positions[i] += dx;
3049
3050 {
3051 int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
3052 RECT rt_scr;
3053 RECT rt_clip;
3054
3055 rt_scr.left = pane->positions[idx+1]-scroll_pos;
3056 rt_scr.top = 0;
3057 rt_scr.right = clnt.right;
3058 rt_scr.bottom = clnt.bottom;
3059
3060 rt_clip.left = pane->positions[idx]-scroll_pos;
3061 rt_clip.top = 0;
3062 rt_clip.right = clnt.right;
3063 rt_clip.bottom = clnt.bottom;
3064
3065 if (rt_scr.left < 0) rt_scr.left = 0;
3066 if (rt_clip.left < 0) rt_clip.left = 0;
3067
3068 ScrollWindowEx(pane->hwnd, dx, 0, &rt_scr, &rt_clip, 0, 0, SW_INVALIDATE);
3069
3070 rt_clip.right = pane->positions[idx+1];
3071 RedrawWindow(pane->hwnd, &rt_clip, 0, RDW_INVALIDATE|RDW_UPDATENOW);
3072
3073 if (pnmh->code == HDN_ENDTRACK) {
3074 ListBox_SetHorizontalExtent(pane->hwnd, pane->positions[COLUMNS]);
3075
3076 if (GetScrollPos(pane->hwnd, SB_HORZ) != scroll_pos)
3077 set_header(pane);
3078 }
3079 }
3080
3081 return FALSE;
3082 }
3083
3084 case HDN_DIVIDERDBLCLICK: {
3085 HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
3086 HD_ITEM item;
3087
3088 calc_single_width(pane, phdn->iItem);
3089 item.mask = HDI_WIDTH;
3090 item.cxy = pane->widths[phdn->iItem];
3091
3092 Header_SetItem(pane->hwndHeader, phdn->iItem, &item);
3093 InvalidateRect(pane->hwnd, 0, TRUE);
3094 break;}
3095 }
3096
3097 return 0;
3098 }
3099
3100 #endif /* _NO_EXTENSIONS */
3101
3102
3103 static void scan_entry(ChildWnd* child, Entry* entry, HWND hwnd)
3104 {
3105 TCHAR path[MAX_PATH];
3106 int idx = ListBox_GetCurSel(child->left.hwnd);
3107 HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
3108
3109 /* delete sub entries in left pane */
3110 for(;;) {
3111 LRESULT res = ListBox_GetItemData(child->left.hwnd, idx+1);
3112 Entry* sub = (Entry*) res;
3113
3114 if (res==LB_ERR || !sub || sub->level<=entry->level)
3115 break;
3116
3117 ListBox_DeleteString(child->left.hwnd, idx+1);
3118 }
3119
3120 /* empty right pane */
3121 ListBox_ResetContent(child->right.hwnd);
3122
3123 /* release memory */
3124 free_entries(entry);
3125
3126 /* read contents from disk */
3127 #ifdef _SHELL_FOLDERS
3128 if (entry->etype == ET_SHELL)
3129 {
3130 read_directory(entry, NULL, child->sortOrder, hwnd);
3131 }
3132 else
3133 #endif
3134 {
3135 get_path(entry, path);
3136 read_directory(entry, path, child->sortOrder, hwnd);
3137 }
3138
3139 /* insert found entries in right pane */
3140 insert_entries(&child->right, entry->down, -1);
3141 calc_widths(&child->right, FALSE);
3142 #ifndef _NO_EXTENSIONS
3143 set_header(&child->right);
3144 #endif
3145
3146 child->header_wdths_ok = FALSE;
3147
3148 SetCursor(old_cursor);
3149 }
3150
3151
3152 /* expand a directory entry */
3153
3154 static BOOL expand_entry(ChildWnd* child, Entry* dir)
3155 {
3156 int idx;
3157 Entry* p;
3158
3159 if (!dir || dir->expanded || !dir->down)
3160 return FALSE;
3161
3162 p = dir->down;
3163
3164 if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='\0' && p->next) {
3165 p = p->next;
3166
3167 if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='.' &&
3168 p->data.cFileName[2]=='\0' && p->next)
3169 p = p->next;
3170 }
3171
3172 /* no subdirectories ? */
3173 if (!(p->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
3174 return FALSE;
3175
3176 idx = ListBox_FindItemData(child->left.hwnd, 0, dir);
3177
3178 dir->expanded = TRUE;
3179
3180 /* insert entries in left pane */
3181 insert_entries(&child->left, p, idx);
3182
3183 if (!child->header_wdths_ok) {
3184 if (calc_widths(&child->left, FALSE)) {
3185 #ifndef _NO_EXTENSIONS
3186 set_header(&child->left);
3187 #endif
3188
3189 child->header_wdths_ok = TRUE;
3190 }
3191 }
3192
3193 return TRUE;
3194 }
3195
3196
3197 static void collapse_entry(Pane* pane, Entry* dir)
3198 {
3199 int idx = ListBox_FindItemData(pane->hwnd, 0, dir);
3200
3201 ShowWindow(pane->hwnd, SW_HIDE);
3202
3203 /* hide sub entries */
3204 for(;;) {
3205 LRESULT res = ListBox_GetItemData(pane->hwnd, idx+1);
3206 Entry* sub = (Entry*) res;
3207
3208 if (res==LB_ERR || !sub || sub->level<=dir->level)
3209 break;
3210
3211 ListBox_DeleteString(pane->hwnd, idx+1);
3212 }
3213
3214 dir->expanded = FALSE;
3215
3216 ShowWindow(pane->hwnd, SW_SHOW);
3217 }
3218
3219
3220 static void set_curdir(ChildWnd* child, Entry* entry, HWND hwnd)
3221 {
3222 TCHAR path[MAX_PATH];
3223
3224 path[0] = '\0';
3225
3226 child->left.cur = entry;
3227 child->right.root = entry->down? entry->down: entry;
3228 child->right.cur = entry;
3229
3230 if (!entry->scanned)
3231 scan_entry(child, entry, hwnd);
3232 else {
3233 ListBox_ResetContent(child->right.hwnd);
3234 insert_entries(&child->right, entry->down, -1);
3235 calc_widths(&child->right, FALSE);
3236 #ifndef _NO_EXTENSIONS
3237 set_header(&child->right);
3238 #endif
3239 }
3240
3241 get_path(entry, path);
3242 lstrcpy(child->path, path);
3243
3244 if (child->hwnd) /* only change window title, if the window already exists */
3245 SetWindowText(child->hwnd, path);
3246
3247 if (path[0])
3248 SetCurrentDirectory(path);
3249 }
3250
3251
3252 BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow)
3253 {
3254 HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, cmd, NULL/*parameters*/, NULL/*dir*/, nCmdShow);
3255
3256 if ((int)hinst <= 32) {
3257 display_error(hwnd, GetLastError());
3258 return FALSE;
3259 }
3260
3261 return TRUE;
3262 }
3263
3264 #ifdef UNICODE
3265 BOOL launch_fileA(HWND hwnd, LPSTR cmd, UINT nCmdShow)
3266 {
3267 HINSTANCE hinst = ShellExecuteA(hwnd, NULL/*operation*/, cmd, NULL/*parameters*/, NULL/*dir*/, nCmdShow);
3268
3269 if ((int)hinst <= 32) {
3270 display_error(hwnd, GetLastError());
3271 return FALSE;
3272 }
3273
3274 return TRUE;
3275 }
3276 #endif
3277
3278
3279 BOOL launch_entry(Entry* entry, HWND hwnd, UINT nCmdShow)
3280 {
3281 TCHAR cmd[MAX_PATH];
3282
3283 #ifdef _SHELL_FOLDERS
3284 if (entry->etype == ET_SHELL) {
3285 BOOL ret = TRUE;
3286
3287 SHELLEXECUTEINFO shexinfo;
3288
3289 shexinfo.cbSize = sizeof(SHELLEXECUTEINFO);
3290 shexinfo.fMask = SEE_MASK_IDLIST;
3291 shexinfo.hwnd = hwnd;
3292 shexinfo.lpVerb = NULL;
3293 shexinfo.lpFile = NULL;
3294 shexinfo.lpParameters = NULL;
3295 shexinfo.lpDirectory = NULL;
3296 shexinfo.nShow = nCmdShow;
3297 shexinfo.lpIDList = get_to_absolute_pidl(entry, hwnd);
3298
3299 if (!ShellExecuteEx(&shexinfo)) {
3300 display_error(hwnd, GetLastError());
3301 ret = FALSE;
3302 }
3303
3304 if (shexinfo.lpIDList != entry->pidl)
3305 (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, shexinfo.lpIDList);
3306
3307 return ret;
3308 }
3309 #endif
3310
3311 get_path(entry, cmd);
3312
3313 /* start program, open document... */
3314 return launch_file(hwnd, cmd, nCmdShow);
3315 }
3316
3317
3318 static void activate_entry(ChildWnd* child, Pane* pane, HWND hwnd)
3319 {
3320 Entry* entry = pane->cur;
3321
3322 if (!entry)
3323 return;
3324
3325 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
3326 int scanned_old = entry->scanned;
3327
3328 if (!scanned_old)
3329 scan_entry(child, entry, hwnd);
3330
3331 #ifndef _NO_EXTENSIONS
3332 if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='\0')
3333 return;
3334 #endif
3335
3336 if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='.' && entry->data.cFileName[2]=='\0') {
3337 entry = child->left.cur->up;
3338 collapse_entry(&child->left, entry);
3339 goto focus_entry;
3340 } else if (entry->expanded)
3341 collapse_entry(pane, child->left.cur);
3342 else {
3343 expand_entry(child, child->left.cur);
3344
3345 if (!pane->treePane) focus_entry: {
3346 int idx = ListBox_FindItemData(child->left.hwnd, ListBox_GetCurSel(child->left.hwnd), entry);
3347 ListBox_SetCurSel(child->left.hwnd, idx);
3348 set_curdir(child, entry, hwnd);
3349 }
3350 }
3351
3352 if (!scanned_old) {
3353 calc_widths(pane, FALSE);
3354
3355 #ifndef _NO_EXTENSIONS
3356 set_header(pane);
3357 #endif
3358 }
3359 } else {
3360 launch_entry(entry, child->hwnd, SW_SHOWNORMAL);
3361 }
3362 }
3363
3364
3365 static BOOL pane_command(Pane* pane, UINT cmd)
3366 {
3367 switch(cmd) {
3368 case ID_VIEW_NAME:
3369 if (pane->visible_cols) {
3370 pane->visible_cols = 0;
3371 calc_widths(pane, TRUE);
3372 #ifndef _NO_EXTENSIONS
3373 set_header(pane);
3374 #endif
3375 InvalidateRect(pane->hwnd, 0, TRUE);
3376 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND|MF_CHECKED);
3377 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND);
3378 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
3379 }
3380 break;
3381
3382 case ID_VIEW_ALL_ATTRIBUTES:
3383 if (pane->visible_cols != COL_ALL) {
3384 pane->visible_cols = COL_ALL;
3385 calc_widths(pane, TRUE);
3386 #ifndef _NO_EXTENSIONS
3387 set_header(pane);
3388 #endif
3389 InvalidateRect(pane->hwnd, 0, TRUE);
3390 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND);
3391 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND|MF_CHECKED);
3392 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
3393 }
3394 break;
3395
3396 #ifndef _NO_EXTENSIONS
3397 case ID_PREFERED_SIZES: {
3398 calc_widths(pane, TRUE);
3399 set_header(pane);
3400 InvalidateRect(pane->hwnd, 0, TRUE);
3401 break;}
3402 #endif
3403
3404 /* TODO: more command ids... */
3405
3406 default:
3407 return FALSE;
3408 }
3409
3410 return TRUE;
3411 }
3412
3413
3414 static HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl, LPCITEMIDLIST* apidl, int x, int y)
3415 {
3416 IContextMenu* pcm;
3417
3418 HRESULT hr = (*shell_folder->lpVtbl->GetUIObjectOf)(shell_folder, hwndParent, cidl, apidl, &IID_IContextMenu, NULL, (LPVOID*)&pcm);
3419 /* HRESULT hr = CDefFolderMenu_Create2(dir?dir->_pidl:DesktopFolder(), hwndParent, 1, &pidl, shell_folder, NULL, 0, NULL, &pcm); */
3420
3421 if (SUCCEEDED(hr)) {
3422 HMENU hmenu = CreatePopupMenu();
3423
3424 if (hmenu) {
3425 hr = (*pcm->lpVtbl->QueryContextMenu)(pcm, hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
3426
3427 if (SUCCEEDED(hr)) {
3428 UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, hwndParent, NULL);
3429
3430 if (idCmd) {
3431 CMINVOKECOMMANDINFO cmi;
3432
3433 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
3434 cmi.fMask = 0;
3435 cmi.hwnd = hwndParent;
3436 cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST);
3437 cmi.lpParameters = NULL;
3438 cmi.lpDirectory = NULL;
3439 cmi.nShow = SW_SHOWNORMAL;
3440 cmi.dwHotKey = 0;
3441 cmi.hIcon = 0;
3442
3443 hr = (*pcm->lpVtbl->InvokeCommand)(pcm, &cmi);
3444 }
3445 }
3446 }
3447
3448 (*pcm->lpVtbl->Release)(pcm);
3449 }
3450
3451 return hr;
3452 }
3453
3454
3455 LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
3456 {
3457 static int last_split;
3458
3459 ChildWnd* child = (ChildWnd*) GetWindowLong(hwnd, GWL_USERDATA);
3460 ASSERT(child);
3461
3462 switch(nmsg) {
3463 case WM_DRAWITEM: {
3464 LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lparam;
3465 Entry* entry = (Entry*) dis->itemData;
3466
3467 if (dis->CtlID == IDW_TREE_LEFT)
3468 draw_item(&child->left, dis, entry, -1);
3469 else
3470 draw_item(&child->right, dis, entry, -1);
3471
3472 return TRUE;}
3473
3474 case WM_CREATE:
3475 InitChildWindow(child);
3476 break;
3477
3478 case WM_NCDESTROY:
3479 free_child_window(child);
3480 SetWindowLong(hwnd, GWL_USERDATA, 0);
3481 break;
3482
3483 case WM_PAINT: {
3484 PAINTSTRUCT ps;
3485 HBRUSH lastBrush;
3486 RECT rt;
3487 GetClientRect(hwnd, &rt);
3488 BeginPaint(hwnd, &ps);
3489 rt.left = child->split_pos-SPLIT_WIDTH/2;
3490 rt.right = child->split_pos+SPLIT_WIDTH/2+1;
3491 lastBrush = SelectBrush(ps.hdc, (HBRUSH)GetStockObject(COLOR_SPLITBAR));
3492 Rectangle(ps.hdc, rt.left, rt.top-1, rt.right, rt.bottom+1);
3493 SelectObject(ps.hdc, lastBrush);
3494 #ifdef _NO_EXTENSIONS
3495 rt.top = rt.bottom - GetSystemMetrics(SM_CYHSCROLL);
3496 FillRect(ps.hdc, &rt, GetStockObject(BLACK_BRUSH));
3497 #endif
3498 EndPaint(hwnd, &ps);
3499 break;}
3500
3501 case WM_SETCURSOR:
3502 if (LOWORD(lparam) == HTCLIENT) {
3503 POINT pt;
3504 GetCursorPos(&pt);
3505 ScreenToClient(hwnd, &pt);
3506
3507 if (pt.x>=child->split_pos-SPLIT_WIDTH/2 && pt.x<child->split_pos+SPLIT_WIDTH/2+1) {
3508 SetCursor(LoadCursor(0, IDC_SIZEWE));
3509 return TRUE;
3510 }
3511 }
3512 goto def;
3513
3514 case WM_LBUTTONDOWN: {
3515 RECT rt;
3516 int x = GET_X_LPARAM(lparam);
3517
3518 GetClientRect(hwnd, &rt);
3519
3520 if (x>=child->split_pos-SPLIT_WIDTH/2 && x<child->split_pos+SPLIT_WIDTH/2+1) {
3521 last_split = child->split_pos;
3522 #ifdef _NO_EXTENSIONS
3523 draw_splitbar(hwnd, last_split);
3524 #endif
3525 SetCapture(hwnd);
3526 }
3527
3528 break;}
3529
3530 case WM_LBUTTONUP:
3531 if (GetCapture() == hwnd) {
3532 #ifdef _NO_EXTENSIONS
3533 RECT rt;
3534 int x = LOWORD(lparam);
3535 draw_splitbar(hwnd, last_split);
3536 last_split = -1;
3537 GetClientRect(hwnd, &rt);
3538 child->split_pos = x;
3539 resize_tree(child, rt.right, rt.bottom);
3540 #endif
3541 ReleaseCapture();
3542 }
3543 break;
3544
3545 #ifdef _NO_EXTENSIONS
3546 case WM_CAPTURECHANGED:
3547 if (GetCapture()==hwnd && last_split>=0)
3548 draw_splitbar(hwnd, last_split);
3549 break;
3550 #endif
3551
3552 case WM_KEYDOWN:
3553 if (wparam == VK_ESCAPE)
3554 if (GetCapture() == hwnd) {
3555 RECT rt;
3556 #ifdef _NO_EXTENSIONS
3557 draw_splitbar(hwnd, last_split);
3558 #else
3559 child->split_pos = last_split;
3560 #endif
3561 GetClientRect(hwnd, &rt);
3562 resize_tree(child, rt.right, rt.bottom);
3563 last_split = -1;
3564 ReleaseCapture();
3565 SetCursor(LoadCursor(0, IDC_ARROW));
3566 }
3567 break;
3568
3569 case WM_MOUSEMOVE:
3570 if (GetCapture() == hwnd) {
3571 RECT rt;
3572 int x = LOWORD(lparam);
3573
3574 #ifdef _NO_EXTENSIONS
3575 HDC hdc = GetDC(hwnd);
3576 GetClientRect(hwnd, &rt);
3577
3578 rt.left = last_split-SPLIT_WIDTH/2;
3579 rt.right = last_split+SPLIT_WIDTH/2+1;
3580 InvertRect(hdc, &rt);
3581
3582 last_split = x;
3583 rt.left = x-SPLIT_WIDTH/2;
3584 rt.right = x+SPLIT_WIDTH/2+1;
3585 InvertRect(hdc, &rt);
3586
3587 ReleaseDC(hwnd, hdc);
3588 #else
3589 GetClientRect(hwnd, &rt);
3590
3591 if (x>=0 && x<rt.right) {
3592 child->split_pos = x;
3593 resize_tree(child, rt.right, rt.bottom);
3594 rt.left = x-SPLIT_WIDTH/2;
3595 rt.right = x+SPLIT_WIDTH/2+1;
3596 InvalidateRect(hwnd, &rt, FALSE);
3597 UpdateWindow(child->left.hwnd);
3598 UpdateWindow(hwnd);
3599 UpdateWindow(child->right.hwnd);
3600 }
3601 #endif
3602 }
3603 break;
3604
3605 #ifndef _NO_EXTENSIONS
3606 case WM_GETMINMAXINFO:
3607 DefMDIChildProc(hwnd, nmsg, wparam, lparam);
3608
3609 {LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
3610
3611 lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
3612 lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
3613 break;}
3614 #endif /* _NO_EXTENSIONS */
3615
3616 case WM_SETFOCUS:
3617 SetCurrentDirectory(child->path);
3618 SetFocus(child->focus_pane? child->right.hwnd: child->left.hwnd);
3619 break;
3620
3621 case WM_DISPATCH_COMMAND: {
3622 Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
3623
3624 switch(LOWORD(wparam)) {
3625 case ID_WINDOW_NEW: {
3626 ChildWnd* new_child = alloc_child_window(child->path, NULL, hwnd);
3627
3628 if (!create_child_window(new_child))
3629 free(new_child);
3630
3631 break;}
3632
3633 case ID_REFRESH:
3634 scan_entry(child, pane->cur, hwnd);
3635 break;
3636
3637 case ID_ACTIVATE:
3638 activate_entry(child, pane, hwnd);
3639 break;
3640
3641 case ID_FILE_MOVE: {
3642 TCHAR new_name[BUFFER_LEN], old_name[BUFFER_LEN];
3643 int len;
3644
3645 int ret = DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_SELECT_DESTINATION), hwnd, DestinationDlgProc, (LPARAM)new_name);
3646 if (ret != IDOK)
3647 break;
3648
3649 if (new_name[0]!='/' && new_name[1]!=':') {
3650 get_path(pane->cur->up, old_name);
3651 len = lstrlen(old_name);
3652
3653 if (old_name[len-1]!='\\' && old_name[len-1]!='/') {
3654 old_name[len++] = '/';
3655 old_name[len] = '\n';
3656 }
3657
3658 lstrcpy(&old_name[len], new_name);
3659 lstrcpy(new_name, old_name);
3660 }
3661
3662 get_path(pane->cur, old_name);
3663
3664 if (MoveFileEx(old_name, new_name, MOVEFILE_COPY_ALLOWED)) {
3665 if (pane->treePane) {
3666 pane->root->scanned = FALSE;
3667 pane->cur = pane->root;
3668 activate_entry(child, pane, hwnd);
3669 }
3670 else
3671 scan_entry(child, pane->root, hwnd);
3672 }
3673 else
3674 display_error(hwnd, GetLastError());
3675 break;}
3676
3677 default:
3678 return pane_command(pane, LOWORD(wparam));
3679 }
3680
3681 return TRUE;}
3682
3683 case WM_COMMAND: {
3684 Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
3685
3686 switch(HIWORD(wparam)) {
3687 case LBN_SELCHANGE: {
3688 int idx = ListBox_GetCurSel(pane->hwnd);
3689 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, idx);
3690
3691 if (pane == &child->left)
3692 set_curdir(child, entry, hwnd);
3693 else
3694 pane->cur = entry;
3695 break;}
3696
3697 case LBN_DBLCLK:
3698 activate_entry(child, pane, hwnd);
3699 break;
3700 }
3701 break;}
3702
3703 #ifndef _NO_EXTENSIONS
3704 case WM_NOTIFY: {
3705 NMHDR* pnmh = (NMHDR*) lparam;
3706 return pane_notify(pnmh->idFrom==IDW_HEADER_LEFT? &child->left: &child->right, pnmh);}
3707 #endif
3708
3709 #ifdef _SHELL_FOLDERS
3710 case WM_CONTEXTMENU: {
3711 Pane* pane;
3712 int idx;
3713
3714 /* first select the current item in the listbox */
3715 HWND hpanel = (HWND) wparam;
3716 POINTS* ppos = &MAKEPOINTS(lparam);
3717 POINT pt; POINTSTOPOINT(pt, *ppos);
3718 ScreenToClient(hpanel, &pt);
3719 SendMessage(hpanel, WM_LBUTTONDOWN, 0, MAKELONG(pt.x, pt.y));
3720 SendMessage(hpanel, WM_LBUTTONUP, 0, MAKELONG(pt.x, pt.y));
3721
3722 /* now create the popup menu using shell namespace and IContextMenu */
3723 pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
3724 idx = ListBox_GetCurSel(pane->hwnd);
3725
3726 if (idx != -1) {
3727 HRESULT hr;
3728 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, idx);
3729
3730 LPITEMIDLIST pidl_abs = get_to_absolute_pidl(entry, hwnd);
3731
3732 if (pidl_abs) {
3733 IShellFolder* parentFolder;
3734 LPCITEMIDLIST pidlLast;
3735
3736 /* get and use the parent folder to display correct context menu in all cases */
3737 if (SUCCEEDED(SHBindToParent(pidl_abs, &IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast))) {
3738 hr = ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, ppos->x, ppos->y);
3739
3740 (*parentFolder->lpVtbl->Release)(parentFolder);
3741 }
3742
3743 (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, pidl_abs);
3744 }
3745 }
3746 break;}
3747 #endif
3748
3749 case WM_SIZE:
3750 if (wparam != SIZE_MINIMIZED)
3751 resize_tree(child, LOWORD(lparam), HIWORD(lparam));
3752 /* fall through */
3753
3754 default: def:
3755 return DefMDIChildProc(hwnd, nmsg, wparam, lparam);
3756 }
3757
3758 return 0;
3759 }
3760
3761
3762 LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
3763 {
3764 ChildWnd* child = (ChildWnd*) GetWindowLong(GetParent(hwnd), GWL_USERDATA);
3765 Pane* pane = (Pane*) GetWindowLong(hwnd, GWL_USERDATA);
3766 ASSERT(child);
3767
3768 switch(nmsg) {
3769 #ifndef _NO_EXTENSIONS
3770 case WM_HSCROLL:
3771 set_header(pane);
3772 break;
3773 #endif
3774
3775 case WM_SETFOCUS:
3776 child->focus_pane = pane==&child->right? 1: 0;
3777 ListBox_SetSel(hwnd, TRUE, 1);
3778 /*TODO: check menu items */
3779 break;
3780
3781 case WM_KEYDOWN:
3782 if (wparam == VK_TAB) {
3783 /*TODO: SetFocus(Globals.hdrivebar) */
3784 SetFocus(child->focus_pane? child->left.hwnd: child->right.hwnd);
3785 }
3786 }
3787
3788 return CallWindowProc(g_orgTreeWndProc, hwnd, nmsg, wparam, lparam);
3789 }
3790
3791
3792 static void InitInstance(HINSTANCE hinstance)
3793 {
3794 const static TCHAR sFont[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
3795
3796 WNDCLASSEX wcFrame;
3797 WNDCLASS wcChild;
3798 ATOM hChildClass;
3799 int col;
3800
3801 INITCOMMONCONTROLSEX icc = {
3802 sizeof(INITCOMMONCONTROLSEX),
3803 ICC_BAR_CLASSES
3804 };
3805
3806 HDC hdc = GetDC(0);
3807
3808 setlocale(LC_COLLATE, ""); /* set collating rules to local settings for compareName */
3809
3810 InitCommonControlsEx(&icc);
3811
3812
3813 /* register frame window class */
3814
3815 wcFrame.cbSize = sizeof(WNDCLASSEX);
3816 wcFrame.style = 0;
3817 wcFrame.lpfnWndProc = FrameWndProc;
3818 wcFrame.cbClsExtra = 0;
3819 wcFrame.cbWndExtra = 0;
3820 wcFrame.hInstance = hinstance;
3821 wcFrame.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_WINEFILE));
3822 wcFrame.hCursor = LoadCursor(0, IDC_ARROW);
3823 wcFrame.hbrBackground = 0;
3824 wcFrame.lpszMenuName = 0;
3825 wcFrame.lpszClassName = sWINEFILEFRAME;
3826 wcFrame.hIconSm = (HICON)LoadImage(hinstance,
3827 MAKEINTRESOURCE(IDI_WINEFILE),
3828 IMAGE_ICON,
3829 GetSystemMetrics(SM_CXSMICON),
3830 GetSystemMetrics(SM_CYSMICON),
3831 LR_SHARED);
3832
3833 Globals.hframeClass = RegisterClassEx(&wcFrame);
3834
3835
3836 /* register tree windows class */
3837
3838 wcChild.style = CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW;
3839 wcChild.lpfnWndProc = ChildWndProc;
3840 wcChild.cbClsExtra = 0;
3841 wcChild.cbWndExtra = 0;
3842 wcChild.hInstance = hinstance;
3843 wcChild.hIcon = 0;
3844 wcChild.hCursor = LoadCursor(0, IDC_ARROW);
3845 wcChild.hbrBackground = 0;
3846 wcChild.lpszMenuName = 0;
3847 wcChild.lpszClassName = sWINEFILETREE;
3848
3849 hChildClass = RegisterClass(&wcChild);
3850
3851
3852 Globals.haccel = LoadAccelerators(hinstance, MAKEINTRESOURCE(IDA_WINEFILE));
3853
3854 Globals.hfont = CreateFont(-MulDiv(8,GetDeviceCaps(hdc,LOGPIXELSY),72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sFont);
3855
3856 ReleaseDC(0, hdc);
3857
3858 Globals.hInstance = hinstance;
3859
3860 #ifdef _SHELL_FOLDERS
3861 CoInitialize(NULL);
3862 CoGetMalloc(MEMCTX_TASK, &Globals.iMalloc);
3863 SHGetDesktopFolder(&Globals.iDesktop);
3864 #ifdef __WINE__
3865 Globals.cfStrFName = RegisterClipboardFormatA(CFSTR_FILENAME);
3866 #else
3867 Globals.cfStrFName = RegisterClipboardFormat(CFSTR_FILENAME);
3868 #endif
3869 #endif
3870
3871 /* load column strings */
3872 col = 0;
3873
3874 load_string(g_pos_names[col++], IDS_COL_NAME);
3875 load_string(g_pos_names[col++], IDS_COL_SIZE);
3876 load_string(g_pos_names[col++], IDS_COL_CDATE);
3877 #ifndef _NO_EXTENSIONS
3878 load_string(g_pos_names[col++], IDS_COL_ADATE);
3879 load_string(g_pos_names[col++], IDS_COL_MDATE);
3880 load_string(g_pos_names[col++], IDS_COL_IDX);
3881 load_string(g_pos_names[col++], IDS_COL_LINKS);
3882 #endif
3883 load_string(g_pos_names[col++], IDS_COL_ATTR);
3884 #ifndef _NO_EXTENSIONS
3885 load_string(g_pos_names[col++], IDS_COL_SEC);
3886 #endif
3887 }
3888
3889
3890 void show_frame(HWND hwndParent, int cmdshow)
3891 {
3892 const static TCHAR sMDICLIENT[] = {'M','D','I','C','L','I','E','N','T','\0'};
3893
3894 TCHAR path[MAX_PATH], b1[BUFFER_LEN];
3895 ChildWnd* child;
3896 HMENU hMenuFrame, hMenuWindow;
3897
3898 CLIENTCREATESTRUCT ccs;
3899
3900 if (Globals.hMainWnd)
3901 return;
3902
3903 Globals.hwndParent = hwndParent;
3904
3905 hMenuFrame = LoadMenu(Globals.hInstance, MAKEINTRESOURCE(IDM_WINEFILE));
3906 hMenuWindow = GetSubMenu(hMenuFrame, GetMenuItemCount(hMenuFrame)-2);
3907
3908 Globals.hMenuFrame = hMenuFrame;
3909 Globals.hMenuView = GetSubMenu(hMenuFrame, 3);
3910 Globals.hMenuOptions = GetSubMenu(hMenuFrame, 4);
3911
3912 ccs.hWindowMenu = hMenuWindow;
3913 ccs.idFirstChild = IDW_FIRST_CHILD;
3914
3915
3916 /* create main window */
3917 Globals.hMainWnd = CreateWindowEx(0, (LPCTSTR)(int)Globals.hframeClass, RS(b1,IDS_WINE_FILE), WS_OVERLAPPEDWINDOW,
3918 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
3919 hwndParent, Globals.hMenuFrame, Globals.hInstance, 0/*lpParam*/);
3920
3921
3922 Globals.hmdiclient = CreateWindowEx(0, sMDICLIENT, NULL,
3923 WS_CHILD|WS_CLIPCHILDREN|WS_VSCROLL|WS_HSCROLL|WS_VISIBLE|WS_BORDER,
3924 0, 0, 0, 0,
3925 Globals.hMainWnd, 0, Globals.hInstance, &ccs);
3926
3927
3928 {
3929 TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0};
3930 int btn = 1;
3931 PTSTR p;
3932
3933 Globals.hdrivebar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE|CCS_NOMOVEY|TBSTYLE_LIST,
3934 IDW_DRIVEBAR, 2, Globals.hInstance, IDB_DRIVEBAR, &drivebarBtn,
3935 1, 16, 13, 16, 13, sizeof(TBBUTTON));
3936 CheckMenuItem(Globals.hMenuOptions, ID_VIEW_DRIVE_BAR, MF_BYCOMMAND|MF_CHECKED);
3937
3938 GetLogicalDriveStrings(BUFFER_LEN, Globals.drives);
3939
3940 drivebarBtn.fsStyle = BTNS_BUTTON;
3941
3942 #ifndef _NO_EXTENSIONS
3943 #ifdef __WINE__
3944 /* insert unix file system button */
3945 b1[0] = '/';
3946 b1[1] = '\0';
3947 b1[2] = '\0';
3948 SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
3949
3950 drivebarBtn.idCommand = ID_DRIVE_UNIX_FS;
3951 SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
3952 drivebarBtn.iString++;
3953 #endif
3954 #ifdef _SHELL_FOLDERS
3955 /* insert shell namespace button */
3956 load_string(b1, IDS_SHELL);
3957 b1[lstrlen(b1)+1] = '\0';
3958 SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
3959
3960 drivebarBtn.idCommand = ID_DRIVE_SHELL_NS;
3961 SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
3962 drivebarBtn.iString++;
3963 #endif
3964
3965 /* register windows drive root strings */
3966 SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)Globals.drives);
3967 #endif
3968
3969 drivebarBtn.idCommand = ID_DRIVE_FIRST;
3970
3971 for(p=Globals.drives; *p; ) {
3972 #ifdef _NO_EXTENSIONS
3973 /* insert drive letter */
3974 TCHAR b[3] = {tolower(*p)};
3975 SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b);
3976 #endif
3977 switch(GetDriveType(p)) {
3978 case DRIVE_REMOVABLE: drivebarBtn.iBitmap = 1; break;
3979 case DRIVE_CDROM: drivebarBtn.iBitmap = 3; break;
3980 case DRIVE_REMOTE: drivebarBtn.iBitmap = 4; break;
3981 case DRIVE_RAMDISK: drivebarBtn.iBitmap = 5; break;
3982 default:/*DRIVE_FIXED*/ drivebarBtn.iBitmap = 2;
3983 }
3984
3985 SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
3986 drivebarBtn.idCommand++;
3987 drivebarBtn.iString++;
3988
3989 while(*p++);
3990 }
3991 }
3992
3993 {
3994 TBBUTTON toolbarBtns[] = {
3995 {0, 0, 0, BTNS_SEP, {0, 0}, 0, 0},
3996 {0, ID_WINDOW_NEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
3997 {1, ID_WINDOW_CASCADE, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
3998 {2, ID_WINDOW_TILE_HORZ, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
3999 {3, ID_WINDOW_TILE_VERT, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4000 /*TODO
4001 {4, ID_... , TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4002 {5, ID_... , TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4003 */ };
4004
4005 Globals.htoolbar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE,
4006 IDW_TOOLBAR, 2, Globals.hInstance, IDB_TOOLBAR, toolbarBtns,
4007 sizeof(toolbarBtns)/sizeof(TBBUTTON), 16, 15, 16, 15, sizeof(TBBUTTON));
4008 CheckMenuItem(Globals.hMenuOptions, ID_VIEW_TOOL_BAR, MF_BYCOMMAND|MF_CHECKED);
4009 }
4010
4011 Globals.hstatusbar = CreateStatusWindow(WS_CHILD|WS_VISIBLE, 0, Globals.hMainWnd, IDW_STATUSBAR);
4012 CheckMenuItem(Globals.hMenuOptions, ID_VIEW_STATUSBAR, MF_BYCOMMAND|MF_CHECKED);
4013
4014 /* CreateStatusWindow does not accept WS_BORDER
4015 Globals.hstatusbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY, STATUSCLASSNAME, 0,
4016 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_BORDER|CCS_NODIVIDER, 0,0,0,0,
4017 Globals.hMainWnd, (HMENU)IDW_STATUSBAR, hinstance, 0);*/
4018
4019 /*TODO: read paths and window placements from registry */
4020 GetCurrentDirectory(MAX_PATH, path);
4021
4022 ShowWindow(Globals.hMainWnd, cmdshow);
4023
4024 //#if defined(_SHELL_FOLDERS) && !defined(__WINE__)
4025 // // Shell Namespace as default:
4026 // child = alloc_child_window(path, get_path_pidl(path,Globals.hMainWnd), Globals.hMainWnd);
4027 //#else
4028 child = alloc_child_window(path, NULL, Globals.hMainWnd);
4029 //#endif
4030
4031 child->pos.showCmd = SW_SHOWMAXIMIZED;
4032 child->pos.rcNormalPosition.left = 0;
4033 child->pos.rcNormalPosition.top = 0;
4034 child->pos.rcNormalPosition.right = 320;
4035 child->pos.rcNormalPosition.bottom = 280;
4036
4037 if (!create_child_window(child))
4038 free(child);
4039
4040 SetWindowPlacement(child->hwnd, &child->pos);
4041
4042 Globals.himl = ImageList_LoadBitmap(Globals.hInstance, MAKEINTRESOURCE(IDB_IMAGES), 16, 0, RGB(0,255,0));
4043
4044 Globals.prescan_node = FALSE;
4045
4046 UpdateWindow(Globals.hMainWnd);
4047 }
4048
4049 void ExitInstance()
4050 {
4051 #ifdef _SHELL_FOLDERS
4052 (*Globals.iDesktop->lpVtbl->Release)(Globals.iDesktop);
4053 (*Globals.iMalloc->lpVtbl->Release)(Globals.iMalloc);
4054 CoUninitialize();
4055 #endif
4056
4057 ImageList_Destroy(Globals.himl);
4058 }
4059
4060
4061 /* search for already running win[e]files */
4062
4063 static int g_foundPrevInstance = 0;
4064
4065 static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lparam)
4066 {
4067 TCHAR cls[128];
4068
4069 GetClassName(hwnd, cls, 128);
4070
4071 if (!lstrcmp(cls, (LPCTSTR)lparam)) {
4072 g_foundPrevInstance++;
4073 return FALSE;
4074 }
4075
4076 return TRUE;
4077 }
4078
4079 /* search for window of given class name to allow only one running instance */
4080 int find_window_class(LPCTSTR classname)
4081 {
4082 EnumWindows(EnumWndProc, (LPARAM)classname);
4083
4084 if (g_foundPrevInstance)
4085 return 1;
4086
4087 return 0;
4088 }
4089
4090
4091 int winefile_main(HINSTANCE hinstance, HWND hwndParent, int cmdshow)
4092 {
4093 MSG msg;
4094
4095 InitInstance(hinstance);
4096
4097 if (cmdshow == SW_SHOWNORMAL)
4098 /*TODO: read window placement from registry */
4099 cmdshow = SW_MAXIMIZE;
4100
4101 show_frame(hwndParent, cmdshow);
4102
4103 while(GetMessage(&msg, 0, 0, 0)) {
4104 if (Globals.hmdiclient && TranslateMDISysAccel(Globals.hmdiclient, &msg))
4105 continue;
4106
4107 if (Globals.hMainWnd && TranslateAccelerator(Globals.hMainWnd, Globals.haccel, &msg))
4108 continue;
4109
4110 TranslateMessage(&msg);
4111 DispatchMessage(&msg);
4112 }
4113
4114 ExitInstance();
4115
4116 return msg.wParam;
4117 }
4118
4119
4120 int APIENTRY WinMain(HINSTANCE hinstance,
4121 HINSTANCE previnstance,
4122 LPSTR cmdline,
4123 int cmdshow)
4124 {
4125 #ifdef _NO_EXTENSIONS
4126 if (find_window_class(sWINEFILEFRAME))
4127 return 1;
4128 #endif
4129
4130 winefile_main(hinstance, 0, cmdshow);
4131
4132 return 0;
4133 }