PathAppendA/W: Don't skip '\\' if path is UNC.
[wine/testsucceed.git] / programs / winefile / winefile.c
blob50131cd6977a8adbbed87fb40b9eedc1fddb66e8
1 /*
2 * Winefile
4 * Copyright 2000 Martin Fuchs
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include "winefile.h"
25 #include "resource.h"
28 /* for read_directory_unix() */
29 #if !defined(_NO_EXTENSIONS)
30 #include <dirent.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <time.h>
34 #endif
36 #ifdef _NO_EXTENSIONS
37 #undef _LEFT_FILES
38 #endif
40 #ifndef _MAX_PATH
41 #define _MAX_DRIVE 3
42 #define _MAX_FNAME 256
43 #define _MAX_DIR _MAX_FNAME
44 #define _MAX_EXT _MAX_FNAME
45 #define _MAX_PATH 260
46 #endif
48 WINEFILE_GLOBALS Globals;
50 extern void WineLicense(HWND hWnd);
51 extern void WineWarranty(HWND hWnd);
53 typedef struct _Entry {
54 struct _Entry* next;
55 struct _Entry* down;
56 struct _Entry* up;
58 BOOL expanded;
59 BOOL scanned;
60 int level;
62 WIN32_FIND_DATA data;
64 #ifndef _NO_EXTENSIONS
65 BY_HANDLE_FILE_INFORMATION bhfi;
66 BOOL bhfi_valid;
67 BOOL unix_dir;
68 #endif
69 } Entry;
71 typedef struct {
72 Entry entry;
73 TCHAR path[MAX_PATH];
74 TCHAR volname[_MAX_FNAME];
75 TCHAR fs[_MAX_DIR];
76 DWORD drive_type;
77 DWORD fs_flags;
78 } Root;
80 enum COLUMN_FLAGS {
81 COL_SIZE = 0x01,
82 COL_DATE = 0x02,
83 COL_TIME = 0x04,
84 COL_ATTRIBUTES = 0x08,
85 COL_DOSNAMES = 0x10,
86 #ifdef _NO_EXTENSIONS
87 COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES
88 #else
89 COL_INDEX = 0x20,
90 COL_LINKS = 0x40,
91 COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES|COL_INDEX|COL_LINKS
92 #endif
95 typedef enum {
96 SORT_NAME,
97 SORT_EXT,
98 SORT_SIZE,
99 SORT_DATE
100 } SORT_ORDER;
102 typedef struct {
103 HWND hwnd;
104 #ifndef _NO_EXTENSIONS
105 HWND hwndHeader;
106 #endif
108 #ifndef _NO_EXTENSIONS
109 #define COLUMNS 10
110 #else
111 #define COLUMNS 5
112 #endif
113 int widths[COLUMNS];
114 int positions[COLUMNS+1];
116 BOOL treePane;
117 int visible_cols;
118 Entry* root;
119 Entry* cur;
120 } Pane;
122 typedef struct {
123 HWND hwnd;
124 Pane left;
125 Pane right;
126 int focus_pane; /* 0: left 1: right */
127 WINDOWPLACEMENT pos;
128 int split_pos;
129 BOOL header_wdths_ok;
131 TCHAR path[MAX_PATH];
132 Root root;
134 SORT_ORDER sortOrder;
135 } ChildWnd;
138 static void read_directory(Entry* parent, LPCTSTR path, int sortOrder);
139 static void set_curdir(ChildWnd* child, Entry* entry);
141 LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
142 LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
143 LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
146 static void display_error(HWND hwnd, DWORD error)
148 PTSTR msg;
150 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
151 0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PTSTR)&msg, 0, NULL))
152 MessageBox(hwnd, msg, _T("Winefile"), MB_OK);
153 else
154 MessageBox(hwnd, _T("Error"), _T("Winefile"), MB_OK);
156 LocalFree(msg);
160 static void read_directory_win(Entry* parent, LPCTSTR path)
162 Entry* entry = (Entry*) malloc(sizeof(Entry));
163 int level = parent->level + 1;
164 Entry* last = 0;
165 HANDLE hFind;
166 #ifndef _NO_EXTENSIONS
167 HANDLE hFile;
168 #endif
170 TCHAR buffer[MAX_PATH], *p;
171 for(p=buffer; *path; )
172 *p++ = *path++;
174 lstrcpy(p, _T("\\*"));
176 hFind = FindFirstFile(buffer, &entry->data);
178 if (hFind != INVALID_HANDLE_VALUE) {
179 parent->down = entry;
181 do {
182 entry->down = 0;
183 entry->up = parent;
184 entry->expanded = FALSE;
185 entry->scanned = FALSE;
186 entry->level = level;
188 #ifdef _NO_EXTENSIONS
189 /* hide directory entry "." */
190 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
191 LPCTSTR name = entry->data.cFileName;
193 if (name[0]=='.' && name[1]=='\0')
194 continue;
196 #else
197 entry->unix_dir = FALSE;
198 entry->bhfi_valid = FALSE;
200 lstrcpy(p+1, entry->data.cFileName);
202 hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
203 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
205 if (hFile != INVALID_HANDLE_VALUE) {
206 if (GetFileInformationByHandle(hFile, &entry->bhfi))
207 entry->bhfi_valid = TRUE;
209 CloseHandle(hFile);
211 #endif
213 last = entry;
215 entry = (Entry*) malloc(sizeof(Entry));
217 if (last)
218 last->next = entry;
219 } while(FindNextFile(hFind, &entry->data));
221 last->next = 0;
223 FindClose(hFind);
224 } else
225 parent->down = 0;
227 free(entry);
229 parent->scanned = TRUE;
233 static Entry* find_entry_win(Entry* parent, LPCTSTR name)
235 Entry* entry;
237 for(entry=parent->down; entry; entry=entry->next) {
238 LPCTSTR p = name;
239 LPCTSTR q = entry->data.cFileName;
241 do {
242 if (!*p || *p==_T('\\') || *p==_T('/'))
243 return entry;
244 } while(tolower(*p++) == tolower(*q++));
246 p = name;
247 q = entry->data.cAlternateFileName;
249 do {
250 if (!*p || *p==_T('\\') || *p==_T('/'))
251 return entry;
252 } while(tolower(*p++) == tolower(*q++));
255 return 0;
259 static Entry* read_tree_win(Root* root, LPCTSTR path, int sortOrder)
261 TCHAR buffer[MAX_PATH];
262 Entry* entry = &root->entry;
263 LPCTSTR s = path;
264 PTSTR d = buffer;
266 #ifndef _NO_EXTENSIONS
267 entry->unix_dir = FALSE;
268 #endif
270 while(entry) {
271 while(*s && *s!=_T('\\') && *s!=_T('/'))
272 *d++ = *s++;
274 while(*s==_T('\\') || *s==_T('/'))
275 s++;
277 *d++ = _T('\\');
278 *d = _T('\0');
280 read_directory(entry, buffer, sortOrder);
282 if (entry->down)
283 entry->expanded = TRUE;
285 if (!*s)
286 break;
288 entry = find_entry_win(entry, s);
291 return entry;
295 #if !defined(_NO_EXTENSIONS) && defined(__linux__)
297 BOOL to_filetime(const time_t* t, FILETIME* ftime)
299 struct tm* tm = gmtime(t);
300 SYSTEMTIME stime;
302 if (!tm)
303 return FALSE;
305 stime.wYear = tm->tm_year+1900;
306 stime.wMonth = tm->tm_mon+1;
307 /* stime.wDayOfWeek */
308 stime.wDay = tm->tm_mday;
309 stime.wHour = tm->tm_hour;
310 stime.wMinute = tm->tm_min;
311 stime.wSecond = tm->tm_sec;
313 return SystemTimeToFileTime(&stime, ftime);
316 static void read_directory_unix(Entry* parent, LPCTSTR path)
318 Entry* entry = (Entry*) malloc(sizeof(Entry));
319 int level = parent->level + 1;
320 Entry* last = 0;
322 DIR* dir = opendir(path);
324 if (dir) {
325 struct stat st;
326 struct dirent* ent;
327 TCHAR buffer[MAX_PATH], *p;
329 for(p=buffer; *path; )
330 *p++ = *path++;
332 if (p==buffer || p[-1]!='/')
333 *p++ = '/';
335 parent->down = entry;
337 while((ent=readdir(dir))) {
338 entry->unix_dir = TRUE;
339 lstrcpy(entry->data.cFileName, ent->d_name);
340 entry->data.dwFileAttributes = ent->d_name[0]=='.'? FILE_ATTRIBUTE_HIDDEN: 0;
342 strcpy(p, ent->d_name);
344 if (!stat(buffer, &st)) {
345 if (S_ISDIR(st.st_mode))
346 entry->data.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
348 entry->data.nFileSizeLow = st.st_size & 0xFFFFFFFF;
349 entry->data.nFileSizeHigh = st.st_size >> 32;
351 memset(&entry->data.ftCreationTime, 0, sizeof(FILETIME));
352 to_filetime(&st.st_atime, &entry->data.ftLastAccessTime);
353 to_filetime(&st.st_mtime, &entry->data.ftLastWriteTime);
355 entry->bhfi.nFileIndexLow = ent->d_ino;
356 entry->bhfi.nFileIndexHigh = 0;
358 entry->bhfi.nNumberOfLinks = st.st_nlink;
360 entry->bhfi_valid = TRUE;
361 } else {
362 entry->data.nFileSizeLow = 0;
363 entry->data.nFileSizeHigh = 0;
364 entry->bhfi_valid = FALSE;
367 entry->down = 0;
368 entry->up = parent;
369 entry->expanded = FALSE;
370 entry->scanned = FALSE;
371 entry->level = level;
373 last = entry;
375 entry = (Entry*) malloc(sizeof(Entry));
377 if (last)
378 last->next = entry;
381 last->next = 0;
383 closedir(dir);
384 } else
385 parent->down = 0;
387 free(entry);
389 parent->scanned = TRUE;
392 static Entry* find_entry_unix(Entry* parent, LPCTSTR name)
394 Entry* entry;
396 for(entry=parent->down; entry; entry=entry->next) {
397 LPCTSTR p = name;
398 LPCTSTR q = entry->data.cFileName;
400 do {
401 if (!*p || *p==_T('/'))
402 return entry;
403 } while(*p++ == *q++);
406 return 0;
409 static Entry* read_tree_unix(Root* root, LPCTSTR path, int sortOrder)
411 TCHAR buffer[MAX_PATH];
412 Entry* entry = &root->entry;
413 LPCTSTR s = path;
414 PTSTR d = buffer;
416 entry->unix_dir = TRUE;
418 while(entry) {
419 while(*s && *s!=_T('/'))
420 *d++ = *s++;
422 while(*s == _T('/'))
423 s++;
425 *d++ = _T('/');
426 *d = _T('\0');
428 read_directory(entry, buffer, sortOrder);
430 if (entry->down)
431 entry->expanded = TRUE;
433 if (!*s)
434 break;
436 entry = find_entry_unix(entry, s);
439 return entry;
442 #endif
445 /* directories first... */
446 static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
448 int dir1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
449 int dir2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
451 return dir2==dir1? 0: dir2<dir1? -1: 1;
455 static int compareName(const void* arg1, const void* arg2)
457 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
458 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
460 int cmp = compareType(fd1, fd2);
461 if (cmp)
462 return cmp;
464 return lstrcmpi(fd1->cFileName, fd2->cFileName);
467 static int compareExt(const void* arg1, const void* arg2)
469 const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
470 const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
471 const TCHAR *name1, *name2, *ext1, *ext2;
473 int cmp = compareType(fd1, fd2);
474 if (cmp)
475 return cmp;
477 name1 = fd1->cFileName;
478 name2 = fd2->cFileName;
480 ext1 = _tcsrchr(name1, _T('.'));
481 ext2 = _tcsrchr(name2, _T('.'));
483 if (ext1)
484 ext1++;
485 else
486 ext1 = _T("");
488 if (ext2)
489 ext2++;
490 else
491 ext2 = _T("");
493 cmp = lstrcmpi(ext1, ext2);
494 if (cmp)
495 return cmp;
497 return lstrcmpi(name1, name2);
500 static int compareSize(const void* arg1, const void* arg2)
502 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
503 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
505 int cmp = compareType(fd1, fd2);
506 if (cmp)
507 return cmp;
509 cmp = fd2->nFileSizeHigh - fd1->nFileSizeHigh;
511 if (cmp < 0)
512 return -1;
513 else if (cmp > 0)
514 return 1;
516 cmp = fd2->nFileSizeLow - fd1->nFileSizeLow;
518 return cmp<0? -1: cmp>0? 1: 0;
521 static int compareDate(const void* arg1, const void* arg2)
523 WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
524 WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
526 int cmp = compareType(fd1, fd2);
527 if (cmp)
528 return cmp;
530 return CompareFileTime(&fd2->ftLastWriteTime, &fd1->ftLastWriteTime);
534 static int (*sortFunctions[])(const void* arg1, const void* arg2) = {
535 compareName, /* SORT_NAME */
536 compareExt, /* SORT_EXT */
537 compareSize, /* SORT_SIZE */
538 compareDate /* SORT_DATE */
542 static void SortDirectory(Entry* parent, SORT_ORDER sortOrder)
544 Entry* entry = parent->down;
545 Entry** array, **p;
546 int len;
548 len = 0;
549 for(entry=parent->down; entry; entry=entry->next)
550 len++;
552 if (len) {
553 array = (Entry**) alloca(len*sizeof(Entry*));
555 p = array;
556 for(entry=parent->down; entry; entry=entry->next)
557 *p++ = entry;
559 /* call qsort with the appropriate compare function */
560 qsort(array, len, sizeof(array[0]), sortFunctions[sortOrder]);
562 parent->down = array[0];
564 for(p=array; --len; p++)
565 p[0]->next = p[1];
567 (*p)->next = 0;
572 static void read_directory(Entry* parent, LPCTSTR path, int sortOrder)
574 TCHAR buffer[MAX_PATH];
575 Entry* entry;
576 LPCTSTR s;
577 PTSTR d;
579 #if !defined(_NO_EXTENSIONS) && defined(__linux__)
580 if (parent->unix_dir)
582 read_directory_unix(parent, path);
584 if (Globals.prescan_node) {
585 s = path;
586 d = buffer;
588 while(*s)
589 *d++ = *s++;
591 *d++ = _T('/');
593 for(entry=parent->down; entry; entry=entry->next)
594 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
595 lstrcpy(d, entry->data.cFileName);
596 read_directory_unix(entry, buffer);
597 SortDirectory(entry, sortOrder);
601 else
602 #endif
604 read_directory_win(parent, path);
606 if (Globals.prescan_node) {
607 s = path;
608 d = buffer;
610 while(*s)
611 *d++ = *s++;
613 *d++ = _T('\\');
615 for(entry=parent->down; entry; entry=entry->next)
616 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
617 lstrcpy(d, entry->data.cFileName);
618 read_directory_win(entry, buffer);
619 SortDirectory(entry, sortOrder);
624 SortDirectory(parent, sortOrder);
628 static ChildWnd* alloc_child_window(LPCTSTR path)
630 TCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
631 ChildWnd* child = (ChildWnd*) malloc(sizeof(ChildWnd));
632 Root* root = &child->root;
633 Entry* entry;
635 memset(child, 0, sizeof(ChildWnd));
637 child->left.treePane = TRUE;
638 child->left.visible_cols = 0;
640 child->right.treePane = FALSE;
641 #ifndef _NO_EXTENSIONS
642 child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_INDEX|COL_LINKS;
643 #else
644 child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES;
645 #endif
647 child->pos.length = sizeof(WINDOWPLACEMENT);
648 child->pos.flags = 0;
649 child->pos.showCmd = SW_SHOWNORMAL;
650 child->pos.rcNormalPosition.left = CW_USEDEFAULT;
651 child->pos.rcNormalPosition.top = CW_USEDEFAULT;
652 child->pos.rcNormalPosition.right = CW_USEDEFAULT;
653 child->pos.rcNormalPosition.bottom = CW_USEDEFAULT;
655 child->focus_pane = 0;
656 child->split_pos = 200;
657 child->sortOrder = SORT_NAME;
658 child->header_wdths_ok = FALSE;
660 lstrcpy(child->path, path);
662 _tsplitpath(path, drv, dir, name, ext);
664 #if !defined(_NO_EXTENSIONS) && defined(__linux__)
665 if (*path == '/')
667 root->drive_type = GetDriveType(path);
669 lstrcat(drv, _T("/"));
670 lstrcpy(root->volname, _T("root fs"));
671 root->fs_flags = 0;
672 lstrcpy(root->fs, _T("unixfs"));
674 lstrcpy(root->path, _T("/"));
675 entry = read_tree_unix(root, path, child->sortOrder);
677 else
678 #endif
680 root->drive_type = GetDriveType(path);
682 lstrcat(drv, _T("\\"));
683 GetVolumeInformation(drv, root->volname, _MAX_FNAME, 0, 0, &root->fs_flags, root->fs, _MAX_DIR);
685 lstrcpy(root->path, drv);
686 entry = read_tree_win(root, path, child->sortOrder);
689 /*@@lstrcpy(root->entry.data.cFileName, drv); */
690 wsprintf(root->entry.data.cFileName, _T("%s - %s"), drv, root->fs);
692 root->entry.data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
694 child->left.root = &root->entry;
696 set_curdir(child, entry);
698 return child;
702 /* recursively free all child entries */
703 static void free_entries(Entry* parent)
705 Entry *entry, *next=parent->down;
707 if (next) {
708 parent->down = 0;
710 do {
711 entry = next;
712 next = entry->next;
714 free_entries(entry);
715 free(entry);
716 } while(next);
720 /* free all memory associated with a child window */
721 static void free_child_window(ChildWnd* child)
723 free_entries(&child->root.entry);
724 free(child);
728 /* get full path of specified directory entry */
729 static void get_path(Entry* dir, PTSTR path)
731 Entry* entry;
732 int len = 0;
733 int level = 0;
735 for(entry=dir; entry; level++) {
736 LPCTSTR name = entry->data.cFileName;
737 LPCTSTR s = name;
738 int l;
740 for(l=0; *s && *s!=_T('/') && *s!=_T('\\'); s++)
741 l++;
743 if (entry->up) {
744 memmove(path+l+1, path, len*sizeof(TCHAR));
745 memcpy(path+1, name, l*sizeof(TCHAR));
746 len += l+1;
748 #ifndef _NO_EXTENSIONS
749 if (entry->unix_dir)
750 path[0] = _T('/');
751 else
752 #endif
753 path[0] = _T('\\');
755 entry = entry->up;
756 } else {
757 memmove(path+l, path, len*sizeof(TCHAR));
758 memcpy(path, name, l*sizeof(TCHAR));
759 len += l;
760 break;
764 if (!level) {
765 #ifndef _NO_EXTENSIONS
766 if (entry->unix_dir)
767 path[len++] = _T('/');
768 else
769 #endif
770 path[len++] = _T('\\');
773 path[len] = _T('\0');
777 static void resize_frame_rect(HWND hwnd, PRECT prect)
779 int new_top;
780 RECT rt;
782 if (IsWindowVisible(Globals.htoolbar)) {
783 SendMessage(Globals.htoolbar, WM_SIZE, 0, 0);
784 GetClientRect(Globals.htoolbar, &rt);
785 prect->top = rt.bottom+3;
786 prect->bottom -= rt.bottom+3;
789 if (IsWindowVisible(Globals.hdrivebar)) {
790 SendMessage(Globals.hdrivebar, WM_SIZE, 0, 0);
791 GetClientRect(Globals.hdrivebar, &rt);
792 new_top = --prect->top + rt.bottom+3;
793 MoveWindow(Globals.hdrivebar, 0, prect->top, rt.right, new_top, TRUE);
794 prect->top = new_top;
795 prect->bottom -= rt.bottom+2;
798 if (IsWindowVisible(Globals.hstatusbar)) {
799 int parts[] = {300, 500};
801 SendMessage(Globals.hstatusbar, WM_SIZE, 0, 0);
802 SendMessage(Globals.hstatusbar, SB_SETPARTS, 2, (LPARAM)&parts);
803 GetClientRect(Globals.hstatusbar, &rt);
804 prect->bottom -= rt.bottom;
807 MoveWindow(Globals.hmdiclient, prect->left-1,prect->top-1,prect->right+2,prect->bottom+1, TRUE);
810 static void resize_frame(HWND hwnd, int cx, int cy)
812 RECT rect;
814 rect.left = 0;
815 rect.top = 0;
816 rect.right = cx;
817 rect.bottom = cy;
819 resize_frame_rect(hwnd, &rect);
822 static void resize_frame_client(HWND hwnd)
824 RECT rect;
826 GetClientRect(hwnd, &rect);
828 resize_frame_rect(hwnd, &rect);
832 static HHOOK hcbthook;
833 static ChildWnd* newchild = NULL;
835 LRESULT CALLBACK CBTProc(int code, WPARAM wparam, LPARAM lparam)
837 if (code==HCBT_CREATEWND && newchild) {
838 ChildWnd* child = newchild;
839 newchild = NULL;
841 child->hwnd = (HWND) wparam;
842 SetWindowLong(child->hwnd, GWL_USERDATA, (LPARAM)child);
845 return CallNextHookEx(hcbthook, code, wparam, lparam);
848 static HWND create_child_window(ChildWnd* child)
850 MDICREATESTRUCT mcs;
851 int idx;
853 mcs.szClass = WINEFILETREE;
854 mcs.szTitle = (LPTSTR)child->path;
855 mcs.hOwner = Globals.hInstance;
856 mcs.x = child->pos.rcNormalPosition.left;
857 mcs.y = child->pos.rcNormalPosition.top;
858 mcs.cx = child->pos.rcNormalPosition.right-child->pos.rcNormalPosition.left;
859 mcs.cy = child->pos.rcNormalPosition.bottom-child->pos.rcNormalPosition.top;
860 mcs.style = 0;
861 mcs.lParam = 0;
863 hcbthook = SetWindowsHookEx(WH_CBT, CBTProc, 0, GetCurrentThreadId());
865 newchild = child;
866 child->hwnd = (HWND) SendMessage(Globals.hmdiclient, WM_MDICREATE, 0, (LPARAM)&mcs);
867 if (!child->hwnd)
868 return 0;
870 UnhookWindowsHookEx(hcbthook);
872 idx = ListBox_FindItemData(child->left.hwnd, ListBox_GetCurSel(child->left.hwnd), child->left.cur);
873 ListBox_SetCurSel(child->left.hwnd, idx);
875 return child->hwnd;
879 struct ExecuteDialog {
880 TCHAR cmd[MAX_PATH];
881 int cmdshow;
885 static BOOL CALLBACK ExecuteDialogWndProg(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
887 static struct ExecuteDialog* dlg;
889 switch(nmsg) {
890 case WM_INITDIALOG:
891 dlg = (struct ExecuteDialog*) lparam;
892 return 1;
894 case WM_COMMAND: {
895 int id = (int)wparam;
897 if (id == IDOK) {
898 GetWindowText(GetDlgItem(hwnd, 201), dlg->cmd, MAX_PATH);
899 dlg->cmdshow = Button_GetState(GetDlgItem(hwnd,214))&BST_CHECKED?
900 SW_SHOWMINIMIZED: SW_SHOWNORMAL;
901 EndDialog(hwnd, id);
902 } else if (id == IDCANCEL)
903 EndDialog(hwnd, id);
905 return 1;}
908 return 0;
912 #ifndef _NO_EXTENSIONS
914 static struct FullScreenParameters {
915 BOOL mode;
916 RECT orgPos;
917 BOOL wasZoomed;
918 } g_fullscreen = {
919 FALSE /* mode */
922 void frame_get_clientspace(HWND hwnd, PRECT prect)
924 RECT rt;
926 if (!IsIconic(hwnd))
927 GetClientRect(hwnd, prect);
928 else {
929 WINDOWPLACEMENT wp;
931 GetWindowPlacement(hwnd, &wp);
933 prect->left = prect->top = 0;
934 prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left-
935 2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE));
936 prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top-
937 2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))-
938 GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE);
941 if (IsWindowVisible(Globals.htoolbar)) {
942 GetClientRect(Globals.htoolbar, &rt);
943 prect->top += rt.bottom+2;
946 if (IsWindowVisible(Globals.hdrivebar)) {
947 GetClientRect(Globals.hdrivebar, &rt);
948 prect->top += rt.bottom+2;
951 if (IsWindowVisible(Globals.hstatusbar)) {
952 GetClientRect(Globals.hstatusbar, &rt);
953 prect->bottom -= rt.bottom;
957 static BOOL toggle_fullscreen(HWND hwnd)
959 RECT rt;
961 if ((g_fullscreen.mode=!g_fullscreen.mode)) {
962 GetWindowRect(hwnd, &g_fullscreen.orgPos);
963 g_fullscreen.wasZoomed = IsZoomed(hwnd);
965 Frame_CalcFrameClient(hwnd, &rt);
966 ClientToScreen(hwnd, (LPPOINT)&rt.left);
967 ClientToScreen(hwnd, (LPPOINT)&rt.right);
969 rt.left = g_fullscreen.orgPos.left-rt.left;
970 rt.top = g_fullscreen.orgPos.top-rt.top;
971 rt.right = GetSystemMetrics(SM_CXSCREEN)+g_fullscreen.orgPos.right-rt.right;
972 rt.bottom = GetSystemMetrics(SM_CYSCREEN)+g_fullscreen.orgPos.bottom-rt.bottom;
974 MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
975 } else {
976 MoveWindow(hwnd, g_fullscreen.orgPos.left, g_fullscreen.orgPos.top,
977 g_fullscreen.orgPos.right-g_fullscreen.orgPos.left,
978 g_fullscreen.orgPos.bottom-g_fullscreen.orgPos.top, TRUE);
980 if (g_fullscreen.wasZoomed)
981 ShowWindow(hwnd, WS_MAXIMIZE);
984 return g_fullscreen.mode;
987 static void fullscreen_move(HWND hwnd)
989 RECT rt, pos;
990 GetWindowRect(hwnd, &pos);
992 Frame_CalcFrameClient(hwnd, &rt);
993 ClientToScreen(hwnd, (LPPOINT)&rt.left);
994 ClientToScreen(hwnd, (LPPOINT)&rt.right);
996 rt.left = pos.left-rt.left;
997 rt.top = pos.top-rt.top;
998 rt.right = GetSystemMetrics(SM_CXSCREEN)+pos.right-rt.right;
999 rt.bottom = GetSystemMetrics(SM_CYSCREEN)+pos.bottom-rt.bottom;
1001 MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
1004 #endif
1007 static void toggle_child(HWND hwnd, UINT cmd, HWND hchild)
1009 BOOL vis = IsWindowVisible(hchild);
1011 CheckMenuItem(Globals.hMenuOptions, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
1013 ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
1015 #ifndef _NO_EXTENSIONS
1016 if (g_fullscreen.mode)
1017 fullscreen_move(hwnd);
1018 #endif
1020 resize_frame_client(hwnd);
1023 BOOL activate_drive_window(LPCTSTR path)
1025 TCHAR drv1[_MAX_DRIVE], drv2[_MAX_DRIVE];
1026 HWND child_wnd;
1028 _tsplitpath(path, drv1, 0, 0, 0);
1030 /* search for a already open window for the same drive */
1031 for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
1032 ChildWnd* child = (ChildWnd*) GetWindowLong(child_wnd, GWL_USERDATA);
1034 if (child) {
1035 _tsplitpath(child->root.path, drv2, 0, 0, 0);
1037 if (!lstrcmpi(drv2, drv1)) {
1038 SendMessage(Globals.hmdiclient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
1040 if (IsMinimized(child_wnd))
1041 ShowWindow(child_wnd, SW_SHOWNORMAL);
1043 return TRUE;
1048 return FALSE;
1051 LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1053 switch(nmsg) {
1054 case WM_CLOSE:
1055 DestroyWindow(hwnd);
1056 break;
1058 case WM_DESTROY:
1059 PostQuitMessage(0);
1060 break;
1062 case WM_COMMAND: {
1063 UINT cmd = LOWORD(wparam);
1064 HWND hwndClient = (HWND) SendMessage(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
1066 if (SendMessage(hwndClient, WM_DISPATCH_COMMAND, wparam, lparam))
1067 break;
1069 if (cmd>=ID_DRIVE_FIRST && cmd<=ID_DRIVE_FIRST+0xFF) {
1070 TCHAR drv[_MAX_DRIVE], path[MAX_PATH];
1071 ChildWnd* child;
1072 LPCTSTR root = Globals.drives;
1073 int i;
1075 for(i=cmd-ID_DRIVE_FIRST; i--; root++)
1076 while(*root)
1077 root++;
1079 if (activate_drive_window(root))
1080 return 0;
1082 _tsplitpath(root, drv, 0, 0, 0);
1084 if (!SetCurrentDirectory(drv)) {
1085 display_error(hwnd, GetLastError());
1086 return 0;
1089 GetCurrentDirectory(MAX_PATH, path); /*@@ letztes Verzeichnis pro Laufwerk speichern */
1090 child = alloc_child_window(path);
1092 if (!create_child_window(child))
1093 free(child);
1094 } else switch(cmd) {
1095 case ID_FILE_EXIT:
1096 PostQuitMessage(0);
1097 break;
1099 case ID_WINDOW_NEW: {
1100 TCHAR path[MAX_PATH];
1101 ChildWnd* child;
1103 GetCurrentDirectory(MAX_PATH, path);
1104 child = alloc_child_window(path);
1106 if (!create_child_window(child))
1107 free(child);
1108 break;}
1110 case ID_WINDOW_CASCADE:
1111 SendMessage(Globals.hmdiclient, WM_MDICASCADE, 0, 0);
1112 break;
1114 case ID_WINDOW_TILE_HORZ:
1115 SendMessage(Globals.hmdiclient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
1116 break;
1118 case ID_WINDOW_TILE_VERT:
1119 SendMessage(Globals.hmdiclient, WM_MDITILE, MDITILE_VERTICAL, 0);
1120 break;
1122 case ID_WINDOW_ARRANGE:
1123 SendMessage(Globals.hmdiclient, WM_MDIICONARRANGE, 0, 0);
1124 break;
1126 case ID_VIEW_TOOL_BAR:
1127 toggle_child(hwnd, cmd, Globals.htoolbar);
1128 break;
1130 case ID_VIEW_DRIVE_BAR:
1131 toggle_child(hwnd, cmd, Globals.hdrivebar);
1132 break;
1134 case ID_VIEW_STATUSBAR:
1135 toggle_child(hwnd, cmd, Globals.hstatusbar);
1136 break;
1138 case ID_EXECUTE: {
1139 struct ExecuteDialog dlg = {{0}};
1140 if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_EXECUTE), hwnd, ExecuteDialogWndProg, (LPARAM)&dlg) == IDOK)
1141 ShellExecute(hwnd, _T("open")/*operation*/, dlg.cmd/*file*/, NULL/*parameters*/, NULL/*dir*/, dlg.cmdshow);
1142 break;}
1144 case ID_HELP:
1145 WinHelp(hwnd, _T("winfile"), HELP_INDEX, 0);
1146 break;
1148 #ifndef _NO_EXTENSIONS
1149 case ID_VIEW_FULLSCREEN:
1150 CheckMenuItem(Globals.hMenuOptions, cmd, toggle_fullscreen(hwnd)?MF_CHECKED:0);
1151 break;
1153 #ifdef __linux__
1154 case ID_DRIVE_UNIX_FS: {
1155 TCHAR path[MAX_PATH];
1156 ChildWnd* child;
1158 if (activate_drive_window(_T("/")))
1159 break;
1161 getcwd(path, MAX_PATH);
1162 child = alloc_child_window(path);
1164 if (!create_child_window(child))
1165 free(child);
1166 break;}
1167 #endif
1168 #endif
1170 /*TODO: There are even more menu items! */
1172 #ifndef _NO_EXTENSIONS
1173 case ID_LICENSE:
1174 WineLicense(Globals.hMainWnd);
1175 break;
1177 case ID_NO_WARRANTY:
1178 WineWarranty(Globals.hMainWnd);
1179 break;
1181 case ID_ABOUT_WINE:
1182 ShellAbout(hwnd, _T("WINE"), _T("Winefile"), 0);
1183 break;
1184 #endif
1186 default:
1187 /*@@if (wParam >= PM_FIRST_LANGUAGE && wParam <= PM_LAST_LANGUAGE)
1188 STRING_SelectLanguageByNumber(wParam - PM_FIRST_LANGUAGE);
1189 else */if ((cmd<IDW_FIRST_CHILD || cmd>=IDW_FIRST_CHILD+0x100) &&
1190 (cmd<SC_SIZE || cmd>SC_RESTORE))
1191 MessageBox(hwnd, _T("Not yet implemented"), _T("Winefile"), MB_OK);
1193 return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
1195 break;}
1197 case WM_SIZE:
1198 resize_frame(hwnd, LOWORD(lparam), HIWORD(lparam));
1199 break; /* do not pass message to DefFrameProc */
1201 #ifndef _NO_EXTENSIONS
1202 case WM_GETMINMAXINFO: {
1203 LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
1205 lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
1206 lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
1207 break;}
1209 case FRM_CALC_CLIENT:
1210 frame_get_clientspace(hwnd, (PRECT)lparam);
1211 return TRUE;
1212 #endif
1214 default:
1215 return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
1218 return 0;
1222 const static LPTSTR g_pos_names[COLUMNS] = {
1223 _T(""), /* symbol */
1224 _T("Name"),
1225 _T("Size"),
1226 _T("CDate"),
1227 #ifndef _NO_EXTENSIONS
1228 _T("ADate"),
1229 _T("MDate"),
1230 _T("Index/Inode"),
1231 _T("Links"),
1232 #endif
1233 _T("Attributes"),
1234 #ifndef _NO_EXTENSIONS
1235 _T("Security")
1236 #endif
1239 const static int g_pos_align[] = {
1241 HDF_LEFT, /* Name */
1242 HDF_RIGHT, /* Size */
1243 HDF_LEFT, /* CDate */
1244 #ifndef _NO_EXTENSIONS
1245 HDF_LEFT, /* ADate */
1246 HDF_LEFT, /* MDate */
1247 HDF_LEFT, /* Index */
1248 HDF_CENTER, /* Links */
1249 #endif
1250 HDF_CENTER, /* Attributes */
1251 #ifndef _NO_EXTENSIONS
1252 HDF_LEFT /* Security */
1253 #endif
1256 static void resize_tree(ChildWnd* child, int cx, int cy)
1258 HDWP hdwp = BeginDeferWindowPos(4);
1259 RECT rt;
1261 rt.left = 0;
1262 rt.top = 0;
1263 rt.right = cx;
1264 rt.bottom = cy;
1266 cx = child->split_pos + SPLIT_WIDTH/2;
1268 #ifndef _NO_EXTENSIONS
1270 WINDOWPOS wp;
1271 HD_LAYOUT hdl;
1273 hdl.prc = &rt;
1274 hdl.pwpos = &wp;
1276 Header_Layout(child->left.hwndHeader, &hdl);
1278 DeferWindowPos(hdwp, child->left.hwndHeader, wp.hwndInsertAfter,
1279 wp.x-1, wp.y, child->split_pos-SPLIT_WIDTH/2+1, wp.cy, wp.flags);
1280 DeferWindowPos(hdwp, child->right.hwndHeader, wp.hwndInsertAfter,
1281 rt.left+cx+1, wp.y, wp.cx-cx+2, wp.cy, wp.flags);
1283 #endif
1285 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);
1286 DeferWindowPos(hdwp, child->right.hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
1288 EndDeferWindowPos(hdwp);
1292 #ifndef _NO_EXTENSIONS
1294 static HWND create_header(HWND parent, Pane* pane, int id)
1296 HD_ITEM hdi = {HDI_TEXT|HDI_WIDTH|HDI_FORMAT};
1297 int idx;
1299 HWND hwnd = CreateWindow(WC_HEADER, 0, WS_CHILD|WS_VISIBLE|HDS_HORZ/*TODO: |HDS_BUTTONS + sort orders*/,
1300 0, 0, 0, 0, parent, (HMENU)id, Globals.hInstance, 0);
1301 if (!hwnd)
1302 return 0;
1304 SendMessage(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), FALSE);
1306 for(idx=0; idx<COLUMNS; idx++) {
1307 hdi.pszText = g_pos_names[idx];
1308 hdi.fmt = HDF_STRING | g_pos_align[idx];
1309 hdi.cxy = pane->widths[idx];
1310 Header_InsertItem(hwnd, idx, &hdi);
1313 return hwnd;
1316 #endif
1319 static void init_output(HWND hwnd)
1321 TCHAR b[16];
1322 HFONT old_font;
1323 HDC hdc = GetDC(hwnd);
1325 if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, _T("1000"), 0, b, 16) > 4)
1326 Globals.num_sep = b[1];
1327 else
1328 Globals.num_sep = _T('.');
1330 old_font = SelectFont(hdc, Globals.hfont);
1331 GetTextExtentPoint32(hdc, _T(" "), 1, &Globals.spaceSize);
1332 SelectFont(hdc, old_font);
1333 ReleaseDC(hwnd, hdc);
1336 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol);
1339 /* calculate prefered width for all visible columns */
1341 static BOOL calc_widths(Pane* pane, BOOL anyway)
1343 int col, x, cx, spc=3*Globals.spaceSize.cx;
1344 int entries = ListBox_GetCount(pane->hwnd);
1345 int orgWidths[COLUMNS];
1346 int orgPositions[COLUMNS+1];
1347 HFONT hfontOld;
1348 HDC hdc;
1349 int cnt;
1351 if (!anyway) {
1352 memcpy(orgWidths, pane->widths, sizeof(orgWidths));
1353 memcpy(orgPositions, pane->positions, sizeof(orgPositions));
1356 for(col=0; col<COLUMNS; col++)
1357 pane->widths[col] = 0;
1359 hdc = GetDC(pane->hwnd);
1360 hfontOld = SelectFont(hdc, Globals.hfont);
1362 for(cnt=0; cnt<entries; cnt++) {
1363 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, cnt);
1365 DRAWITEMSTRUCT dis;
1367 dis.CtlType = 0;
1368 dis.CtlID = 0;
1369 dis.itemID = 0;
1370 dis.itemAction = 0;
1371 dis.itemState = 0;
1372 dis.hwndItem = pane->hwnd;
1373 dis.hDC = hdc;
1375 draw_item(pane, &dis, entry, COLUMNS);
1378 SelectObject(hdc, hfontOld);
1379 ReleaseDC(pane->hwnd, hdc);
1381 x = 0;
1382 for(col=0; col<COLUMNS; col++) {
1383 pane->positions[col] = x;
1384 cx = pane->widths[col];
1386 if (cx) {
1387 cx += spc;
1389 if (cx < IMAGE_WIDTH)
1390 cx = IMAGE_WIDTH;
1392 pane->widths[col] = cx;
1395 x += cx;
1398 pane->positions[COLUMNS] = x;
1400 ListBox_SetHorizontalExtent(pane->hwnd, x);
1402 /* no change? */
1403 if (!memcmp(orgWidths, pane->widths, sizeof(orgWidths)))
1404 return FALSE;
1406 /* don't move, if only collapsing an entry */
1407 if (!anyway && pane->widths[0]<orgWidths[0] &&
1408 !memcmp(orgWidths+1, pane->widths+1, sizeof(orgWidths)-sizeof(int))) {
1409 pane->widths[0] = orgWidths[0];
1410 memcpy(pane->positions, orgPositions, sizeof(orgPositions));
1412 return FALSE;
1415 InvalidateRect(pane->hwnd, 0, TRUE);
1417 return TRUE;
1421 /* calculate one prefered column width */
1423 static void calc_single_width(Pane* pane, int col)
1425 HFONT hfontOld;
1426 int x, cx;
1427 int entries = ListBox_GetCount(pane->hwnd);
1428 int cnt;
1429 HDC hdc;
1431 pane->widths[col] = 0;
1433 hdc = GetDC(pane->hwnd);
1434 hfontOld = SelectFont(hdc, Globals.hfont);
1436 for(cnt=0; cnt<entries; cnt++) {
1437 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, cnt);
1438 DRAWITEMSTRUCT dis;
1440 dis.CtlType = 0;
1441 dis.CtlID = 0;
1442 dis.itemID = 0;
1443 dis.itemAction = 0;
1444 dis.itemState = 0;
1445 dis.hwndItem = pane->hwnd;
1446 dis.hDC = hdc;
1448 draw_item(pane, &dis, entry, col);
1451 SelectObject(hdc, hfontOld);
1452 ReleaseDC(pane->hwnd, hdc);
1454 cx = pane->widths[col];
1456 if (cx) {
1457 cx += 3*Globals.spaceSize.cx;
1459 if (cx < IMAGE_WIDTH)
1460 cx = IMAGE_WIDTH;
1463 pane->widths[col] = cx;
1465 x = pane->positions[col] + cx;
1467 for(; col<COLUMNS; ) {
1468 pane->positions[++col] = x;
1469 x += pane->widths[col];
1472 ListBox_SetHorizontalExtent(pane->hwnd, x);
1476 /* insert listbox entries after index idx */
1478 static void insert_entries(Pane* pane, Entry* parent, int idx)
1480 Entry* entry = parent;
1482 if (!entry)
1483 return;
1485 ShowWindow(pane->hwnd, SW_HIDE);
1487 for(; entry; entry=entry->next) {
1488 #ifndef _LEFT_FILES
1489 if (pane->treePane && !(entry->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
1490 continue;
1491 #endif
1493 /* don't display entries "." and ".." in the left pane */
1494 if (pane->treePane && (entry->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
1495 && entry->data.cFileName[0]==_T('.'))
1496 if (
1497 #ifndef _NO_EXTENSIONS
1498 entry->data.cFileName[1]==_T('\0') ||
1499 #endif
1500 (entry->data.cFileName[1]==_T('.') && entry->data.cFileName[2]==_T('\0')))
1501 continue;
1503 if (idx != -1)
1504 idx++;
1506 ListBox_InsertItemData(pane->hwnd, idx, entry);
1508 if (pane->treePane && entry->expanded)
1509 insert_entries(pane, entry->down, idx);
1512 ShowWindow(pane->hwnd, SW_SHOW);
1516 static WNDPROC g_orgTreeWndProc;
1518 static void create_tree_window(HWND parent, Pane* pane, int id, int id_header)
1520 static int s_init = 0;
1521 Entry* entry = pane->root;
1523 pane->hwnd = CreateWindow(_T("ListBox"), _T(""), WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
1524 LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED|LBS_NOTIFY,
1525 0, 0, 0, 0, parent, (HMENU)id, Globals.hInstance, 0);
1527 SetWindowLong(pane->hwnd, GWL_USERDATA, (LPARAM)pane);
1528 g_orgTreeWndProc = SubclassWindow(pane->hwnd, TreeWndProc);
1530 SendMessage(pane->hwnd, WM_SETFONT, (WPARAM)Globals.hfont, FALSE);
1532 /* insert entries into listbox */
1533 if (entry)
1534 insert_entries(pane, entry, -1);
1536 /* calculate column widths */
1537 if (!s_init) {
1538 s_init = 1;
1539 init_output(pane->hwnd);
1542 calc_widths(pane, TRUE);
1544 #ifndef _NO_EXTENSIONS
1545 pane->hwndHeader = create_header(parent, pane, id_header);
1546 #endif
1550 static void InitChildWindow(ChildWnd* child)
1552 create_tree_window(child->hwnd, &child->left, IDW_TREE_LEFT, IDW_HEADER_LEFT);
1553 create_tree_window(child->hwnd, &child->right, IDW_TREE_RIGHT, IDW_HEADER_RIGHT);
1557 static void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols)
1559 SYSTEMTIME systime;
1560 FILETIME lft;
1561 int len = 0;
1563 *buffer = _T('\0');
1565 if (!ft->dwLowDateTime && !ft->dwHighDateTime)
1566 return;
1568 if (!FileTimeToLocalFileTime(ft, &lft))
1569 {err: _tcscpy(buffer,_T("???")); return;}
1571 if (!FileTimeToSystemTime(&lft, &systime))
1572 goto err;
1574 if (visible_cols & COL_DATE) {
1575 len = GetDateFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer, BUFFER_LEN);
1576 if (!len)
1577 goto err;
1580 if (visible_cols & COL_TIME) {
1581 if (len)
1582 buffer[len-1] = ' ';
1584 buffer[len++] = ' ';
1586 if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer+len, BUFFER_LEN-len))
1587 buffer[len] = _T('\0');
1592 static void calc_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
1594 RECT rt = {0};
1596 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
1598 if (rt.right > pane->widths[col])
1599 pane->widths[col] = rt.right;
1602 static void calc_tabbed_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
1604 RECT rt = {0};
1606 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
1607 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
1609 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
1610 /*@@ rt (0,0) ??? */
1612 if (rt.right > pane->widths[col])
1613 pane->widths[col] = rt.right;
1617 static void output_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str, DWORD flags)
1619 int x = dis->rcItem.left;
1620 RECT rt;
1622 rt.left = x+pane->positions[col]+Globals.spaceSize.cx;
1623 rt.top = dis->rcItem.top;
1624 rt.right = x+pane->positions[col+1]-Globals.spaceSize.cx;
1625 rt.bottom = dis->rcItem.bottom;
1627 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|flags);
1630 static void output_tabbed_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
1632 int x = dis->rcItem.left;
1633 RECT rt;
1635 rt.left = x+pane->positions[col]+Globals.spaceSize.cx;
1636 rt.top = dis->rcItem.top;
1637 rt.right = x+pane->positions[col+1]-Globals.spaceSize.cx;
1638 rt.bottom = dis->rcItem.bottom;
1640 /* DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
1641 DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
1643 DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
1646 static void output_number(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
1648 int x = dis->rcItem.left;
1649 RECT rt;
1650 LPCTSTR s = str;
1651 TCHAR b[128];
1652 LPTSTR d = b;
1653 int pos;
1655 rt.left = x+pane->positions[col]+Globals.spaceSize.cx;
1656 rt.top = dis->rcItem.top;
1657 rt.right = x+pane->positions[col+1]-Globals.spaceSize.cx;
1658 rt.bottom = dis->rcItem.bottom;
1660 if (*s)
1661 *d++ = *s++;
1663 /* insert number separator characters */
1664 pos = lstrlen(s) % 3;
1666 while(*s)
1667 if (pos--)
1668 *d++ = *s++;
1669 else {
1670 *d++ = Globals.num_sep;
1671 pos = 3;
1674 DrawText(dis->hDC, b, d-b, &rt, DT_RIGHT|DT_SINGLELINE|DT_NOPREFIX|DT_END_ELLIPSIS);
1678 static int is_exe_file(LPCTSTR ext)
1680 const static LPCTSTR executable_extensions[] = {
1681 _T("COM"),
1682 _T("EXE"),
1683 _T("BAT"),
1684 _T("CMD"),
1685 #ifndef _NO_EXTENSIONS
1686 _T("CMM"),
1687 _T("BTM"),
1688 _T("AWK"),
1689 #endif
1693 TCHAR ext_buffer[_MAX_EXT];
1694 const LPCTSTR* p;
1695 LPCTSTR s;
1696 LPTSTR d;
1698 for(s=ext+1,d=ext_buffer; (*d=tolower(*s)); s++)
1699 d++;
1701 for(p=executable_extensions; *p; p++)
1702 if (!_tcscmp(ext_buffer, *p))
1703 return 1;
1705 return 0;
1708 static int is_registered_type(LPCTSTR ext)
1710 /* TODO */
1712 return 1;
1716 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
1718 TCHAR buffer[BUFFER_LEN];
1719 DWORD attrs;
1720 int visible_cols = pane->visible_cols;
1721 COLORREF bkcolor, textcolor;
1722 RECT focusRect = dis->rcItem;
1723 HBRUSH hbrush;
1724 enum IMAGE img;
1725 #ifndef _NO_EXTENSIONS
1726 QWORD index;
1727 #endif
1728 int img_pos, cx;
1729 int col = 0;
1731 if (entry) {
1732 attrs = entry->data.dwFileAttributes;
1734 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
1735 if (entry->data.cFileName[0]==_T('.') && entry->data.cFileName[1]==_T('.')
1736 && entry->data.cFileName[2]==_T('\0'))
1737 img = IMG_FOLDER_UP;
1738 #ifndef _NO_EXTENSIONS
1739 else if (entry->data.cFileName[0]==_T('.') && entry->data.cFileName[1]==_T('\0'))
1740 img = IMG_FOLDER_CUR;
1741 #endif
1742 else if (
1743 #ifdef _NO_EXTENSIONS
1744 entry->expanded ||
1745 #endif
1746 (pane->treePane && (dis->itemState&ODS_FOCUS)))
1747 img = IMG_OPEN_FOLDER;
1748 else
1749 img = IMG_FOLDER;
1750 } else {
1751 LPCTSTR ext = _tcsrchr(entry->data.cFileName, '.');
1752 if (!ext)
1753 ext = _T("");
1755 if (is_exe_file(ext))
1756 img = IMG_EXECUTABLE;
1757 else if (is_registered_type(ext))
1758 img = IMG_DOCUMENT;
1759 else
1760 img = IMG_FILE;
1762 } else {
1763 attrs = 0;
1764 img = IMG_NONE;
1767 if (pane->treePane) {
1768 if (entry) {
1769 img_pos = dis->rcItem.left + entry->level*(IMAGE_WIDTH+Globals.spaceSize.cx);
1771 if (calcWidthCol == -1) {
1772 int x;
1773 int y = dis->rcItem.top + IMAGE_HEIGHT/2;
1774 Entry* up;
1775 RECT rt_clip;
1776 HRGN hrgn_org = CreateRectRgn(0, 0, 0, 0);
1777 HRGN hrgn;
1779 rt_clip.left = dis->rcItem.left;
1780 rt_clip.top = dis->rcItem.top;
1781 rt_clip.right = dis->rcItem.left+pane->widths[col];
1782 rt_clip.bottom = dis->rcItem.bottom;
1784 hrgn = CreateRectRgnIndirect(&rt_clip);
1786 if (!GetClipRgn(dis->hDC, hrgn_org)) {
1787 DeleteObject(hrgn_org);
1788 hrgn_org = 0;
1791 /* HGDIOBJ holdPen = SelectObject(dis->hDC, GetStockObject(BLACK_PEN)); */
1792 ExtSelectClipRgn(dis->hDC, hrgn, RGN_AND);
1793 DeleteObject(hrgn);
1795 if ((up=entry->up) != NULL) {
1796 MoveToEx(dis->hDC, img_pos-IMAGE_WIDTH/2, y, 0);
1797 LineTo(dis->hDC, img_pos-2, y);
1799 x = img_pos - IMAGE_WIDTH/2;
1801 do {
1802 x -= IMAGE_WIDTH+Globals.spaceSize.cx;
1804 if (up->next
1805 #ifndef _LEFT_FILES
1806 && (up->next->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
1807 #endif
1809 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
1810 LineTo(dis->hDC, x, dis->rcItem.bottom);
1812 } while((up=up->up) != NULL);
1815 x = img_pos - IMAGE_WIDTH/2;
1817 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
1818 LineTo(dis->hDC, x, y);
1820 if (entry->next
1821 #ifndef _LEFT_FILES
1822 && (entry->next->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
1823 #endif
1825 LineTo(dis->hDC, x, dis->rcItem.bottom);
1827 if (entry->down && entry->expanded) {
1828 x += IMAGE_WIDTH+Globals.spaceSize.cx;
1829 MoveToEx(dis->hDC, x, dis->rcItem.top+IMAGE_HEIGHT, 0);
1830 LineTo(dis->hDC, x, dis->rcItem.bottom);
1833 SelectClipRgn(dis->hDC, hrgn_org);
1834 if (hrgn_org) DeleteObject(hrgn_org);
1835 /* SelectObject(dis->hDC, holdPen); */
1836 } else if (calcWidthCol==col || calcWidthCol==COLUMNS) {
1837 int right = img_pos + IMAGE_WIDTH - Globals.spaceSize.cx;
1839 if (right > pane->widths[col])
1840 pane->widths[col] = right;
1842 } else {
1843 img_pos = dis->rcItem.left;
1845 } else {
1846 img_pos = dis->rcItem.left;
1848 if (calcWidthCol==col || calcWidthCol==COLUMNS)
1849 pane->widths[col] = IMAGE_WIDTH;
1852 if (calcWidthCol == -1) {
1853 focusRect.left = img_pos -2;
1855 #ifdef _NO_EXTENSIONS
1856 if (pane->treePane && entry) {
1857 RECT rt = {0};
1859 DrawText(dis->hDC, entry->data.cFileName, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
1861 focusRect.right = dis->rcItem.left+pane->positions[col+1]+Globals.spaceSize.cx + rt.right +2;
1863 #else
1865 if (attrs & FILE_ATTRIBUTE_COMPRESSED)
1866 textcolor = COLOR_COMPRESSED;
1867 else
1868 #endif
1869 textcolor = RGB(0,0,0);
1871 if (dis->itemState & ODS_FOCUS) {
1872 textcolor = RGB(255,255,255);
1873 bkcolor = COLOR_SELECTION;
1874 } else {
1875 bkcolor = RGB(255,255,255);
1878 hbrush = CreateSolidBrush(bkcolor);
1879 FillRect(dis->hDC, &focusRect, hbrush);
1880 DeleteObject(hbrush);
1882 SetBkMode(dis->hDC, TRANSPARENT);
1883 SetTextColor(dis->hDC, textcolor);
1885 cx = pane->widths[col];
1887 if (cx && img!=IMG_NONE) {
1888 if (cx > IMAGE_WIDTH)
1889 cx = IMAGE_WIDTH;
1891 ImageList_DrawEx(Globals.himl, img, dis->hDC,
1892 img_pos, dis->rcItem.top, cx,
1893 IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
1897 if (!entry)
1898 return;
1900 #ifdef _NO_EXTENSIONS
1901 if (img >= IMG_FOLDER_UP)
1902 return;
1903 #endif
1905 col++;
1907 /* ouput file name */
1908 if (calcWidthCol == -1)
1909 output_text(pane, dis, col, entry->data.cFileName, 0);
1910 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
1911 calc_width(pane, dis, col, entry->data.cFileName);
1913 col++;
1915 #ifdef _NO_EXTENSIONS
1916 if (!pane->treePane) {
1917 #endif
1919 /* display file size */
1920 if (visible_cols & COL_SIZE) {
1921 #ifdef _NO_EXTENSIONS
1922 if (!(attrs&FILE_ATTRIBUTE_DIRECTORY))
1923 #endif
1925 QWORD size;
1927 *(DWORD*)(&size) = entry->data.nFileSizeLow; /*TODO: platform spefific */
1928 *(((DWORD*)&size)+1) = entry->data.nFileSizeHigh;
1930 _stprintf(buffer, _T("%") LONGLONGARG _T("d"), size);
1932 if (calcWidthCol == -1)
1933 output_number(pane, dis, col, buffer);
1934 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
1935 calc_width(pane, dis, col, buffer);/*TODO: not ever time enough */
1938 col++;
1941 /* display file date */
1942 if (visible_cols & (COL_DATE|COL_TIME)) {
1943 #ifndef _NO_EXTENSIONS
1944 format_date(&entry->data.ftCreationTime, buffer, visible_cols);
1945 if (calcWidthCol == -1)
1946 output_text(pane, dis, col, buffer, 0);
1947 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
1948 calc_width(pane, dis, col, buffer);
1949 col++;
1951 format_date(&entry->data.ftLastAccessTime, buffer, visible_cols);
1952 if (calcWidthCol == -1)
1953 output_text(pane, dis, col, buffer, 0);
1954 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
1955 calc_width(pane, dis, col, buffer);
1956 col++;
1957 #endif
1959 format_date(&entry->data.ftLastWriteTime, buffer, visible_cols);
1960 if (calcWidthCol == -1)
1961 output_text(pane, dis, col, buffer, 0);
1962 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
1963 calc_width(pane, dis, col, buffer);
1964 col++;
1967 #ifndef _NO_EXTENSIONS
1968 if (entry->bhfi_valid) {
1969 ((DWORD*)&index)[0] = entry->bhfi.nFileIndexLow; /*TODO: platform spefific */
1970 ((DWORD*)&index)[1] = entry->bhfi.nFileIndexHigh;
1972 if (visible_cols & COL_INDEX) {
1973 _stprintf(buffer, _T("%") LONGLONGARG _T("X"), index);
1974 if (calcWidthCol == -1)
1975 output_text(pane, dis, col, buffer, DT_RIGHT);
1976 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
1977 calc_width(pane, dis, col, buffer);
1978 col++;
1981 if (visible_cols & COL_LINKS) {
1982 wsprintf(buffer, _T("%d"), entry->bhfi.nNumberOfLinks);
1983 if (calcWidthCol == -1)
1984 output_text(pane, dis, col, buffer, DT_CENTER);
1985 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
1986 calc_width(pane, dis, col, buffer);
1987 col++;
1989 } else
1990 col += 2;
1991 #endif
1993 /* show file attributes */
1994 if (visible_cols & COL_ATTRIBUTES) {
1995 #ifdef _NO_EXTENSIONS
1996 _tcscpy(buffer, _T(" \t \t \t \t "));
1997 #else
1998 _tcscpy(buffer, _T(" \t \t \t \t \t \t \t \t \t \t \t "));
1999 #endif
2001 if (attrs & FILE_ATTRIBUTE_NORMAL) buffer[ 0] = 'N';
2002 else {
2003 if (attrs & FILE_ATTRIBUTE_READONLY) buffer[ 2] = 'R';
2004 if (attrs & FILE_ATTRIBUTE_HIDDEN) buffer[ 4] = 'H';
2005 if (attrs & FILE_ATTRIBUTE_SYSTEM) buffer[ 6] = 'S';
2006 if (attrs & FILE_ATTRIBUTE_ARCHIVE) buffer[ 8] = 'A';
2007 if (attrs & FILE_ATTRIBUTE_COMPRESSED) buffer[10] = 'C';
2008 #ifndef _NO_EXTENSIONS
2009 if (attrs & FILE_ATTRIBUTE_DIRECTORY) buffer[12] = 'D';
2010 if (attrs & FILE_ATTRIBUTE_ENCRYPTED) buffer[14] = 'E';
2011 if (attrs & FILE_ATTRIBUTE_TEMPORARY) buffer[16] = 'T';
2012 if (attrs & FILE_ATTRIBUTE_SPARSE_FILE) buffer[18] = 'P';
2013 if (attrs & FILE_ATTRIBUTE_REPARSE_POINT) buffer[20] = 'Q';
2014 if (attrs & FILE_ATTRIBUTE_OFFLINE) buffer[22] = 'O';
2015 if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) buffer[24] = 'X';
2016 #endif
2019 if (calcWidthCol == -1)
2020 output_tabbed_text(pane, dis, col, buffer);
2021 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
2022 calc_tabbed_width(pane, dis, col, buffer);
2024 col++;
2027 /*TODO
2028 if (flags.security) {
2029 DWORD rights = get_access_mask();
2031 tcscpy(buffer, _T(" \t \t \t \t \t \t \t \t \t \t \t "));
2033 if (rights & FILE_READ_DATA) buffer[ 0] = 'R';
2034 if (rights & FILE_WRITE_DATA) buffer[ 2] = 'W';
2035 if (rights & FILE_APPEND_DATA) buffer[ 4] = 'A';
2036 if (rights & FILE_READ_EA) {buffer[6] = 'entry'; buffer[ 7] = 'R';}
2037 if (rights & FILE_WRITE_EA) {buffer[9] = 'entry'; buffer[10] = 'W';}
2038 if (rights & FILE_EXECUTE) buffer[12] = 'X';
2039 if (rights & FILE_DELETE_CHILD) buffer[14] = 'D';
2040 if (rights & FILE_READ_ATTRIBUTES) {buffer[16] = 'a'; buffer[17] = 'R';}
2041 if (rights & FILE_WRITE_ATTRIBUTES) {buffer[19] = 'a'; buffer[20] = 'W';}
2042 if (rights & WRITE_DAC) buffer[22] = 'C';
2043 if (rights & WRITE_OWNER) buffer[24] = 'O';
2044 if (rights & SYNCHRONIZE) buffer[26] = 'S';
2046 output_text(dis, col++, buffer, DT_LEFT, 3, psize);
2049 if (flags.description) {
2050 get_description(buffer);
2051 output_text(dis, col++, buffer, 0, psize);
2055 #ifdef _NO_EXTENSIONS
2058 /* draw focus frame */
2059 if ((dis->itemState&ODS_FOCUS) && calcWidthCol==-1) {
2060 /* Currently [04/2000] Wine neither behaves exactly the same */
2061 /* way as WIN 95 nor like Windows NT... */
2062 HGDIOBJ lastBrush;
2063 HPEN lastPen;
2064 HPEN hpen;
2066 if (!(GetVersion() & 0x80000000)) { /* Windows NT? */
2067 LOGBRUSH lb = {PS_SOLID, RGB(255,255,255)};
2068 hpen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
2069 } else
2070 hpen = CreatePen(PS_DOT, 0, RGB(255,255,255));
2072 lastPen = SelectPen(dis->hDC, hpen);
2073 lastBrush = SelectObject(dis->hDC, GetStockObject(HOLLOW_BRUSH));
2074 SetROP2(dis->hDC, R2_XORPEN);
2075 Rectangle(dis->hDC, focusRect.left, focusRect.top, focusRect.right, focusRect.bottom);
2076 SelectObject(dis->hDC, lastBrush);
2077 SelectObject(dis->hDC, lastPen);
2078 DeleteObject(hpen);
2080 #endif
2084 #ifdef _NO_EXTENSIONS
2086 static void draw_splitbar(HWND hwnd, int x)
2088 RECT rt;
2089 HDC hdc = GetDC(hwnd);
2091 GetClientRect(hwnd, &rt);
2093 rt.left = x - SPLIT_WIDTH/2;
2094 rt.right = x + SPLIT_WIDTH/2+1;
2096 InvertRect(hdc, &rt);
2098 ReleaseDC(hwnd, hdc);
2101 #endif
2104 #ifndef _NO_EXTENSIONS
2106 static void set_header(Pane* pane)
2108 HD_ITEM item;
2109 int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
2110 int i=0, x=0;
2112 item.mask = HDI_WIDTH;
2113 item.cxy = 0;
2115 for(; x+pane->widths[i]<scroll_pos && i<COLUMNS; i++) {
2116 x += pane->widths[i];
2117 Header_SetItem(pane->hwndHeader, i, &item);
2120 if (i < COLUMNS) {
2121 x += pane->widths[i];
2122 item.cxy = x - scroll_pos;
2123 Header_SetItem(pane->hwndHeader, i++, &item);
2125 for(; i<COLUMNS; i++) {
2126 item.cxy = pane->widths[i];
2127 x += pane->widths[i];
2128 Header_SetItem(pane->hwndHeader, i, &item);
2133 static LRESULT pane_notify(Pane* pane, NMHDR* pnmh)
2135 switch(pnmh->code) {
2136 case HDN_TRACK:
2137 case HDN_ENDTRACK: {
2138 HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
2139 int idx = phdn->iItem;
2140 int dx = phdn->pitem->cxy - pane->widths[idx];
2141 int i;
2143 RECT clnt;
2144 GetClientRect(pane->hwnd, &clnt);
2146 /* move immediate to simulate HDS_FULLDRAG (for now [04/2000] not realy needed with WINELIB) */
2147 Header_SetItem(pane->hwndHeader, idx, phdn->pitem);
2149 pane->widths[idx] += dx;
2151 for(i=idx; ++i<=COLUMNS; )
2152 pane->positions[i] += dx;
2155 int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
2156 RECT rt_scr;
2157 RECT rt_clip;
2159 rt_scr.left = pane->positions[idx+1]-scroll_pos;
2160 rt_scr.top = 0;
2161 rt_scr.right = clnt.right;
2162 rt_scr.bottom = clnt.bottom;
2164 rt_clip.left = pane->positions[idx]-scroll_pos;
2165 rt_clip.top = 0;
2166 rt_clip.right = clnt.right;
2167 rt_clip.bottom = clnt.bottom;
2169 if (rt_scr.left < 0) rt_scr.left = 0;
2170 if (rt_clip.left < 0) rt_clip.left = 0;
2172 ScrollWindowEx(pane->hwnd, dx, 0, &rt_scr, &rt_clip, 0, 0, SW_INVALIDATE);
2174 rt_clip.right = pane->positions[idx+1];
2175 RedrawWindow(pane->hwnd, &rt_clip, 0, RDW_INVALIDATE|RDW_UPDATENOW);
2177 if (pnmh->code == HDN_ENDTRACK) {
2178 ListBox_SetHorizontalExtent(pane->hwnd, pane->positions[COLUMNS]);
2180 if (GetScrollPos(pane->hwnd, SB_HORZ) != scroll_pos)
2181 set_header(pane);
2185 return FALSE;
2188 case HDN_DIVIDERDBLCLICK: {
2189 HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
2190 HD_ITEM item;
2192 calc_single_width(pane, phdn->iItem);
2193 item.mask = HDI_WIDTH;
2194 item.cxy = pane->widths[phdn->iItem];
2196 Header_SetItem(pane->hwndHeader, phdn->iItem, &item);
2197 InvalidateRect(pane->hwnd, 0, TRUE);
2198 break;}
2201 return 0;
2204 #endif
2207 static void scan_entry(ChildWnd* child, Entry* entry)
2209 TCHAR path[MAX_PATH];
2210 int idx = ListBox_GetCurSel(child->left.hwnd);
2211 HCURSOR crsrOld = SetCursor(LoadCursor(0, IDC_WAIT));
2213 /* delete sub entries in left pane */
2214 for(;;) {
2215 LRESULT res = ListBox_GetItemData(child->left.hwnd, idx+1);
2216 Entry* sub = (Entry*) res;
2218 if (res==LB_ERR || !sub || sub->level<=entry->level)
2219 break;
2221 ListBox_DeleteString(child->left.hwnd, idx+1);
2224 /* empty right pane */
2225 ListBox_ResetContent(child->right.hwnd);
2227 /* release memory */
2228 free_entries(entry);
2230 /* read contents from disk */
2231 get_path(entry, path);
2232 read_directory(entry, path, child->sortOrder);
2234 /* insert found entries in right pane */
2235 insert_entries(&child->right, entry->down, -1);
2236 calc_widths(&child->right, FALSE);
2237 #ifndef _NO_EXTENSIONS
2238 set_header(&child->right);
2239 #endif
2241 child->header_wdths_ok = FALSE;
2243 SetCursor(crsrOld);
2247 /* expand a directory entry */
2249 static BOOL expand_entry(ChildWnd* child, Entry* dir)
2251 int idx;
2252 Entry* p;
2254 if (!dir || dir->expanded || !dir->down)
2255 return FALSE;
2257 p = dir->down;
2259 if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='\0' && p->next) {
2260 p = p->next;
2262 if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='.' &&
2263 p->data.cFileName[2]=='\0' && p->next)
2264 p = p->next;
2267 /* no subdirectories ? */
2268 if (!(p->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
2269 return FALSE;
2271 idx = ListBox_FindItemData(child->left.hwnd, 0, dir);
2273 dir->expanded = TRUE;
2275 /* insert entries in left pane */
2276 insert_entries(&child->left, p, idx);
2278 if (!child->header_wdths_ok) {
2279 if (calc_widths(&child->left, FALSE)) {
2280 #ifndef _NO_EXTENSIONS
2281 set_header(&child->left);
2282 #endif
2284 child->header_wdths_ok = TRUE;
2288 return TRUE;
2292 static void collapse_entry(Pane* pane, Entry* dir)
2294 int idx = ListBox_FindItemData(pane->hwnd, 0, dir);
2296 ShowWindow(pane->hwnd, SW_HIDE);
2298 /* hide sub entries */
2299 for(;;) {
2300 LRESULT res = ListBox_GetItemData(pane->hwnd, idx+1);
2301 Entry* sub = (Entry*) res;
2303 if (res==LB_ERR || !sub || sub->level<=dir->level)
2304 break;
2306 ListBox_DeleteString(pane->hwnd, idx+1);
2309 dir->expanded = FALSE;
2311 ShowWindow(pane->hwnd, SW_SHOW);
2315 static void set_curdir(ChildWnd* child, Entry* entry)
2317 TCHAR path[MAX_PATH];
2319 child->left.cur = entry;
2320 child->right.root = entry;
2321 child->right.cur = entry;
2323 if (!entry->scanned)
2324 scan_entry(child, entry);
2325 else {
2326 ListBox_ResetContent(child->right.hwnd);
2327 insert_entries(&child->right, entry->down, -1);
2328 calc_widths(&child->right, FALSE);
2329 #ifndef _NO_EXTENSIONS
2330 set_header(&child->right);
2331 #endif
2334 get_path(entry, path);
2335 lstrcpy(child->path, path);
2336 SetWindowText(child->hwnd, path);
2337 SetCurrentDirectory(path);
2341 static void activate_entry(ChildWnd* child, Pane* pane)
2343 Entry* entry = pane->cur;
2345 if (!entry)
2346 return;
2348 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2349 int scanned_old = entry->scanned;
2351 if (!scanned_old)
2352 scan_entry(child, entry);
2354 #ifndef _NO_EXTENSIONS
2355 if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='\0')
2356 return;
2357 #endif
2359 if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='.' && entry->data.cFileName[2]=='\0') {
2360 entry = child->left.cur->up;
2361 collapse_entry(&child->left, entry);
2362 goto focus_entry;
2363 } else if (entry->expanded)
2364 collapse_entry(pane, child->left.cur);
2365 else {
2366 expand_entry(child, child->left.cur);
2368 if (!pane->treePane) focus_entry: {
2369 int idx = ListBox_FindItemData(child->left.hwnd, ListBox_GetCurSel(child->left.hwnd), entry);
2370 ListBox_SetCurSel(child->left.hwnd, idx);
2371 set_curdir(child, entry);
2375 if (!scanned_old) {
2376 calc_widths(pane, FALSE);
2378 #ifndef _NO_EXTENSIONS
2379 set_header(pane);
2380 #endif
2382 } else {
2384 /*TODO: start program, open document... */
2390 static BOOL pane_command(Pane* pane, UINT cmd)
2392 switch(cmd) {
2393 case ID_VIEW_NAME:
2394 if (pane->visible_cols) {
2395 pane->visible_cols = 0;
2396 calc_widths(pane, TRUE);
2397 #ifndef _NO_EXTENSIONS
2398 set_header(pane);
2399 #endif
2400 InvalidateRect(pane->hwnd, 0, TRUE);
2401 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND|MF_CHECKED);
2402 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND);
2403 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
2405 break;
2407 case ID_VIEW_ALL_ATTRIBUTES:
2408 if (pane->visible_cols != COL_ALL) {
2409 pane->visible_cols = COL_ALL;
2410 calc_widths(pane, TRUE);
2411 #ifndef _NO_EXTENSIONS
2412 set_header(pane);
2413 #endif
2414 InvalidateRect(pane->hwnd, 0, TRUE);
2415 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND);
2416 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND|MF_CHECKED);
2417 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
2419 break;
2421 #ifndef _NO_EXTENSIONS
2422 case ID_PREFERED_SIZES: {
2423 calc_widths(pane, TRUE);
2424 set_header(pane);
2425 InvalidateRect(pane->hwnd, 0, TRUE);
2426 break;}
2427 #endif
2429 /* TODO: more command ids... */
2431 default:
2432 return FALSE;
2435 return TRUE;
2439 LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
2441 static int last_split;
2443 ChildWnd* child = (ChildWnd*) GetWindowLong(hwnd, GWL_USERDATA);
2444 ASSERT(child);
2446 switch(nmsg) {
2447 case WM_DRAWITEM: {
2448 LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lparam;
2449 Entry* entry = (Entry*) dis->itemData;
2451 if (dis->CtlID == IDW_TREE_LEFT)
2452 draw_item(&child->left, dis, entry, -1);
2453 else
2454 draw_item(&child->right, dis, entry, -1);
2456 return TRUE;}
2458 case WM_CREATE:
2459 InitChildWindow(child);
2460 break;
2462 case WM_NCDESTROY:
2463 free_child_window(child);
2464 SetWindowLong(hwnd, GWL_USERDATA, 0);
2465 break;
2467 case WM_PAINT: {
2468 PAINTSTRUCT ps;
2469 HBRUSH lastBrush;
2470 RECT rt;
2471 GetClientRect(hwnd, &rt);
2472 BeginPaint(hwnd, &ps);
2473 rt.left = child->split_pos-SPLIT_WIDTH/2;
2474 rt.right = child->split_pos+SPLIT_WIDTH/2+1;
2475 lastBrush = SelectBrush(ps.hdc, (HBRUSH)GetStockObject(COLOR_SPLITBAR));
2476 Rectangle(ps.hdc, rt.left, rt.top-1, rt.right, rt.bottom+1);
2477 SelectObject(ps.hdc, lastBrush);
2478 #ifdef _NO_EXTENSIONS
2479 rt.top = rt.bottom - GetSystemMetrics(SM_CYHSCROLL);
2480 FillRect(ps.hdc, &rt, GetStockObject(BLACK_BRUSH));
2481 #endif
2482 EndPaint(hwnd, &ps);
2483 break;}
2485 case WM_SETCURSOR:
2486 if (LOWORD(lparam) == HTCLIENT) {
2487 POINT pt;
2488 GetCursorPos(&pt);
2489 ScreenToClient(hwnd, &pt);
2491 if (pt.x>=child->split_pos-SPLIT_WIDTH/2 && pt.x<child->split_pos+SPLIT_WIDTH/2+1) {
2492 SetCursor(LoadCursor(0, IDC_SIZEWE));
2493 return TRUE;
2496 goto def;
2498 case WM_LBUTTONDOWN: {
2499 RECT rt;
2500 int x = LOWORD(lparam);
2502 GetClientRect(hwnd, &rt);
2504 if (x>=child->split_pos-SPLIT_WIDTH/2 && x<child->split_pos+SPLIT_WIDTH/2+1) {
2505 last_split = child->split_pos;
2506 #ifdef _NO_EXTENSIONS
2507 draw_splitbar(hwnd, last_split);
2508 #endif
2509 SetCapture(hwnd);
2512 break;}
2514 case WM_LBUTTONUP:
2515 if (GetCapture() == hwnd) {
2516 #ifdef _NO_EXTENSIONS
2517 RECT rt;
2518 int x = LOWORD(lparam);
2519 draw_splitbar(hwnd, last_split);
2520 last_split = -1;
2521 GetClientRect(hwnd, &rt);
2522 child->split_pos = x;
2523 resize_tree(child, rt.right, rt.bottom);
2524 #endif
2525 ReleaseCapture();
2527 break;
2529 #ifdef _NO_EXTENSIONS
2530 case WM_CAPTURECHANGED:
2531 if (GetCapture()==hwnd && last_split>=0)
2532 draw_splitbar(hwnd, last_split);
2533 break;
2534 #endif
2536 case WM_KEYDOWN:
2537 if (wparam == VK_ESCAPE)
2538 if (GetCapture() == hwnd) {
2539 RECT rt;
2540 #ifdef _NO_EXTENSIONS
2541 draw_splitbar(hwnd, last_split);
2542 #else
2543 child->split_pos = last_split;
2544 #endif
2545 GetClientRect(hwnd, &rt);
2546 resize_tree(child, rt.right, rt.bottom);
2547 last_split = -1;
2548 ReleaseCapture();
2549 SetCursor(LoadCursor(0, IDC_ARROW));
2551 break;
2553 case WM_MOUSEMOVE:
2554 if (GetCapture() == hwnd) {
2555 RECT rt;
2556 int x = LOWORD(lparam);
2558 #ifdef _NO_EXTENSIONS
2559 HDC hdc = GetDC(hwnd);
2560 GetClientRect(hwnd, &rt);
2562 rt.left = last_split-SPLIT_WIDTH/2;
2563 rt.right = last_split+SPLIT_WIDTH/2+1;
2564 InvertRect(hdc, &rt);
2566 last_split = x;
2567 rt.left = x-SPLIT_WIDTH/2;
2568 rt.right = x+SPLIT_WIDTH/2+1;
2569 InvertRect(hdc, &rt);
2571 ReleaseDC(hwnd, hdc);
2572 #else
2573 GetClientRect(hwnd, &rt);
2575 if (x>=0 && x<rt.right) {
2576 child->split_pos = x;
2577 resize_tree(child, rt.right, rt.bottom);
2578 rt.left = x-SPLIT_WIDTH/2;
2579 rt.right = x+SPLIT_WIDTH/2+1;
2580 InvalidateRect(hwnd, &rt, FALSE);
2581 UpdateWindow(child->left.hwnd);
2582 UpdateWindow(hwnd);
2583 UpdateWindow(child->right.hwnd);
2585 #endif
2587 break;
2589 #ifndef _NO_EXTENSIONS
2590 case WM_GETMINMAXINFO:
2591 DefMDIChildProc(hwnd, nmsg, wparam, lparam);
2593 {LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
2595 lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
2596 lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
2597 break;}
2598 #endif
2600 case WM_SETFOCUS:
2601 SetCurrentDirectory(child->path);
2602 SetFocus(child->focus_pane? child->right.hwnd: child->left.hwnd);
2603 break;
2605 case WM_DISPATCH_COMMAND: {
2606 Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
2608 switch(LOWORD(wparam)) {
2609 case ID_WINDOW_NEW: {
2610 ChildWnd* new_child = alloc_child_window(child->path);
2612 if (!create_child_window(new_child))
2613 free(new_child);
2615 break;}
2617 case ID_REFRESH:
2618 scan_entry(child, pane->cur);
2619 break;
2621 case ID_ACTIVATE:
2622 activate_entry(child, pane);
2623 break;
2625 default:
2626 return pane_command(pane, LOWORD(wparam));
2629 return TRUE;}
2631 case WM_COMMAND: {
2632 Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
2634 switch(HIWORD(wparam)) {
2635 case LBN_SELCHANGE: {
2636 int idx = ListBox_GetCurSel(pane->hwnd);
2637 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, idx);
2639 if (pane == &child->left)
2640 set_curdir(child, entry);
2641 else
2642 pane->cur = entry;
2643 break;}
2645 case LBN_DBLCLK:
2646 activate_entry(child, pane);
2647 break;
2649 break;}
2651 #ifndef _NO_EXTENSIONS
2652 case WM_NOTIFY: {
2653 NMHDR* pnmh = (NMHDR*) lparam;
2654 return pane_notify(pnmh->idFrom==IDW_HEADER_LEFT? &child->left: &child->right, pnmh);}
2655 #endif
2657 case WM_SIZE:
2658 if (wparam != SIZE_MINIMIZED)
2659 resize_tree(child, LOWORD(lparam), HIWORD(lparam));
2660 /* fall through */
2662 default: def:
2663 return DefMDIChildProc(hwnd, nmsg, wparam, lparam);
2666 return 0;
2670 LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
2672 ChildWnd* child = (ChildWnd*) GetWindowLong(GetParent(hwnd), GWL_USERDATA);
2673 Pane* pane = (Pane*) GetWindowLong(hwnd, GWL_USERDATA);
2674 ASSERT(child);
2676 switch(nmsg) {
2677 #ifndef _NO_EXTENSIONS
2678 case WM_HSCROLL:
2679 set_header(pane);
2680 break;
2681 #endif
2683 case WM_SETFOCUS:
2684 child->focus_pane = pane==&child->right? 1: 0;
2685 ListBox_SetSel(hwnd, TRUE, 1);
2686 /*TODO: check menu items */
2687 break;
2689 case WM_KEYDOWN:
2690 if (wparam == VK_TAB) {
2691 /*TODO: SetFocus(Globals.hdrivebar) */
2692 SetFocus(child->focus_pane? child->left.hwnd: child->right.hwnd);
2696 return CallWindowProc(g_orgTreeWndProc, hwnd, nmsg, wparam, lparam);
2700 static void InitInstance(HINSTANCE hinstance)
2702 WNDCLASSEX wcFrame;
2703 ATOM hframeClass;
2704 WNDCLASS wcChild;
2705 WINE_UNUSED ATOM hChildClass;
2706 HMENU hMenuFrame = LoadMenu(hinstance, MAKEINTRESOURCE(IDM_WINEFILE));
2707 HMENU hMenuWindow = GetSubMenu(hMenuFrame, GetMenuItemCount(hMenuFrame)-2);
2709 CLIENTCREATESTRUCT ccs;
2711 INITCOMMONCONTROLSEX icc = {
2712 sizeof(INITCOMMONCONTROLSEX),
2713 ICC_BAR_CLASSES
2716 ChildWnd* child;
2717 TCHAR path[MAX_PATH];
2719 HDC hdc = GetDC(0);
2722 wcFrame.cbSize = sizeof(WNDCLASSEX);
2723 wcFrame.style = 0;
2724 wcFrame.lpfnWndProc = FrameWndProc;
2725 wcFrame.cbClsExtra = 0;
2726 wcFrame.cbWndExtra = 0;
2727 wcFrame.hInstance = hinstance;
2728 wcFrame.hIcon = LoadIcon(hinstance,
2729 MAKEINTRESOURCE(IDI_WINEFILE));
2730 wcFrame.hCursor = LoadCursor(0, IDC_ARROW);
2731 wcFrame.hbrBackground = 0;
2732 wcFrame.lpszMenuName = 0;
2733 wcFrame.lpszClassName = WINEFILEFRAME;
2734 wcFrame.hIconSm = (HICON)LoadImage(hinstance,
2735 MAKEINTRESOURCE(IDI_WINEFILE),
2736 IMAGE_ICON,
2737 GetSystemMetrics(SM_CXSMICON),
2738 GetSystemMetrics(SM_CYSMICON),
2739 LR_SHARED);
2741 /* register frame window class */
2742 hframeClass = RegisterClassEx(&wcFrame);
2744 wcChild.style = CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW;
2745 wcChild.lpfnWndProc = ChildWndProc;
2746 wcChild.cbClsExtra = 0;
2747 wcChild.cbWndExtra = 0;
2748 wcChild.hInstance = hinstance;
2749 wcChild.hIcon = 0;
2750 wcChild.hCursor = LoadCursor(0, IDC_ARROW);
2751 wcChild.hbrBackground = 0;
2752 wcChild.lpszMenuName = 0;
2753 wcChild.lpszClassName = WINEFILETREE;
2755 /* register tree windows class */
2756 hChildClass = RegisterClass(&wcChild);
2758 ccs.hWindowMenu = hMenuWindow;
2759 ccs.idFirstChild = IDW_FIRST_CHILD;
2761 Globals.hMenuFrame = hMenuFrame;
2762 Globals.hMenuView = GetSubMenu(hMenuFrame, 3);
2763 Globals.hMenuOptions = GetSubMenu(hMenuFrame, 4);
2765 Globals.haccel = LoadAccelerators(hinstance, MAKEINTRESOURCE(IDA_WINEFILE));
2767 Globals.hfont = CreateFont(-MulDiv(8,GetDeviceCaps(hdc,LOGPIXELSY),72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("MS Sans Serif"));
2769 ReleaseDC(0, hdc);
2771 Globals.hInstance = hinstance;
2773 /* create main window */
2774 Globals.hMainWnd = CreateWindowEx(0, (LPCTSTR)(int)hframeClass, _T("Wine File"), WS_OVERLAPPEDWINDOW,
2775 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2776 0/*hWndParent*/, Globals.hMenuFrame, hinstance, 0/*lpParam*/);
2779 Globals.hmdiclient = CreateWindowEx(0, _T("MDICLIENT"), NULL,
2780 WS_CHILD|WS_CLIPCHILDREN|WS_VSCROLL|WS_HSCROLL|WS_VISIBLE|WS_BORDER,
2781 0, 0, 0, 0,
2782 Globals.hMainWnd, 0, hinstance, &ccs);
2785 InitCommonControlsEx(&icc);
2788 TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, TBSTYLE_SEP};
2789 int btn = 1;
2790 PTSTR p;
2792 Globals.hdrivebar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE|CCS_NOMOVEY|TBSTYLE_LIST,
2793 IDW_DRIVEBAR, 2, Globals.hInstance, IDB_DRIVEBAR, &drivebarBtn,
2794 1, 16, 13, 16, 13, sizeof(TBBUTTON));
2795 CheckMenuItem(Globals.hMenuOptions, ID_VIEW_DRIVE_BAR, MF_BYCOMMAND|MF_CHECKED);
2797 GetLogicalDriveStrings(BUFFER_LEN, Globals.drives);
2799 drivebarBtn.fsStyle = TBSTYLE_BUTTON;
2801 #ifndef _NO_EXTENSIONS
2802 #ifdef __linux__
2803 /* insert unix file system button */
2804 SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)_T("/\0"));
2806 drivebarBtn.idCommand = ID_DRIVE_UNIX_FS;
2807 SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
2808 drivebarBtn.iString++;
2809 #endif
2811 /* register windows drive root strings */
2812 SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)Globals.drives);
2813 #endif
2815 drivebarBtn.idCommand = ID_DRIVE_FIRST;
2817 for(p=Globals.drives; *p; ) {
2818 #ifdef _NO_EXTENSIONS
2819 /* insert drive letter */
2820 TCHAR b[3] = {tolower(*p)};
2821 SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b);
2822 #endif
2823 switch(GetDriveType(p)) {
2824 case DRIVE_REMOVABLE: drivebarBtn.iBitmap = 1; break;
2825 case DRIVE_CDROM: drivebarBtn.iBitmap = 3; break;
2826 case DRIVE_REMOTE: drivebarBtn.iBitmap = 4; break;
2827 case DRIVE_RAMDISK: drivebarBtn.iBitmap = 5; break;
2828 default:/*DRIVE_FIXED*/ drivebarBtn.iBitmap = 2;
2831 SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
2832 drivebarBtn.idCommand++;
2833 drivebarBtn.iString++;
2835 while(*p++);
2840 TBBUTTON toolbarBtns[] = {
2841 {0, 0, 0, TBSTYLE_SEP},
2842 {0, ID_WINDOW_NEW, TBSTATE_ENABLED, TBSTYLE_BUTTON},
2843 {1, ID_WINDOW_CASCADE, TBSTATE_ENABLED, TBSTYLE_BUTTON},
2844 {2, ID_WINDOW_TILE_HORZ, TBSTATE_ENABLED, TBSTYLE_BUTTON},
2845 {3, ID_WINDOW_TILE_VERT, TBSTATE_ENABLED, TBSTYLE_BUTTON},
2846 {4, 2/*TODO: ID_...*/, TBSTATE_ENABLED, TBSTYLE_BUTTON},
2847 {5, 2/*TODO: ID_...*/, TBSTATE_ENABLED, TBSTYLE_BUTTON},
2850 Globals.htoolbar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE,
2851 IDW_TOOLBAR, 2, Globals.hInstance, IDB_TOOLBAR, toolbarBtns,
2852 sizeof(toolbarBtns)/sizeof(TBBUTTON), 16, 15, 16, 15, sizeof(TBBUTTON));
2853 CheckMenuItem(Globals.hMenuOptions, ID_VIEW_TOOL_BAR, MF_BYCOMMAND|MF_CHECKED);
2856 Globals.hstatusbar = CreateStatusWindow(WS_CHILD|WS_VISIBLE, 0, Globals.hMainWnd, IDW_STATUSBAR);
2857 CheckMenuItem(Globals.hMenuOptions, ID_VIEW_STATUSBAR, MF_BYCOMMAND|MF_CHECKED);
2859 /* CreateStatusWindow does not accept WS_BORDER
2860 Globals.hstatusbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY, STATUSCLASSNAME, 0,
2861 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_BORDER|CCS_NODIVIDER, 0,0,0,0,
2862 Globals.hMainWnd, (HMENU)IDW_STATUSBAR, hinstance, 0);*/
2864 /*TODO: read paths and window placements from registry */
2865 GetCurrentDirectory(MAX_PATH, path);
2866 child = alloc_child_window(path);
2868 child->pos.showCmd = SW_SHOWMAXIMIZED;
2869 child->pos.rcNormalPosition.left = 0;
2870 child->pos.rcNormalPosition.top = 0;
2871 child->pos.rcNormalPosition.right = 320;
2872 child->pos.rcNormalPosition.bottom = 280;
2874 if (!create_child_window(child))
2875 free(child);
2877 SetWindowPlacement(child->hwnd, &child->pos);
2879 Globals.himl = ImageList_LoadBitmap(Globals.hInstance, MAKEINTRESOURCE(IDB_IMAGES), 16, 0, RGB(0,255,0));
2881 Globals.prescan_node = FALSE;
2884 void ExitInstance()
2886 ImageList_Destroy(Globals.himl);
2890 #ifdef _NO_EXTENSIONS
2892 /* search for already running win[e]files */
2894 static int g_foundPrevInstance = 0;
2896 static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lparam)
2898 TCHAR cls[128];
2900 GetClassName(hwnd, cls, 128);
2902 if (!lstrcmp(cls, (LPCTSTR)lparam)) {
2903 g_foundPrevInstance++;
2904 return FALSE;
2907 return TRUE;
2910 #endif
2913 int APIENTRY WinMain(HINSTANCE hinstance,
2914 HINSTANCE previnstance,
2915 LPSTR cmdline,
2916 int cmdshow)
2918 MSG msg;
2920 #ifdef _NO_EXTENSIONS
2921 /* allow only one running instance */
2922 EnumWindows(EnumWndProc, (LPARAM)WINEFILEFRAME);
2924 if (g_foundPrevInstance)
2925 return 1;
2926 #endif
2928 InitInstance(hinstance);
2930 if (cmdshow == SW_SHOWNORMAL) {
2931 /*TODO: read window placement from registry */
2932 cmdshow = SW_MAXIMIZE;
2935 ShowWindow(Globals.hMainWnd, cmdshow);
2936 UpdateWindow(Globals.hMainWnd);
2938 while(GetMessage(&msg, 0, 0, 0)) {
2939 if (!TranslateMDISysAccel(Globals.hmdiclient, &msg) &&
2940 !TranslateAccelerator(Globals.hMainWnd, Globals.haccel, &msg))
2942 TranslateMessage(&msg);
2943 DispatchMessage(&msg);
2947 ExitInstance();
2949 return 0;