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