winefile.c

Go to the documentation of this file.
00001 /*
00002  * Winefile
00003  *
00004  * Copyright 2000, 2003, 2004, 2005, 2008 Martin Fuchs
00005  * Copyright 2006 Jason Green
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00020  */
00021 
00022 #include "winefile.h"
00023 
00024 
00025 static void set_curdir(ChildWnd* child, Entry* entry, int idx, HWND hwnd);
00026 static void refresh_child(ChildWnd* child);
00027 static void refresh_drives(void);
00028 
00029 
00030 /* some common string constants */
00031 const TCHAR sEmpty[] = {'\0'};
00032 const TCHAR sSpace[] = {' ', '\0'};
00033 const TCHAR sNumFmt[] = {'%','d','\0'};
00034 const TCHAR sQMarks[] = {'?','?','?','\0'};
00035 
00036 #ifdef _MSC_VER
00037 const TCHAR sLongHexFmt[] = {'%','I','6','4','X','\0'};
00038 const TCHAR sLongNumFmt[] = {'%','I','6','4','d','\0'};
00039 #else
00040 const TCHAR sLongHexFmt[] = {'%','L','X','\0'};
00041 const TCHAR sLongNumFmt[] = {'%','L','d','\0'};
00042 #endif
00043 
00044 /* window class names */
00045 const TCHAR sWINEFILEFRAME[] = {'W','F','S','_','F','r','a','m','e','\0'};
00046 const TCHAR sWINEFILETREE[] = {'W','F','S','_','T','r','e','e','\0'};
00047 
00048 
00049 /* globals */
00050 struct WINEFILE_GLOBALS Globals;
00051 
00052 static int last_split;
00053 
00054 
00055 /* load resource string */
00056 LPTSTR load_string(LPTSTR buffer, UINT id)
00057 {
00058     LoadString(Globals.hInstance, id, buffer, BUFFER_LEN);
00059 
00060     return buffer;
00061 }
00062 
00063 
00064 /* display error message for the specified WIN32 error code */
00065 void display_error(HWND hwnd, DWORD error)
00066 {
00067     TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
00068     PTSTR msg;
00069 
00070     if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
00071         0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PTSTR)&msg, 0, NULL))
00072         MessageBox(hwnd, msg, RS(b2,IDS_WINEFILE), MB_OK);
00073     else
00074         MessageBox(hwnd, RS(b1,IDS_ERROR), RS(b2,IDS_WINEFILE), MB_OK);
00075 
00076     LocalFree(msg);
00077 }
00078 
00079 
00080 /* display network error message using WNetGetLastError() */
00081 void display_network_error(HWND hwnd)
00082 {
00083     TCHAR msg[BUFFER_LEN], provider[BUFFER_LEN], b2[BUFFER_LEN];
00084     DWORD error;
00085 
00086     if (WNetGetLastError(&error, msg, BUFFER_LEN, provider, BUFFER_LEN) == NO_ERROR)
00087         MessageBox(hwnd, msg, RS(b2,IDS_WINEFILE), MB_OK);
00088 }
00089 
00090 
00091 #ifdef __WINE__
00092 
00093 #ifdef UNICODE
00094 
00095 /* call vswprintf() in msvcrt.dll */
00096 /*TODO: fix swprintf() in non-msvcrt mode, so that this dynamic linking function can be removed */
00097 static int msvcrt_swprintf(WCHAR* buffer, const WCHAR* fmt, ...)
00098 {
00099     static int (__cdecl *pvswprintf)(WCHAR*, const WCHAR*, va_list) = NULL;
00100     va_list ap;
00101     int ret;
00102 
00103     if (!pvswprintf) {
00104         HMODULE hModMsvcrt = LoadLibraryA("msvcrt");
00105         pvswprintf = (int(__cdecl*)(WCHAR*,const WCHAR*,va_list)) GetProcAddress(hModMsvcrt, "vswprintf");
00106     }
00107 
00108     va_start(ap, fmt);
00109     ret = (*pvswprintf)(buffer, fmt, ap);
00110     va_end(ap);
00111 
00112     return ret;
00113 }
00114 
00115 /* UNICODE version of strrchr() for WINE */
00116 static LPCWSTR my_wcsrchr(LPCWSTR str, WCHAR c)
00117 {
00118     LPCWSTR p = str;
00119 
00120     while(*p)
00121         ++p;
00122 
00123     do {
00124         if (--p < str)
00125             return NULL;
00126     } while(*p != c);
00127 
00128     return p;
00129 }
00130 
00131 #define _tcsrchr my_wcsrchr
00132 #else   /* UNICODE */
00133 #define _tcsrchr strrchr
00134 #endif  /* UNICODE */
00135 
00136 #endif  /* __WINE__ */
00137 
00138 
00139 /* allocate and initialize memeory for a new child window for the given path */
00140 
00141 static ChildWnd* alloc_child_window(LPCTSTR path, LPITEMIDLIST pidl, HWND hwnd)
00142 {
00143     TCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
00144     TCHAR dir_path[MAX_PATH];
00145     TCHAR b1[BUFFER_LEN];
00146     static const TCHAR sAsterics[] = {'*', '\0'};
00147 
00148     ChildWnd* child = (ChildWnd*) heap_alloc(sizeof(ChildWnd));
00149     Root* root = &child->root;
00150     Entry* entry;
00151 
00152     memset(child, 0, sizeof(ChildWnd));
00153 
00154     child->left.treePane = TRUE;
00155     child->left.visible_cols = 0;
00156 
00157     child->right.treePane = FALSE;
00158 #ifndef _NO_EXTENSIONS
00159     child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_INDEX|COL_LINKS;
00160 #else
00161     child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES;
00162 #endif
00163 
00164     child->pos.length = sizeof(WINDOWPLACEMENT);
00165     child->pos.flags = 0;
00166     child->pos.showCmd = SW_SHOWNORMAL;
00167     child->pos.rcNormalPosition.left = CW_USEDEFAULT;
00168     child->pos.rcNormalPosition.top = CW_USEDEFAULT;
00169     child->pos.rcNormalPosition.right = CW_USEDEFAULT;
00170     child->pos.rcNormalPosition.bottom = CW_USEDEFAULT;
00171 
00172     child->focus_pane = 0;
00173     child->split_pos = DEFAULT_SPLIT_POS;
00174     child->sortOrder = SORT_NAME;
00175     child->header_wdths_ok = FALSE;
00176 
00177     if (path) {
00178         lstrcpy(child->path, path);
00179 
00180         _tsplitpath(path, drv, dir, name, ext);
00181     }
00182 
00183     lstrcpy(child->filter_pattern, sAsterics);
00184     child->filter_flags = TF_ALL;
00185 
00186     root->entry.level = 0;
00187 
00188     lstrcpy(dir_path, drv);
00189     lstrcat(dir_path, dir);
00190     entry = read_tree(root, dir_path, pidl, drv, child->sortOrder, hwnd);
00191 
00192 #ifdef _SHELL_FOLDERS
00193     if (root->entry.etype == ET_SHELL)
00194         load_string(root->entry.data.cFileName, IDS_DESKTOP);
00195     else
00196 #endif
00197         wsprintf(root->entry.data.cFileName, RS(b1,IDS_TITLEFMT), drv, root->fs);
00198 
00199     root->entry.data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
00200 
00201     child->left.root = &root->entry;
00202     child->right.root = NULL;
00203 
00204     set_curdir(child, entry, 0, hwnd);
00205 
00206     return child;
00207 }
00208 
00209 
00210 /* free all memory associated with a child window */
00211 
00212 static void free_child_window(ChildWnd* child)
00213 {
00214     free_entries(&child->root.entry);
00215     heap_free(child);
00216 }
00217 
00218 
00219 /* adjust child windows to the new frame window size */
00220 
00221 static void resize_frame_rect(HWND hwnd, PRECT prect)
00222 {
00223     int new_top;
00224     RECT rt;
00225 
00226     if (IsWindowVisible(Globals.htoolbar)) {
00227         SendMessage(Globals.htoolbar, WM_SIZE, 0, 0);
00228         GetClientRect(Globals.htoolbar, &rt);
00229         prect->top = rt.bottom+3;
00230         prect->bottom -= rt.bottom+3;
00231     }
00232 
00233     if (IsWindowVisible(Globals.hdrivebar)) {
00234         SendMessage(Globals.hdrivebar, WM_SIZE, 0, 0);
00235         GetClientRect(Globals.hdrivebar, &rt);
00236         new_top = --prect->top + rt.bottom+3;
00237         MoveWindow(Globals.hdrivebar, 0, prect->top, rt.right, new_top, TRUE);
00238         prect->top = new_top;
00239         prect->bottom -= rt.bottom+2;
00240     }
00241 
00242     if (IsWindowVisible(Globals.hstatusbar)) {
00243         int parts[] = {300, 500};
00244 
00245         SendMessage(Globals.hstatusbar, WM_SIZE, 0, 0);
00246         SendMessage(Globals.hstatusbar, SB_SETPARTS, 2, (LPARAM)&parts);
00247         GetClientRect(Globals.hstatusbar, &rt);
00248         prect->bottom -= rt.bottom;
00249     }
00250 
00251     MoveWindow(Globals.hmdiclient, prect->left-1,prect->top-1,prect->right+2,prect->bottom+1, TRUE);
00252 }
00253 
00254 
00255 /* set the frame window size */
00256 
00257 static void resize_frame(HWND hwnd, int cx, int cy)
00258 {
00259     RECT rect;
00260 
00261     rect.left   = 0;
00262     rect.top    = 0;
00263     rect.right  = cx;
00264     rect.bottom = cy;
00265 
00266     resize_frame_rect(hwnd, &rect);
00267 }
00268 
00269 
00270 /* update window layouts to the current frame window size */
00271 
00272 static void resize_frame_client(HWND hwnd)
00273 {
00274     RECT rect;
00275 
00276     GetClientRect(hwnd, &rect);
00277 
00278     resize_frame_rect(hwnd, &rect);
00279 }
00280 
00281 
00282 static HHOOK hcbthook;
00283 static ChildWnd* newchild = NULL;
00284 
00285 /* window creation callback function used in create_child_window() */
00286 static LRESULT CALLBACK CBTProc(int code, WPARAM wparam, LPARAM lparam)
00287 {
00288     if (code==HCBT_CREATEWND && newchild) {
00289         ChildWnd* child = newchild;
00290         newchild = NULL;
00291 
00292         child->hwnd = (HWND) wparam;
00293         SetWindowLongPtr(child->hwnd, GWLP_USERDATA, (LPARAM)child);
00294     }
00295 
00296     return CallNextHookEx(hcbthook, code, wparam, lparam);
00297 }
00298 
00299 /* create a new MDI child window */
00300 static HWND create_child_window(ChildWnd* child)
00301 {
00302     MDICREATESTRUCT mcs;
00303     int idx;
00304 
00305     mcs.szClass = sWINEFILETREE;
00306     mcs.szTitle = (LPTSTR)child->path;
00307     mcs.hOwner  = Globals.hInstance;
00308     mcs.x       = child->pos.rcNormalPosition.left;
00309     mcs.y       = child->pos.rcNormalPosition.top;
00310     mcs.cx      = child->pos.rcNormalPosition.right-child->pos.rcNormalPosition.left;
00311     mcs.cy      = child->pos.rcNormalPosition.bottom-child->pos.rcNormalPosition.top;
00312     mcs.style   = 0;
00313     mcs.lParam  = 0;
00314 
00315     hcbthook = SetWindowsHookEx(WH_CBT, CBTProc, 0, GetCurrentThreadId());
00316 
00317     newchild = child;
00318     child->hwnd = (HWND) SendMessage(Globals.hmdiclient, WM_MDICREATE, 0, (LPARAM)&mcs);
00319     if (!child->hwnd) {
00320         UnhookWindowsHookEx(hcbthook);
00321         return 0;
00322     }
00323 
00324     UnhookWindowsHookEx(hcbthook);
00325 
00326     (void)ListBox_SetItemHeight(child->left.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
00327     (void)ListBox_SetItemHeight(child->right.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
00328 
00329     idx = ListBox_FindItemData(child->left.hwnd, 0, child->left.cur);
00330     (void)ListBox_SetCurSel(child->left.hwnd, idx);
00331 
00332     return child->hwnd;
00333 }
00334 
00335 
00336 #ifndef _NO_EXTENSIONS
00337 
00338 /* calculate client space for the frame window */
00339 static void frame_get_clientspace(HWND hwnd, PRECT prect)
00340 {
00341     RECT rt;
00342 
00343     if (!IsIconic(hwnd))
00344         GetClientRect(hwnd, prect);
00345     else {
00346         WINDOWPLACEMENT wp;
00347 
00348         GetWindowPlacement(hwnd, &wp);
00349 
00350         prect->left = prect->top = 0;
00351         prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left-
00352                         2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE));
00353         prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top-
00354                         2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))-
00355                         GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE);
00356     }
00357 
00358     if (IsWindowVisible(Globals.htoolbar)) {
00359         GetClientRect(Globals.htoolbar, &rt);
00360         prect->top += rt.bottom+2;
00361     }
00362 
00363     if (IsWindowVisible(Globals.hdrivebar)) {
00364         GetClientRect(Globals.hdrivebar, &rt);
00365         prect->top += rt.bottom+2;
00366     }
00367 
00368     if (IsWindowVisible(Globals.hstatusbar)) {
00369         GetClientRect(Globals.hstatusbar, &rt);
00370         prect->bottom -= rt.bottom;
00371     }
00372 }
00373 
00374 
00375 /* full screen mode state */
00376 static struct FullScreenParameters {
00377     BOOL    mode;
00378     RECT    orgPos;
00379     BOOL    wasZoomed;
00380 } g_fullscreen = {
00381     FALSE,  /* mode */
00382     {0, 0, 0, 0},
00383     FALSE
00384 };
00385 
00386 /* toggle full screen mode */
00387 static BOOL toggle_fullscreen(HWND hwnd)
00388 {
00389     RECT rt;
00390 
00391     if ((g_fullscreen.mode=!g_fullscreen.mode)) {
00392         GetWindowRect(hwnd, &g_fullscreen.orgPos);
00393         g_fullscreen.wasZoomed = IsZoomed(hwnd);
00394 
00395         (void)Frame_CalcFrameClient(hwnd, &rt);
00396         ClientToScreen(hwnd, (LPPOINT)&rt.left);
00397         ClientToScreen(hwnd, (LPPOINT)&rt.right);
00398 
00399         rt.left = g_fullscreen.orgPos.left-rt.left;
00400         rt.top = g_fullscreen.orgPos.top-rt.top;
00401         rt.right = GetSystemMetrics(SM_CXSCREEN)+g_fullscreen.orgPos.right-rt.right;
00402         rt.bottom = GetSystemMetrics(SM_CYSCREEN)+g_fullscreen.orgPos.bottom-rt.bottom;
00403 
00404         MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
00405     } else {
00406         MoveWindow(hwnd, g_fullscreen.orgPos.left, g_fullscreen.orgPos.top,
00407                             g_fullscreen.orgPos.right-g_fullscreen.orgPos.left,
00408                             g_fullscreen.orgPos.bottom-g_fullscreen.orgPos.top, TRUE);
00409 
00410         if (g_fullscreen.wasZoomed)
00411             ShowWindow(hwnd, WS_MAXIMIZE);
00412     }
00413 
00414     return g_fullscreen.mode;
00415 }
00416 
00417 /* adjust window coordinates in full screen mode */
00418 static void fullscreen_move(HWND hwnd)
00419 {
00420     RECT rt, pos;
00421     GetWindowRect(hwnd, &pos);
00422 
00423     (void)Frame_CalcFrameClient(hwnd, &rt);
00424     ClientToScreen(hwnd, (LPPOINT)&rt.left);
00425     ClientToScreen(hwnd, (LPPOINT)&rt.right);
00426 
00427     rt.left = pos.left-rt.left;
00428     rt.top = pos.top-rt.top;
00429     rt.right = GetSystemMetrics(SM_CXSCREEN)+pos.right-rt.right;
00430     rt.bottom = GetSystemMetrics(SM_CYSCREEN)+pos.bottom-rt.bottom;
00431 
00432     MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
00433 }
00434 
00435 #endif
00436 
00437 
00438 /* toggle the visibility of a child window */
00439 
00440 static void toggle_child(HWND hwnd, UINT cmd, HWND hchild)
00441 {
00442     BOOL vis = IsWindowVisible(hchild);
00443 
00444     CheckMenuItem(Globals.hMenuOptions, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
00445 
00446     ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
00447 
00448 #ifndef _NO_EXTENSIONS
00449     if (g_fullscreen.mode)
00450         fullscreen_move(hwnd);
00451 #endif
00452 
00453     resize_frame_client(hwnd);
00454 }
00455 
00456 
00457 /* activate a drive child window */
00458 static BOOL activate_drive_window(LPCTSTR path)
00459 {
00460     TCHAR drv1[_MAX_DRIVE], drv2[_MAX_DRIVE];
00461     HWND child_wnd;
00462 
00463     _tsplitpath(path, drv1, 0, 0, 0);
00464 
00465     /* search for a already open window for the same drive */
00466     for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
00467         ChildWnd* child = (ChildWnd*) GetWindowLongPtr(child_wnd, GWLP_USERDATA);
00468 
00469         if (child) {
00470             _tsplitpath(child->root.path, drv2, 0, 0, 0);
00471 
00472             if (!lstrcmpi(drv2, drv1)) {
00473                 SendMessage(Globals.hmdiclient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
00474 
00475                 if (IsMinimized(child_wnd))
00476                     ShowWindow(child_wnd, SW_SHOWNORMAL);
00477 
00478                 return TRUE;
00479             }
00480         }
00481     }
00482 
00483     return FALSE;
00484 }
00485 
00486 /* activate window containing a file system tree */
00487 static BOOL activate_fs_window(LPCTSTR filesys)
00488 {
00489     HWND child_wnd;
00490 
00491     /* search for a already open window of the given file system name */
00492     for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
00493         ChildWnd* child = (ChildWnd*) GetWindowLongPtr(child_wnd, GWLP_USERDATA);
00494 
00495         if (child) {
00496             if (!lstrcmpi(child->root.fs, filesys)) {
00497                 SendMessage(Globals.hmdiclient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
00498 
00499                 if (IsMinimized(child_wnd))
00500                     ShowWindow(child_wnd, SW_SHOWNORMAL);
00501 
00502                 return TRUE;
00503             }
00504         }
00505     }
00506 
00507     return FALSE;
00508 }
00509 
00510 
00511 /* frame window message handler */
00512 
00513 static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
00514 {
00515     TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
00516 
00517     switch(nmsg) {
00518         case WM_CLOSE:
00519             if (Globals.saveSettings)
00520                 save_registry_settings();  
00521 
00522             DestroyWindow(hwnd);
00523 
00524             /* clear handle variables */
00525             Globals.hMenuFrame = 0;
00526             Globals.hMenuView = 0;
00527             Globals.hMenuOptions = 0;
00528             Globals.hMainWnd = 0;
00529             Globals.hmdiclient = 0;
00530             Globals.hdrivebar = 0;
00531             break;
00532 
00533         case WM_DESTROY:
00534             PostQuitMessage(0);
00535             break;
00536 
00537         case WM_INITMENUPOPUP: {
00538             HWND hwndClient = (HWND) SendMessage(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
00539 
00540             if (!SendMessage(hwndClient, WM_INITMENUPOPUP, wparam, lparam))
00541                 return 0;
00542             break;}
00543 
00544         case WM_COMMAND: {
00545             UINT cmd = LOWORD(wparam);
00546             HWND hwndClient = (HWND) SendMessage(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
00547 
00548             if (SendMessage(hwndClient, WM_DISPATCH_COMMAND, wparam, lparam))
00549                 break;
00550 
00551             if (cmd>=ID_DRIVE_FIRST && cmd<=ID_DRIVE_FIRST+0xFF) {
00552                 TCHAR drv[_MAX_DRIVE], path[MAX_PATH];
00553                 ChildWnd* child;
00554                 LPCTSTR root = Globals.drives;
00555                 int i;
00556 
00557                 for(i=cmd-ID_DRIVE_FIRST; i--; root++)
00558                     while(*root)
00559                         root++;
00560 
00561                 if (activate_drive_window(root))
00562                     return 0;
00563 
00564                 _tsplitpath(root, drv, 0, 0, 0);
00565 
00566                 if (!SetCurrentDirectory(drv)) {
00567                     display_error(hwnd, GetLastError());
00568                     return 0;
00569                 }
00570 
00571                 GetCurrentDirectory(MAX_PATH, path); /*TODO: store last directory per drive */
00572                 child = alloc_child_window(path, NULL, hwnd);
00573 
00574                 if (!create_child_window(child))
00575                     heap_free(child);
00576             } else switch(cmd) {
00577                 case ID_FILE_EXIT:
00578                     SendMessage(hwnd, WM_CLOSE, 0, 0);
00579                     break;
00580 
00581                 case ID_WINDOW_NEW: {
00582                     TCHAR path[MAX_PATH];
00583                     ChildWnd* child;
00584 
00585                     GetCurrentDirectory(MAX_PATH, path);
00586                     child = alloc_child_window(path, NULL, hwnd);
00587 
00588                     if (!create_child_window(child))
00589                         heap_free(child);
00590                     break;}
00591 
00592                 case ID_REFRESH:
00593                     refresh_drives();
00594                     break;
00595 
00596                 case ID_WINDOW_CASCADE:
00597                     SendMessage(Globals.hmdiclient, WM_MDICASCADE, 0, 0);
00598                     break;
00599 
00600                 case ID_WINDOW_TILE_HORZ:
00601                     SendMessage(Globals.hmdiclient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
00602                     break;
00603 
00604                 case ID_WINDOW_TILE_VERT:
00605                     SendMessage(Globals.hmdiclient, WM_MDITILE, MDITILE_VERTICAL, 0);
00606                     break;
00607 
00608                 case ID_WINDOW_ARRANGE:
00609                     SendMessage(Globals.hmdiclient, WM_MDIICONARRANGE, 0, 0);
00610                     break;
00611 
00612                 case ID_SELECT_FONT:
00613                     choose_font(hwnd);
00614                     break;
00615 
00616                 case ID_VIEW_TOOL_BAR:
00617                     toggle_child(hwnd, cmd, Globals.htoolbar);
00618                     break;
00619 
00620                 case ID_VIEW_DRIVE_BAR:
00621                     toggle_child(hwnd, cmd, Globals.hdrivebar);
00622                     break;
00623 
00624                 case ID_VIEW_STATUSBAR:
00625                     toggle_child(hwnd, cmd, Globals.hstatusbar);
00626                     break;
00627 
00628                 case ID_VIEW_SAVESETTINGS:
00629                     Globals.saveSettings = !Globals.saveSettings;
00630                     CheckMenuItem(Globals.hMenuOptions, ID_VIEW_SAVESETTINGS,
00631                                   Globals.saveSettings ? MF_CHECKED : MF_UNCHECKED);
00632                     break;
00633 
00634                 case ID_EXECUTE: {
00635                     struct ExecuteDialog dlg;
00636 
00637                     memset(&dlg, 0, sizeof(struct ExecuteDialog));
00638 
00639                     if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_EXECUTE), hwnd, ExecuteDialogDlgProc, (LPARAM)&dlg) == IDOK) {
00640                         HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, dlg.cmd/*file*/, NULL/*parameters*/, NULL/*dir*/, dlg.cmdshow);
00641 
00642                         if (PtrToUlong(hinst) <= 32)
00643                             display_error(hwnd, GetLastError());
00644                     }
00645                     break;}
00646 
00647                 case ID_CONNECT_NETWORK_DRIVE: {
00648                     DWORD ret = WNetConnectionDialog(hwnd, RESOURCETYPE_DISK);
00649                     if (ret == NO_ERROR)
00650                         refresh_drives();
00651                     else if (ret != (DWORD)-1) {
00652                         if (ret == ERROR_EXTENDED_ERROR)
00653                             display_network_error(hwnd);
00654                         else
00655                             display_error(hwnd, ret);
00656                     }
00657                     break;}
00658 
00659                 case ID_DISCONNECT_NETWORK_DRIVE: {
00660                     DWORD ret = WNetDisconnectDialog(hwnd, RESOURCETYPE_DISK);
00661                     if (ret == NO_ERROR)
00662                         refresh_drives();
00663                     else if (ret != (DWORD)-1) {
00664                         if (ret == ERROR_EXTENDED_ERROR)
00665                             display_network_error(hwnd);
00666                         else
00667                             display_error(hwnd, ret);
00668                     }
00669                     break;}
00670 
00671                 case ID_FORMAT_DISK: {
00672                     UINT sem_org = SetErrorMode(0); /* Get the current Error Mode settings. */
00673                     SetErrorMode(sem_org & ~SEM_FAILCRITICALERRORS); /* Force O/S to handle */
00674                     SHFormatDrive(hwnd, 0 /* A: */, SHFMT_ID_DEFAULT, 0);
00675                     SetErrorMode(sem_org); /* Put it back the way it was. */
00676                     break;}
00677 
00678                 case ID_HELP:
00679                     WinHelp(hwnd, RS(b1,IDS_WINEFILE), HELP_INDEX, 0);
00680                     break;
00681 
00682 #ifndef _NO_EXTENSIONS
00683                 case ID_VIEW_FULLSCREEN:
00684                     CheckMenuItem(Globals.hMenuOptions, cmd, toggle_fullscreen(hwnd)?MF_CHECKED:0);
00685                     break;
00686 
00687 #ifdef __WINE__
00688                 case ID_DRIVE_UNIX_FS: {
00689                     TCHAR path[MAX_PATH];
00690 #ifdef UNICODE
00691                     char cpath[MAX_PATH];
00692 #endif
00693                     ChildWnd* child;
00694 
00695                     if (activate_fs_window(RS(b1,IDS_UNIXFS)))
00696                         break;
00697 
00698 
00699 #ifdef UNICODE
00700                     getcwd(cpath, MAX_PATH);
00701                     MultiByteToWideChar(CP_UNIXCP, 0, cpath, -1, path, MAX_PATH);
00702 #else
00703                     getcwd(path, MAX_PATH);
00704 #endif
00705                     child = alloc_child_window(path, NULL, hwnd);
00706 
00707                     if (!create_child_window(child))
00708                         heap_free(child);
00709                     break;}
00710 #endif
00711 
00712 #ifdef _SHELL_FOLDERS
00713                 case ID_DRIVE_SHELL_NS: {
00714                     TCHAR path[MAX_PATH];
00715                     ChildWnd* child;
00716 
00717                     if (activate_fs_window(RS(b1,IDS_SHELL)))
00718                         break;
00719 
00720                     GetCurrentDirectory(MAX_PATH, path);
00721                     child = alloc_child_window(path, get_path_pidl(path,hwnd), hwnd);
00722 
00723                     if (!create_child_window(child))
00724                         heap_free(child);
00725                     break;}
00726 #endif
00727 #endif
00728 
00729                 /*TODO: There are even more menu items! */
00730 
00731                 case ID_ABOUT:
00732                     ShellAbout(hwnd, RS(b1,IDS_WINEFILE), NULL,
00733                                LoadImage(Globals.hInstance, MAKEINTRESOURCE(IDI_WINEFILE),
00734                                          IMAGE_ICON, 48, 48, LR_SHARED));
00735                     break;
00736 
00737                 default:
00738                     /*TODO: if (wParam >= PM_FIRST_LANGUAGE && wParam <= PM_LAST_LANGUAGE)
00739                         STRING_SelectLanguageByNumber(wParam - PM_FIRST_LANGUAGE);
00740                     else */if ((cmd<IDW_FIRST_CHILD || cmd>=IDW_FIRST_CHILD+0x100) &&
00741                         (cmd<SC_SIZE || cmd>SC_RESTORE))
00742                         MessageBox(hwnd, RS(b2,IDS_NO_IMPL), RS(b1,IDS_WINEFILE), MB_OK);
00743 
00744                     return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
00745             }
00746             break;}
00747 
00748         case WM_SIZE:
00749             resize_frame(hwnd, LOWORD(lparam), HIWORD(lparam));
00750             break;  /* do not pass message to DefFrameProc */
00751 
00752         case WM_DEVICECHANGE:
00753             SendMessage(hwnd, WM_COMMAND, MAKELONG(ID_REFRESH,0), 0);
00754             break;
00755 
00756 #ifndef _NO_EXTENSIONS
00757         case WM_GETMINMAXINFO: {
00758             LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
00759 
00760             lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
00761             lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
00762             break;}
00763 
00764         case FRM_CALC_CLIENT:
00765             frame_get_clientspace(hwnd, (PRECT)lparam);
00766             return TRUE;
00767 #endif /* _NO_EXTENSIONS */
00768 
00769         default:
00770             return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
00771     }
00772 
00773     return 0;
00774 }
00775 
00776 
00777 /* array of item attribute names, filled from ressource strings */
00778 static TCHAR g_pos_names[COLUMNS][20] = {
00779     {'\0'}  /* symbol */
00780 };
00781 
00782 /* array of item attribute flags  */
00783 static const int g_pos_align[] = {
00784     0,
00785     HDF_LEFT,   /* Name */
00786     HDF_RIGHT,  /* Size */
00787     HDF_LEFT,   /* CDate */
00788 #ifndef _NO_EXTENSIONS
00789     HDF_LEFT,   /* ADate */
00790     HDF_LEFT,   /* MDate */
00791     HDF_LEFT,   /* Index */
00792     HDF_CENTER, /* Links */
00793 #endif
00794     HDF_CENTER, /* Attributes */
00795 #ifndef _NO_EXTENSIONS
00796     HDF_LEFT    /* Security */
00797 #endif
00798 };
00799 
00800 /* resize child window descendants */
00801 static void resize_tree(ChildWnd* child, int cx, int cy)
00802 {
00803     HDWP hdwp = BeginDeferWindowPos(4);
00804     RECT rt;
00805 
00806     rt.left   = 0;
00807     rt.top    = 0;
00808     rt.right  = cx;
00809     rt.bottom = cy;
00810 
00811     cx = child->split_pos + SPLIT_WIDTH/2;
00812 
00813 #ifndef _NO_EXTENSIONS
00814     {
00815         WINDOWPOS wp;
00816         HD_LAYOUT hdl;
00817 
00818         hdl.prc   = &rt;
00819         hdl.pwpos = &wp;
00820 
00821         (void)Header_Layout(child->left.hwndHeader, &hdl);
00822 
00823         DeferWindowPos(hdwp, child->left.hwndHeader, wp.hwndInsertAfter,
00824                         wp.x-1, wp.y, child->split_pos-SPLIT_WIDTH/2+1, wp.cy, wp.flags);
00825         DeferWindowPos(hdwp, child->right.hwndHeader, wp.hwndInsertAfter,
00826                         rt.left+cx+1, wp.y, wp.cx-cx+2, wp.cy, wp.flags);
00827     }
00828 #endif /* _NO_EXTENSIONS */
00829 
00830     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);
00831     DeferWindowPos(hdwp, child->right.hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
00832 
00833     EndDeferWindowPos(hdwp);
00834 }
00835 
00836 
00837 #ifndef _NO_EXTENSIONS
00838 
00839 /* create the header control for the given pane */
00840 static HWND create_header(HWND parent, Pane* pane, UINT id)
00841 {
00842     HD_ITEM hdi;
00843     int idx;
00844 
00845     HWND hwnd = CreateWindow(WC_HEADER, 0, WS_CHILD|WS_VISIBLE|HDS_HORZ|HDS_FULLDRAG/*TODO: |HDS_BUTTONS + sort orders*/,
00846                              0, 0, 0, 0, parent, (HMENU)ULongToHandle(id), Globals.hInstance, 0);
00847     if (!hwnd)
00848         return 0;
00849 
00850     SetWindowFont(hwnd, GetStockObject(DEFAULT_GUI_FONT), FALSE);
00851 
00852     hdi.mask = HDI_TEXT|HDI_WIDTH|HDI_FORMAT;
00853 
00854     for(idx=0; idx<COLUMNS; idx++) {
00855         hdi.pszText = g_pos_names[idx];
00856         hdi.fmt = HDF_STRING | g_pos_align[idx];
00857         hdi.cxy = pane->widths[idx];
00858         (void)Header_InsertItem(hwnd, idx, &hdi);
00859     }
00860 
00861     return hwnd;
00862 }
00863 
00864 #endif /* _NO_EXTENSIONS */
00865 
00866 
00867 /* initialise global variables for text output */
00868 
00869 static void init_output(HWND hwnd)
00870 {
00871     static const TCHAR s1000[] = {'1','0','0','0','\0'};
00872 
00873     TCHAR b[16];
00874     HFONT old_font;
00875     HDC hdc = GetDC(hwnd);
00876 
00877     if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, s1000, 0, b, 16) > 4)
00878         Globals.num_sep = b[1];
00879     else
00880         Globals.num_sep = '.';
00881 
00882     old_font = SelectFont(hdc, Globals.hfont);
00883     GetTextExtentPoint32(hdc, sSpace, 1, &Globals.spaceSize);
00884     (void)SelectFont(hdc, old_font);
00885     ReleaseDC(hwnd, hdc);
00886 }
00887 
00888 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol);
00889 
00890 
00891 /* calculate preferred width for all visible columns */
00892 
00893 static BOOL calc_widths(Pane* pane, BOOL anyway)
00894 {
00895     int col, x, cx, spc=3*Globals.spaceSize.cx;
00896     int entries = ListBox_GetCount(pane->hwnd);
00897     int orgWidths[COLUMNS];
00898     int orgPositions[COLUMNS+1];
00899     HFONT hfontOld;
00900     HDC hdc;
00901     int cnt;
00902 
00903     if (!anyway) {
00904         memcpy(orgWidths, pane->widths, sizeof(orgWidths));
00905         memcpy(orgPositions, pane->positions, sizeof(orgPositions));
00906     }
00907 
00908     for(col=0; col<COLUMNS; col++)
00909         pane->widths[col] = 0;
00910 
00911     hdc = GetDC(pane->hwnd);
00912     hfontOld = SelectFont(hdc, Globals.hfont);
00913 
00914     for(cnt=0; cnt<entries; cnt++) {
00915         Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, cnt);
00916 
00917         DRAWITEMSTRUCT dis;
00918 
00919         dis.CtlType       = 0;
00920         dis.CtlID         = 0;
00921         dis.itemID        = 0;
00922         dis.itemAction    = 0;
00923         dis.itemState     = 0;
00924         dis.hwndItem      = pane->hwnd;
00925         dis.hDC           = hdc;
00926         dis.rcItem.left   = 0;
00927         dis.rcItem.top    = 0;
00928         dis.rcItem.right  = 0;
00929         dis.rcItem.bottom = 0;
00930         /*dis.itemData    = 0; */
00931 
00932         draw_item(pane, &dis, entry, COLUMNS);
00933     }
00934 
00935     SelectObject(hdc, hfontOld);
00936     ReleaseDC(pane->hwnd, hdc);
00937 
00938     x = 0;
00939     for(col=0; col<COLUMNS; col++) {
00940         pane->positions[col] = x;
00941         cx = pane->widths[col];
00942 
00943         if (cx) {
00944             cx += spc;
00945 
00946             if (cx < IMAGE_WIDTH)
00947                 cx = IMAGE_WIDTH;
00948 
00949             pane->widths[col] = cx;
00950         }
00951 
00952         x += cx;
00953     }
00954 
00955     pane->positions[COLUMNS] = x;
00956 
00957     ListBox_SetHorizontalExtent(pane->hwnd, x);
00958 
00959     /* no change? */
00960     if (!memcmp(orgWidths, pane->widths, sizeof(orgWidths)))
00961         return FALSE;
00962 
00963     /* don't move, if only collapsing an entry */
00964     if (!anyway && pane->widths[0]<orgWidths[0] &&
00965         !memcmp(orgWidths+1, pane->widths+1, sizeof(orgWidths)-sizeof(int))) {
00966         pane->widths[0] = orgWidths[0];
00967         memcpy(pane->positions, orgPositions, sizeof(orgPositions));
00968 
00969         return FALSE;
00970     }
00971 
00972     InvalidateRect(pane->hwnd, 0, TRUE);
00973 
00974     return TRUE;
00975 }
00976 
00977 
00978 /* calculate one preferred column width */
00979 
00980 static void calc_single_width(Pane* pane, int col)
00981 {
00982     HFONT hfontOld;
00983     int x, cx;
00984     int entries = ListBox_GetCount(pane->hwnd);
00985     int cnt;
00986     HDC hdc;
00987 
00988     pane->widths[col] = 0;
00989 
00990     hdc = GetDC(pane->hwnd);
00991     hfontOld = SelectFont(hdc, Globals.hfont);
00992 
00993     for(cnt=0; cnt<entries; cnt++) {
00994         Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, cnt);
00995         DRAWITEMSTRUCT dis;
00996 
00997         dis.CtlType       = 0;
00998         dis.CtlID         = 0;
00999         dis.itemID        = 0;
01000         dis.itemAction    = 0;
01001         dis.itemState     = 0;
01002         dis.hwndItem      = pane->hwnd;
01003         dis.hDC           = hdc;
01004         dis.rcItem.left   = 0;
01005         dis.rcItem.top    = 0;
01006         dis.rcItem.right  = 0;
01007         dis.rcItem.bottom = 0;
01008         /*dis.itemData    = 0; */
01009 
01010         draw_item(pane, &dis, entry, col);
01011     }
01012 
01013     SelectObject(hdc, hfontOld);
01014     ReleaseDC(pane->hwnd, hdc);
01015 
01016     cx = pane->widths[col];
01017 
01018     if (cx) {
01019         cx += 3*Globals.spaceSize.cx;
01020 
01021         if (cx < IMAGE_WIDTH)
01022             cx = IMAGE_WIDTH;
01023     }
01024 
01025     pane->widths[col] = cx;
01026 
01027     x = pane->positions[col] + cx;
01028 
01029     for(; col<COLUMNS; ) {
01030         pane->positions[++col] = x;
01031         x += pane->widths[col];
01032     }
01033 
01034     ListBox_SetHorizontalExtent(pane->hwnd, x);
01035 }
01036 
01037 
01038 /* check for file name matches, taking case into account */
01039 
01040 static BOOL pattern_match(LPCTSTR str, LPCTSTR pattern)
01041 {
01042     for( ; *str&&*pattern; str++,pattern++) {
01043         if (*pattern == '*') {
01044             do pattern++;
01045             while(*pattern == '*');
01046 
01047             if (!*pattern)
01048                 return TRUE;
01049 
01050             for(; *str; str++)
01051                 if (*str==*pattern && pattern_match(str, pattern))
01052                     return TRUE;
01053 
01054             return FALSE;
01055         }
01056         else if (*str!=*pattern && *pattern!='?')
01057             return FALSE;
01058     }
01059 
01060     if (*str || *pattern)
01061         if (*pattern!='*' || pattern[1]!='\0')
01062             return FALSE;
01063 
01064     return TRUE;
01065 }
01066 
01067 
01068 /* case independent file name matching algorithm */
01069 
01070 static BOOL pattern_imatch(LPCTSTR str, LPCTSTR pattern)
01071 {
01072     TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
01073 
01074     lstrcpy(b1, str);
01075     lstrcpy(b2, pattern);
01076     CharUpper(b1);
01077     CharUpper(b2);
01078 
01079     return pattern_match(b1, b2);
01080 }
01081 
01082 
01083 /* file type constants */
01084 enum FILE_TYPE {
01085     FT_OTHER        = 0,
01086     FT_EXECUTABLE   = 1,
01087     FT_DOCUMENT     = 2
01088 };
01089 
01090 static enum FILE_TYPE get_file_type(LPCTSTR filename);
01091 
01092 
01093 /* insert listbox entries after index idx */
01094 
01095 static int insert_entries(Pane* pane, Entry* dir, LPCTSTR pattern, int filter_flags, int idx)
01096 {
01097     Entry* entry = dir;
01098 
01099     if (!entry)
01100         return idx;
01101 
01102     ShowWindow(pane->hwnd, SW_HIDE);
01103 
01104     for(; entry; entry=entry->next) {
01105 #ifndef _LEFT_FILES
01106         if (pane->treePane && !(entry->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
01107             continue;
01108 #endif
01109 
01110         if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
01111             /* don't display entries "." and ".." in the left pane */
01112             if (pane->treePane && entry->data.cFileName[0]=='.')
01113                 if (
01114 #ifndef _NO_EXTENSIONS
01115                     entry->data.cFileName[1]=='\0' ||
01116 #endif
01117                     (entry->data.cFileName[1]=='.' && entry->data.cFileName[2]=='\0'))
01118                     continue;
01119 
01120             /* filter directories in right pane */
01121             if (!pane->treePane && !(filter_flags&TF_DIRECTORIES))
01122                 continue;
01123         }
01124 
01125         /* filter using the file name pattern */
01126         if (pattern)
01127             if (!pattern_imatch(entry->data.cFileName, pattern))
01128                 continue;
01129 
01130         /* filter system and hidden files */
01131         if (!(filter_flags&TF_HIDDEN) && (entry->data.dwFileAttributes&(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)))
01132             continue;
01133 
01134         /* filter looking at the file type */
01135         if ((filter_flags&(TF_PROGRAMS|TF_DOCUMENTS|TF_OTHERS)) != (TF_PROGRAMS|TF_DOCUMENTS|TF_OTHERS))
01136             switch(get_file_type(entry->data.cFileName)) {
01137               case FT_EXECUTABLE:
01138                 if (!(filter_flags & TF_PROGRAMS))
01139                     continue;
01140                 break;
01141 
01142               case FT_DOCUMENT:
01143                 if (!(filter_flags & TF_DOCUMENTS))
01144                     continue;
01145                 break;
01146 
01147               default: /* TF_OTHERS */
01148                 if (!(filter_flags & TF_OTHERS))
01149                     continue;
01150             }
01151 
01152         if (idx != -1)
01153             idx++;
01154 
01155         (void)ListBox_InsertItemData(pane->hwnd, idx, entry);
01156 
01157         if (pane->treePane && entry->expanded)
01158             idx = insert_entries(pane, entry->down, pattern, filter_flags, idx);
01159     }
01160 
01161     ShowWindow(pane->hwnd, SW_SHOW);
01162 
01163     return idx;
01164 }
01165 
01166 
01167 /* print a file size as textual representation into the given character buffer */
01168 static void format_bytes(LPTSTR buffer, LONGLONG bytes)
01169 {
01170     static const TCHAR sFmtGB[] = {'%', '.', '1', 'f', ' ', 'G', 'B', '\0'};
01171     static const TCHAR sFmtMB[] = {'%', '.', '1', 'f', ' ', 'M', 'B', '\0'};
01172     static const TCHAR sFmtkB[] = {'%', '.', '1', 'f', ' ', 'k', 'B', '\0'};
01173 
01174     float fBytes = (float)bytes;
01175 
01176     if (bytes >= 1073741824)    /* 1 GB */
01177         _stprintf(buffer, sFmtGB, fBytes/1073741824.f+.5f);
01178     else if (bytes >= 1048576)  /* 1 MB */
01179         _stprintf(buffer, sFmtMB, fBytes/1048576.f+.5f);
01180     else if (bytes >= 1024)     /* 1 kB */
01181         _stprintf(buffer, sFmtkB, fBytes/1024.f+.5f);
01182     else
01183         _stprintf(buffer, sLongNumFmt, bytes);
01184 }
01185 
01186 /* display free space of the current drive in the status bar */
01187 static void set_space_status(void)
01188 {
01189     ULARGE_INTEGER ulFreeBytesToCaller, ulTotalBytes, ulFreeBytes;
01190     TCHAR fmt[64], b1[64], b2[64], buffer[BUFFER_LEN];
01191 
01192     if (GetDiskFreeSpaceEx(NULL, &ulFreeBytesToCaller, &ulTotalBytes, &ulFreeBytes)) {
01193         format_bytes(b1, ulFreeBytesToCaller.QuadPart);
01194         format_bytes(b2, ulTotalBytes.QuadPart);
01195         wsprintf(buffer, RS(fmt,IDS_FREE_SPACE_FMT), b1, b2);
01196     } else
01197         lstrcpy(buffer, sQMarks);
01198 
01199     SendMessage(Globals.hstatusbar, SB_SETTEXT, 0, (LPARAM)buffer);
01200 }
01201 
01202 
01203 #ifndef _NO_EXTENSIONS
01204 
01205 /* initialise the header control for a Winefile pane */
01206 static void set_header(Pane* pane)
01207 {
01208     HD_ITEM item;
01209     int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
01210     int i=0, x=0;
01211 
01212     item.mask = HDI_WIDTH;
01213     item.cxy = 0;
01214 
01215     for(; x+pane->widths[i]<scroll_pos && i<COLUMNS; i++) {
01216         x += pane->widths[i];
01217         (void)Header_SetItem(pane->hwndHeader, i, &item);
01218     }
01219 
01220     if (i < COLUMNS) {
01221         x += pane->widths[i];
01222         item.cxy = x - scroll_pos;
01223         (void)Header_SetItem(pane->hwndHeader, i++, &item);
01224 
01225         for(; i<COLUMNS; i++) {
01226             item.cxy = pane->widths[i];
01227             x += pane->widths[i];
01228             (void)Header_SetItem(pane->hwndHeader, i, &item);
01229         }
01230     }
01231 }
01232 
01233 /* handle WM_NOTIFY messages for Winefile panes */
01234 static LRESULT pane_notify(Pane* pane, NMHDR* pnmh)
01235 {
01236     switch(pnmh->code) {
01237         case HDN_ITEMCHANGED: {
01238             HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
01239             int idx = phdn->iItem;
01240             int dx = phdn->pitem->cxy - pane->widths[idx];
01241             int i;
01242 
01243             RECT clnt;
01244             GetClientRect(pane->hwnd, &clnt);
01245 
01246             pane->widths[idx] += dx;
01247 
01248             for(i=idx; ++i<=COLUMNS; )
01249                 pane->positions[i] += dx;
01250 
01251             {
01252                 int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
01253                 RECT rt_scr;
01254                 RECT rt_clip;
01255 
01256                 rt_scr.left   = pane->positions[idx+1]-scroll_pos;
01257                 rt_scr.top    = 0;
01258                 rt_scr.right  = clnt.right;
01259                 rt_scr.bottom = clnt.bottom;
01260 
01261                 rt_clip.left   = pane->positions[idx]-scroll_pos;
01262                 rt_clip.top    = 0;
01263                 rt_clip.right  = clnt.right;
01264                 rt_clip.bottom = clnt.bottom;
01265 
01266                 if (rt_scr.left < 0) rt_scr.left = 0;
01267                 if (rt_clip.left < 0) rt_clip.left = 0;
01268 
01269                 ScrollWindowEx(pane->hwnd, dx, 0, &rt_scr, &rt_clip, 0, 0, SW_INVALIDATE);
01270 
01271                 rt_clip.right = pane->positions[idx+1];
01272                 RedrawWindow(pane->hwnd, &rt_clip, 0, RDW_INVALIDATE|RDW_UPDATENOW);
01273 
01274                 if (pnmh->code == HDN_ENDTRACK) {
01275                     ListBox_SetHorizontalExtent(pane->hwnd, pane->positions[COLUMNS]);
01276 
01277                     if (GetScrollPos(pane->hwnd, SB_HORZ) != scroll_pos)
01278                         set_header(pane);
01279                 }
01280             }
01281 
01282             return FALSE;
01283         }
01284 
01285         case HDN_DIVIDERDBLCLICK: {
01286             HD_NOTIFY* phdn = (HD_NOTIFY*) pnmh;
01287             HD_ITEM item;
01288 
01289             calc_single_width(pane, phdn->iItem);
01290             item.mask = HDI_WIDTH;
01291             item.cxy = pane->widths[phdn->iItem];
01292 
01293             (void)Header_SetItem(pane->hwndHeader, phdn->iItem, &item);
01294             InvalidateRect(pane->hwnd, 0, TRUE);
01295             break;}
01296     }
01297 
01298     return 0;
01299 }
01300 
01301 #endif /* _NO_EXTENSIONS */
01302 
01303 
01304 /* original tree window message handler */
01305 static WNDPROC g_orgTreeWndProc;
01306 
01307 /* tree window message handler */
01308 static LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
01309 {
01310     ChildWnd* child = (ChildWnd*) GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
01311     Pane* pane = (Pane*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
01312     ASSERT(child);
01313 
01314     switch(nmsg) {
01315 #ifndef _NO_EXTENSIONS
01316         case WM_HSCROLL:
01317             set_header(pane);
01318             break;
01319 #endif
01320 
01321         case WM_SETFOCUS:
01322             child->focus_pane = pane==&child->right? 1: 0;
01323             (void)ListBox_SetSel(hwnd, TRUE, 1);
01324             /*TODO: check menu items */
01325             break;
01326 
01327         case WM_KEYDOWN:
01328             if (wparam == VK_TAB) {
01329                 /*TODO: SetFocus(Globals.hdrivebar) */
01330                 SetFocus(child->focus_pane? child->left.hwnd: child->right.hwnd);
01331             }
01332     }
01333 
01334     return CallWindowProc(g_orgTreeWndProc, hwnd, nmsg, wparam, lparam);
01335 }
01336 
01337 
01338 /* create a new tree window to be used as Winefile pane */
01339 
01340 static void create_tree_window(HWND parent, Pane* pane, UINT id, UINT id_header, LPCTSTR pattern, int filter_flags)
01341 {
01342     static const TCHAR sListBox[] = {'L','i','s','t','B','o','x','\0'};
01343 
01344     static int s_init = 0;
01345     Entry* entry = pane->root;
01346 
01347     pane->hwnd = CreateWindow(sListBox, sEmpty, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
01348                                 LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED|LBS_NOTIFY,
01349                                 0, 0, 0, 0, parent, (HMENU)ULongToHandle(id), Globals.hInstance, 0);
01350 
01351     SetWindowLongPtr(pane->hwnd, GWLP_USERDATA, (LPARAM)pane);
01352     g_orgTreeWndProc = SubclassWindow(pane->hwnd, TreeWndProc);
01353 
01354     SetWindowFont(pane->hwnd, Globals.hfont, FALSE);
01355 
01356     /* insert entries into listbox */
01357     if (entry)
01358         insert_entries(pane, entry, pattern, filter_flags, -1);
01359 
01360     /* calculate column widths */
01361     if (!s_init) {
01362         s_init = 1;
01363         init_output(pane->hwnd);
01364     }
01365 
01366     calc_widths(pane, TRUE);
01367 
01368 #ifndef _NO_EXTENSIONS
01369     pane->hwndHeader = create_header(parent, pane, id_header);
01370 #endif
01371 }
01372 
01373 
01374 /* initialise child window data */
01375 
01376 static void InitChildWindow(ChildWnd* child)
01377 {
01378     create_tree_window(child->hwnd, &child->left, IDW_TREE_LEFT, IDW_HEADER_LEFT, NULL, TF_ALL);
01379     create_tree_window(child->hwnd, &child->right, IDW_TREE_RIGHT, IDW_HEADER_RIGHT, child->filter_pattern, child->filter_flags);
01380 }
01381 
01382 
01383 /* print a FILETIME as textual representation */
01384 
01385 void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols)
01386 {
01387     SYSTEMTIME systime;
01388     FILETIME lft;
01389     int len = 0;
01390 
01391     *buffer = '\0';
01392 
01393     if (!ft->dwLowDateTime && !ft->dwHighDateTime)
01394         return;
01395 
01396     if (!FileTimeToLocalFileTime(ft, &lft))
01397         {err: lstrcpy(buffer,sQMarks); return;}
01398 
01399     if (!FileTimeToSystemTime(&lft, &systime))
01400         goto err;
01401 
01402     if (visible_cols & COL_DATE) {
01403         len = GetDateFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer, BUFFER_LEN);
01404         if (!len)
01405             goto err;
01406     }
01407 
01408     if (visible_cols & COL_TIME) {
01409         if (len)
01410             buffer[len-1] = ' ';
01411 
01412         buffer[len++] = ' ';
01413 
01414         if (!GetTimeFormat(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer+len, BUFFER_LEN-len))
01415             buffer[len] = '\0';
01416     }
01417 }
01418 
01419 
01420 /* accumulate the maximum pane width for the given text */
01421 static void calc_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
01422 {
01423     RECT rt = {0, 0, 0, 0};
01424 
01425     DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
01426 
01427     if (rt.right > pane->widths[col])
01428         pane->widths[col] = rt.right;
01429 }
01430 
01431 /* accumulate the maximum oane width for the given text, taking tabs into account */
01432 static void calc_tabbed_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
01433 {
01434     RECT rt = {0, 0, 0, 0};
01435 
01436 /*  DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
01437     DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
01438 
01439     DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
01440     /*FIXME rt (0,0) ??? */
01441 
01442     if (rt.right > pane->widths[col])
01443         pane->widths[col] = rt.right;
01444 }
01445 
01446 
01447 /* display text in a Winefile pane */
01448 static void output_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str, DWORD flags)
01449 {
01450     int x = dis->rcItem.left;
01451     RECT rt;
01452 
01453     rt.left   = x+pane->positions[col]+Globals.spaceSize.cx;
01454     rt.top    = dis->rcItem.top;
01455     rt.right  = x+pane->positions[col+1]-Globals.spaceSize.cx;
01456     rt.bottom = dis->rcItem.bottom;
01457 
01458     DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|flags);
01459 }
01460 
01461 /* display text in a Winefile pane, formated by tabulator characters */
01462 static void output_tabbed_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
01463 {
01464     int x = dis->rcItem.left;
01465     RECT rt;
01466 
01467     rt.left   = x+pane->positions[col]+Globals.spaceSize.cx;
01468     rt.top    = dis->rcItem.top;
01469     rt.right  = x+pane->positions[col+1]-Globals.spaceSize.cx;
01470     rt.bottom = dis->rcItem.bottom;
01471 
01472 /*  DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
01473     DrawTextEx(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
01474 
01475     DrawText(dis->hDC, (LPTSTR)str, -1, &rt, DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
01476 }
01477 
01478 /* display numbers in a Winefile pane */
01479 static void output_number(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str)
01480 {
01481     int x = dis->rcItem.left;
01482     RECT rt;
01483     LPCTSTR s = str;
01484     TCHAR b[128];
01485     LPTSTR d = b;
01486     int pos;
01487 
01488     rt.left   = x+pane->positions[col]+Globals.spaceSize.cx;
01489     rt.top    = dis->rcItem.top;
01490     rt.right  = x+pane->positions[col+1]-Globals.spaceSize.cx;
01491     rt.bottom = dis->rcItem.bottom;
01492 
01493     if (*s)
01494         *d++ = *s++;
01495 
01496     /* insert number separator characters */
01497     pos = lstrlen(s) % 3;
01498 
01499     while(*s)
01500         if (pos--)
01501             *d++ = *s++;
01502         else {
01503             *d++ = Globals.num_sep;
01504             pos = 3;
01505         }
01506 
01507     DrawText(dis->hDC, b, d-b, &rt, DT_RIGHT|DT_SINGLELINE|DT_NOPREFIX|DT_END_ELLIPSIS);
01508 }
01509 
01510 
01511 /* check for executable filename extensions */
01512 static BOOL is_exe_file(LPCTSTR ext)
01513 {
01514     static const TCHAR executable_extensions[][4] = {
01515         {'C','O','M','\0'},
01516         {'E','X','E','\0'},
01517         {'B','A','T','\0'},
01518         {'C','M','D','\0'},
01519 #ifndef _NO_EXTENSIONS
01520         {'C','M','M','\0'},
01521         {'B','T','M','\0'},
01522         {'A','W','K','\0'},
01523 #endif /* _NO_EXTENSIONS */
01524         {'\0'}
01525     };
01526 
01527     TCHAR ext_buffer[_MAX_EXT];
01528     const TCHAR (*p)[4];
01529     LPCTSTR s;
01530     LPTSTR d;
01531 
01532     for(s=ext+1,d=ext_buffer; (*d=tolower(*s)); s++)
01533         d++;
01534 
01535     for(p=executable_extensions; (*p)[0]; p++)
01536         if (!lstrcmpi(ext_buffer, *p))
01537             return TRUE;
01538 
01539     return FALSE;
01540 }
01541 
01542 /* check is the given file name extension is present in the Registry */
01543 static BOOL is_registered_type(LPCTSTR ext)
01544 {
01545     /* check if there exists a classname for this file extension in the registry */
01546     if (!RegQueryValue(HKEY_CLASSES_ROOT, ext, NULL, NULL))
01547         return TRUE;
01548 
01549     return FALSE;
01550 }
01551 
01552 /* determine file type from filename */
01553 static enum FILE_TYPE get_file_type(LPCTSTR filename)
01554 {
01555     LPCTSTR ext = _tcsrchr(filename, '.');
01556     if (!ext)
01557         ext = sEmpty;
01558 
01559     if (is_exe_file(ext))
01560         return FT_EXECUTABLE;
01561     else if (is_registered_type(ext))
01562         return FT_DOCUMENT;
01563     else
01564         return FT_OTHER;
01565 }
01566 
01567 
01568 /* display a entry in a Winefile pane */
01569 
01570 //@@ TODO refactor into smaller functions
01571 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
01572 {
01573     TCHAR buffer[BUFFER_LEN];
01574     DWORD attrs;
01575     int visible_cols = pane->visible_cols;
01576     COLORREF bkcolor, textcolor;
01577     RECT focusRect = dis->rcItem;
01578     HBRUSH hbrush;
01579     enum IMAGE img;
01580     int img_pos, cx;
01581     int col = 0;
01582 
01583     if (entry) {
01584         attrs = entry->data.dwFileAttributes;
01585 
01586         if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
01587             if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='.'
01588                     && entry->data.cFileName[2]=='\0')
01589                 img = IMG_FOLDER_UP;
01590 #ifndef _NO_EXTENSIONS
01591             else if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='\0')
01592                 img = IMG_FOLDER_CUR;
01593 #endif
01594             else if (
01595 #ifdef _NO_EXTENSIONS
01596                      entry->expanded ||
01597 #endif
01598                      (pane->treePane && (dis->itemState&ODS_FOCUS)))
01599                 img = IMG_OPEN_FOLDER;
01600             else
01601                 img = IMG_FOLDER;
01602         } else {
01603             switch(get_file_type(entry->data.cFileName)) {
01604               case FT_EXECUTABLE:   img = IMG_EXECUTABLE;   break;
01605               case FT_DOCUMENT:     img = IMG_DOCUMENT;     break;
01606               default:              img = IMG_FILE;
01607             }
01608         }
01609     } else {
01610         attrs = 0;
01611         img = IMG_NONE;
01612     }
01613 
01614     if (pane->treePane) {
01615         if (entry) {
01616             img_pos = dis->rcItem.left + entry->level*(IMAGE_WIDTH+TREE_LINE_DX);
01617 
01618             if (calcWidthCol == -1) {
01619                 int x;
01620                 int y = dis->rcItem.top + IMAGE_HEIGHT/2;
01621                 Entry* up;
01622                 RECT rt_clip;
01623                 HRGN hrgn_org = CreateRectRgn(0, 0, 0, 0);
01624                 HRGN hrgn;
01625 
01626                 rt_clip.left   = dis->rcItem.left;
01627                 rt_clip.top    = dis->rcItem.top;
01628                 rt_clip.right  = dis->rcItem.left+pane->widths[col];
01629                 rt_clip.bottom = dis->rcItem.bottom;
01630 
01631                 hrgn = CreateRectRgnIndirect(&rt_clip);
01632 
01633                 if (!GetClipRgn(dis->hDC, hrgn_org)) {
01634                     DeleteObject(hrgn_org);
01635                     hrgn_org = 0;
01636                 }
01637 
01638                 /* HGDIOBJ holdPen = SelectObject(dis->hDC, GetStockObject(BLACK_PEN)); */
01639                 ExtSelectClipRgn(dis->hDC, hrgn, RGN_AND);
01640                 DeleteObject(hrgn);
01641 
01642                 if ((up=entry->up) != NULL) {
01643                     MoveToEx(dis->hDC, img_pos-IMAGE_WIDTH/2, y, 0);
01644                     LineTo(dis->hDC, img_pos-2, y);
01645 
01646                     x = img_pos - IMAGE_WIDTH/2;
01647 
01648                     do {
01649                         x -= IMAGE_WIDTH+TREE_LINE_DX;
01650 
01651                         if (up->next
01652 #ifndef _LEFT_FILES
01653                             && (up->next->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01654 #endif
01655                             ) {
01656                             MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
01657                             LineTo(dis->hDC, x, dis->rcItem.bottom);
01658                         }
01659                     } while((up=up->up) != NULL);
01660                 }
01661 
01662                 x = img_pos - IMAGE_WIDTH/2;
01663 
01664                 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
01665                 LineTo(dis->hDC, x, y);
01666 
01667                 if (entry->next
01668 #ifndef _LEFT_FILES
01669                     && (entry->next->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
01670 #endif
01671                     )
01672                     LineTo(dis->hDC, x, dis->rcItem.bottom);
01673 
01674                 SelectClipRgn(dis->hDC, hrgn_org);
01675                 if (hrgn_org) DeleteObject(hrgn_org);
01676                 /* SelectObject(dis->hDC, holdPen); */
01677             } else if (calcWidthCol==col || calcWidthCol==COLUMNS) {
01678                 int right = img_pos + IMAGE_WIDTH - TREE_LINE_DX;
01679 
01680                 if (right > pane->widths[col])
01681                     pane->widths[col] = right;
01682             }
01683         } else  {
01684             img_pos = dis->rcItem.left;
01685         }
01686     } else {
01687         img_pos = dis->rcItem.left;
01688 
01689         if (calcWidthCol==col || calcWidthCol==COLUMNS)
01690             pane->widths[col] = IMAGE_WIDTH;
01691     }
01692 
01693     if (calcWidthCol == -1) {
01694         focusRect.left = img_pos - 2;
01695 
01696 #ifdef _NO_EXTENSIONS
01697         if (pane->treePane && entry) {
01698             RECT rt = {0};
01699 
01700             DrawText(dis->hDC, entry->data.cFileName, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
01701 
01702             focusRect.right = dis->rcItem.left+pane->positions[col+1]+TREE_LINE_DX + rt.right +2;
01703         }
01704 #else
01705 
01706         if (attrs & FILE_ATTRIBUTE_COMPRESSED)
01707             textcolor = COLOR_COMPRESSED;
01708         else
01709 #endif /* _NO_EXTENSIONS */
01710             textcolor = RGB(0,0,0);
01711 
01712         if (dis->itemState & ODS_FOCUS) {
01713             textcolor = COLOR_SELECTION_TXT;
01714             bkcolor = COLOR_SELECTION;
01715         } else {
01716             bkcolor = GetSysColor(COLOR_WINDOW);
01717         }
01718 
01719         hbrush = CreateSolidBrush(bkcolor);
01720         FillRect(dis->hDC, &focusRect, hbrush);
01721         DeleteObject(hbrush);
01722 
01723         SetBkMode(dis->hDC, TRANSPARENT);
01724         SetTextColor(dis->hDC, textcolor);
01725 
01726         cx = pane->widths[col];
01727 
01728         if (cx && img!=IMG_NONE) {
01729             if (cx > IMAGE_WIDTH)
01730                 cx = IMAGE_WIDTH;
01731 
01732 #ifdef _SHELL_FOLDERS
01733             if (entry->hicon && entry->hicon!=(HICON)-1)
01734                 DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->hicon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
01735             else
01736 #endif
01737                 ImageList_DrawEx(Globals.himl, img, dis->hDC,
01738                                  img_pos, dis->rcItem.top, cx,
01739                                  IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
01740         }
01741     }
01742 
01743     if (!entry)
01744         return;
01745 
01746 #ifdef _NO_EXTENSIONS
01747     if (img >= IMG_FOLDER_UP)
01748         return;
01749 #endif
01750 
01751     col++;
01752 
01753     /* ouput file name */
01754     if (calcWidthCol == -1)
01755         output_text(pane, dis, col, entry->data.cFileName, 0);
01756     else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01757         calc_width(pane, dis, col, entry->data.cFileName);
01758 
01759     col++;
01760 
01761 #ifdef _NO_EXTENSIONS
01762   if (!pane->treePane) {
01763 #endif
01764 
01765         /* display file size */
01766     if (visible_cols & COL_SIZE) {
01767 #ifdef _NO_EXTENSIONS
01768         if (!(attrs&FILE_ATTRIBUTE_DIRECTORY))
01769 #endif
01770         {
01771             ULONGLONG size;
01772 
01773             size = ((ULONGLONG)entry->data.nFileSizeHigh << 32) | entry->data.nFileSizeLow;
01774 
01775             _stprintf(buffer, sLongNumFmt, size);
01776 
01777             if (calcWidthCol == -1)
01778                 output_number(pane, dis, col, buffer);
01779             else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01780                 calc_width(pane, dis, col, buffer);/*TODO: not in every case time enough */
01781         }
01782 
01783         col++;
01784     }
01785 
01786     /* display file date */
01787     if (visible_cols & (COL_DATE|COL_TIME)) {
01788 #ifndef _NO_EXTENSIONS
01789         format_date(&entry->data.ftCreationTime, buffer, visible_cols);
01790         if (calcWidthCol == -1)
01791             output_text(pane, dis, col, buffer, 0);
01792         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01793             calc_width(pane, dis, col, buffer);
01794         col++;
01795 
01796         format_date(&entry->data.ftLastAccessTime, buffer, visible_cols);
01797         if (calcWidthCol == -1)
01798             output_text(pane, dis, col, buffer, 0);
01799         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01800             calc_width(pane, dis, col, buffer);
01801         col++;
01802 #endif /* _NO_EXTENSIONS */
01803 
01804         format_date(&entry->data.ftLastWriteTime, buffer, visible_cols);
01805         if (calcWidthCol == -1)
01806             output_text(pane, dis, col, buffer, 0);
01807         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01808             calc_width(pane, dis, col, buffer);
01809         col++;
01810     }
01811 
01812 #ifndef _NO_EXTENSIONS
01813     if (entry->bhfi_valid) {
01814         ULONGLONG index = ((ULONGLONG)entry->bhfi.nFileIndexHigh << 32) | entry->bhfi.nFileIndexLow;
01815 
01816         if (visible_cols & COL_INDEX) {
01817             _stprintf(buffer, sLongHexFmt, index);
01818 
01819             if (calcWidthCol == -1)
01820                 output_text(pane, dis, col, buffer, DT_RIGHT);
01821             else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01822                 calc_width(pane, dis, col, buffer);
01823 
01824             col++;
01825         }
01826 
01827         if (visible_cols & COL_LINKS) {
01828             wsprintf(buffer, sNumFmt, entry->bhfi.nNumberOfLinks);
01829 
01830             if (calcWidthCol == -1)
01831                 output_text(pane, dis, col, buffer, DT_CENTER);
01832             else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01833                 calc_width(pane, dis, col, buffer);
01834 
01835             col++;
01836         }
01837     } else
01838         col += 2;
01839 #endif /* _NO_EXTENSIONS */
01840 
01841     /* show file attributes */
01842     if (visible_cols & COL_ATTRIBUTES) {
01843 #ifdef _NO_EXTENSIONS
01844         static const TCHAR s4Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
01845         lstrcpy(buffer, s4Tabs);
01846 #else
01847         static const TCHAR s11Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
01848         lstrcpy(buffer, s11Tabs);
01849 #endif
01850 
01851         if (attrs & FILE_ATTRIBUTE_NORMAL)                  buffer[ 0] = 'N';
01852         else {
01853             if (attrs & FILE_ATTRIBUTE_READONLY)            buffer[ 2] = 'R';
01854             if (attrs & FILE_ATTRIBUTE_HIDDEN)              buffer[ 4] = 'H';
01855             if (attrs & FILE_ATTRIBUTE_SYSTEM)              buffer[ 6] = 'S';
01856             if (attrs & FILE_ATTRIBUTE_ARCHIVE)             buffer[ 8] = 'A';
01857             if (attrs & FILE_ATTRIBUTE_COMPRESSED)          buffer[10] = 'C';
01858 #ifndef _NO_EXTENSIONS
01859             if (attrs & FILE_ATTRIBUTE_DIRECTORY)           buffer[12] = 'D';
01860             if (attrs & FILE_ATTRIBUTE_ENCRYPTED)           buffer[14] = 'E';
01861             if (attrs & FILE_ATTRIBUTE_TEMPORARY)           buffer[16] = 'T';
01862             if (attrs & FILE_ATTRIBUTE_SPARSE_FILE)         buffer[18] = 'P';
01863             if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)       buffer[20] = 'Q';
01864             if (attrs & FILE_ATTRIBUTE_OFFLINE)             buffer[22] = 'O';
01865             if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) buffer[24] = 'X';
01866 #endif /* _NO_EXTENSIONS */
01867         }
01868 
01869         if (calcWidthCol == -1)
01870             output_tabbed_text(pane, dis, col, buffer);
01871         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
01872             calc_tabbed_width(pane, dis, col, buffer);
01873 
01874         col++;
01875     }
01876 
01877 /*TODO
01878     if (flags.security) {
01879         static const TCHAR sSecTabs[] = {
01880             ' ','\t',' ','\t',' ','\t',' ',
01881             ' ','\t',' ',
01882             ' ','\t',' ','\t',' ','\t',' ',
01883             ' ','\t',' ',
01884             ' ','\t',' ','\t',' ','\t',' ',
01885             '\0'
01886         };
01887 
01888         DWORD rights = get_access_mask();
01889 
01890         lstrcpy(buffer, sSecTabs);
01891 
01892         if (rights & FILE_READ_DATA)            buffer[ 0] = 'R';
01893         if (rights & FILE_WRITE_DATA)           buffer[ 2] = 'W';
01894         if (rights & FILE_APPEND_DATA)          buffer[ 4] = 'A';
01895         if (rights & FILE_READ_EA)              {buffer[6] = 'entry'; buffer[ 7] = 'R';}
01896         if (rights & FILE_WRITE_EA)             {buffer[9] = 'entry'; buffer[10] = 'W';}
01897         if (rights & FILE_EXECUTE)              buffer[12] = 'X';
01898         if (rights & FILE_DELETE_CHILD)         buffer[14] = 'D';
01899         if (rights & FILE_READ_ATTRIBUTES)      {buffer[16] = 'a'; buffer[17] = 'R';}
01900         if (rights & FILE_WRITE_ATTRIBUTES)     {buffer[19] = 'a'; buffer[20] = 'W';}
01901         if (rights & WRITE_DAC)                 buffer[22] = 'C';
01902         if (rights & WRITE_OWNER)               buffer[24] = 'O';
01903         if (rights & SYNCHRONIZE)               buffer[26] = 'S';
01904 
01905         output_text(dis, col++, buffer, DT_LEFT, 3, psize);
01906     }
01907 
01908     if (flags.description) {
01909         get_description(buffer);
01910         output_text(dis, col++, buffer, 0, psize);
01911     }
01912 */
01913 
01914 #ifdef _NO_EXTENSIONS
01915   }
01916 
01917         /* draw focus frame */
01918     if ((dis->itemState&ODS_FOCUS) && calcWidthCol==-1) {
01919             /* Currently [04/2000] Wine neither behaves exactly the same */
01920             /* way as WIN 95 nor like Windows NT... */
01921         HGDIOBJ lastBrush;
01922         HPEN lastPen;
01923         HPEN hpen;
01924 
01925         if (!(GetVersion() & 0x80000000)) { /* Is the OS already Windows NT compatible? */
01926             LOGBRUSH lb = {PS_SOLID, RGB(255,255,255)};
01927             hpen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
01928         } else
01929             hpen = CreatePen(PS_DOT, 0, RGB(255,255,255));
01930 
01931         lastPen = SelectPen(dis->hDC, hpen);
01932         lastBrush = SelectObject(dis->hDC, GetStockObject(HOLLOW_BRUSH));
01933         SetROP2(dis->hDC, R2_XORPEN);
01934         Rectangle(dis->hDC, focusRect.left, focusRect.top, focusRect.right, focusRect.bottom);
01935         SelectObject(dis->hDC, lastBrush);
01936         SelectObject(dis->hDC, lastPen);
01937         DeleteObject(hpen);
01938     }
01939 #endif /* _NO_EXTENSIONS */
01940 }
01941 
01942 
01943 #ifdef _NO_EXTENSIONS
01944 
01945 /* draw the window split bar when not providing extensions over the original Winfile user interface */
01946 
01947 static void draw_splitbar(HWND hwnd, int x)
01948 {
01949     RECT rt;
01950     HDC hdc = GetDC(hwnd);
01951 
01952     GetClientRect(hwnd, &rt);
01953 
01954     rt.left = x - SPLIT_WIDTH/2;
01955     rt.right = x + SPLIT_WIDTH/2+1;
01956 
01957     InvertRect(hdc, &rt);
01958 
01959     ReleaseDC(hwnd, hdc);
01960 }
01961 
01962 #endif /* _NO_EXTENSIONS */
01963 
01964 
01965 /* scan the content of the given entry node */
01966 
01967 static void scan_entry(ChildWnd* child, Entry* entry, int idx, HWND hwnd)
01968 {
01969     TCHAR path[MAX_PATH];
01970     HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
01971 
01972     /* delete sub entries in left pane */
01973     for(;;) {
01974         LRESULT res = ListBox_GetItemData(child->left.hwnd, idx+1);
01975         Entry* sub = (Entry*) res;
01976 
01977         if (res==LB_ERR || !sub || sub->level<=entry->level)
01978             break;
01979 
01980         (void)ListBox_DeleteString(child->left.hwnd, idx+1);
01981     }
01982 
01983     /* empty right pane */
01984     (void)ListBox_ResetContent(child->right.hwnd);
01985 
01986     /* release memory */
01987     free_entries(entry);
01988 
01989     /* read contents from disk */
01990 #ifdef _SHELL_FOLDERS
01991     if (entry->etype == ET_SHELL)
01992     {
01993         read_directory(entry, NULL, child->sortOrder, hwnd);
01994     }
01995     else
01996 #endif
01997     {
01998         get_path(entry, path);
01999         read_directory(entry, path, child->sortOrder, hwnd);
02000     }
02001 
02002     /* insert found entries in right pane */
02003     insert_entries(&child->right, entry->down, child->filter_pattern, child->filter_flags, -1);
02004     calc_widths(&child->right, FALSE);
02005 #ifndef _NO_EXTENSIONS
02006     set_header(&child->right);
02007 #endif
02008 
02009     child->header_wdths_ok = FALSE;
02010 
02011     SetCursor(old_cursor);
02012 }
02013 
02014 
02015 /* expand a directory entry */
02016 
02017 static BOOL expand_entry(ChildWnd* child, Entry* dir)
02018 {
02019     int idx;
02020     Entry* p;
02021 
02022     if (!dir || dir->expanded || !dir->down)
02023         return FALSE;
02024 
02025     p = dir->down;
02026 
02027     if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='\0' && p->next) {
02028         p = p->next;
02029 
02030         if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='.' &&
02031                 p->data.cFileName[2]=='\0' && p->next)
02032             p = p->next;
02033     }
02034 
02035     /* no subdirectories ? */
02036     if (!(p->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
02037         return FALSE;
02038 
02039     idx = ListBox_FindItemData(child->left.hwnd, 0, dir);
02040 
02041     dir->expanded = TRUE;
02042 
02043     /* insert entries in left pane */
02044     insert_entries(&child->left, p, NULL, TF_ALL, idx);
02045 
02046     if (!child->header_wdths_ok) {
02047         if (calc_widths(&child->left, FALSE)) {
02048 #ifndef _NO_EXTENSIONS
02049             set_header(&child->left);
02050 #endif
02051 
02052             child->header_wdths_ok = TRUE;
02053         }
02054     }
02055 
02056     return TRUE;
02057 }
02058 
02059 
02060 /* close child nodes of the given entry */
02061 
02062 static void collapse_entry(Pane* pane, Entry* dir)
02063 {
02064     int idx = ListBox_FindItemData(pane->hwnd, 0, dir);
02065 
02066     ShowWindow(pane->hwnd, SW_HIDE);
02067 
02068     /* hide sub entries */
02069     for(;;) {
02070         LRESULT res = ListBox_GetItemData(pane->hwnd, idx+1);
02071         Entry* sub = (Entry*) res;
02072 
02073         if (res==LB_ERR || !sub || sub->level<=dir->level)
02074             break;
02075 
02076         (void)ListBox_DeleteString(pane->hwnd, idx+1);
02077     }
02078 
02079     dir->expanded = FALSE;
02080 
02081     ShowWindow(pane->hwnd, SW_SHOW);
02082 }
02083 
02084 
02085 /* refresh the right pane of a Winefile child window */
02086 
02087 static void refresh_right_pane(ChildWnd* child)
02088 {
02089     (void)ListBox_ResetContent(child->right.hwnd);
02090     insert_entries(&child->right, child->right.root, child->filter_pattern, child->filter_flags, -1);
02091     calc_widths(&child->right, FALSE);
02092 
02093 #ifndef _NO_EXTENSIONS
02094     set_header(&child->right);
02095 #endif
02096 }
02097 
02098 
02099 /* change the current directory of a child window according to the given entry pointer */
02100 
02101 static void set_curdir(ChildWnd* child, Entry* entry, int idx, HWND hwnd)
02102 {
02103     TCHAR path[MAX_PATH];
02104 
02105     if (!entry)
02106         return;
02107 
02108     path[0] = '\0';
02109 
02110     child->left.cur = entry;
02111 
02112     child->right.root = entry->down? entry->down: entry;
02113     child->right.cur = entry;
02114 
02115     if (!entry->scanned)
02116         scan_entry(child, entry, idx, hwnd);
02117     else
02118         refresh_right_pane(child);
02119 
02120     get_path(entry, path);
02121     lstrcpy(child->path, path);
02122 
02123     if (child->hwnd)    /* only change window title, if the window already exists */
02124         SetWindowText(child->hwnd, path);
02125 
02126     if (path[0])
02127         if (SetCurrentDirectory(path))
02128             set_space_status();
02129 }
02130 
02131 
02132 /* refresh the child window content */
02133 
02134 static void refresh_child(ChildWnd* child)
02135 {
02136     TCHAR path[MAX_PATH], drv[_MAX_DRIVE+1];
02137     Entry* entry;
02138     int idx;
02139 
02140     get_path(child->left.cur, path);
02141     _tsplitpath(path, drv, NULL, NULL, NULL);
02142 
02143     child->right.root = NULL;
02144 
02145     scan_entry(child, &child->root.entry, 0, child->hwnd);
02146 
02147 #ifdef _SHELL_FOLDERS
02148     if (child->root.entry.etype == ET_SHELL)
02149         entry = read_tree(&child->root, NULL, get_path_pidl(path,child->hwnd), drv, child->sortOrder, child->hwnd);
02150     else
02151 #endif
02152         entry = read_tree(&child->root, path, NULL, drv, child->sortOrder, child->hwnd);
02153 
02154     if (!entry)
02155         entry = &child->root.entry;
02156 
02157     insert_entries(&child->left, child->root.entry.down, NULL, TF_ALL, 0);
02158 
02159     set_curdir(child, entry, 0, child->hwnd);
02160 
02161     idx = ListBox_FindItemData(child->left.hwnd, 0, child->left.cur);
02162     (void)ListBox_SetCurSel(child->left.hwnd, idx);
02163 }
02164 
02165 
02166 /* create the drive toolbar */
02167 
02168 static void create_drive_bar(void)
02169 {
02170     TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0};
02171 #ifndef _NO_EXTENSIONS
02172     TCHAR b1[BUFFER_LEN];
02173 #endif
02174     int btn = 1;
02175     PTSTR p;
02176 
02177     GetLogicalDriveStrings(BUFFER_LEN, Globals.drives);
02178 
02179     Globals.hdrivebar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE|CCS_NOMOVEY|TBSTYLE_LIST,
02180                 IDW_DRIVEBAR, 2, Globals.hInstance, IDB_DRIVEBAR, &drivebarBtn,
02181                 0, 16, 13, 16, 13, sizeof(TBBUTTON));
02182 
02183 #ifndef _NO_EXTENSIONS
02184 #ifdef __WINE__
02185     /* insert unix file system button */
02186     b1[0] = '/';
02187     b1[1] = '\0';
02188     b1[2] = '\0';
02189     SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
02190 
02191     drivebarBtn.idCommand = ID_DRIVE_UNIX_FS;
02192     SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
02193     drivebarBtn.iString++;
02194 #endif
02195 #ifdef _SHELL_FOLDERS
02196     /* insert shell namespace button */
02197     load_string(b1, IDS_SHELL);
02198     b1[lstrlen(b1)+1] = '\0';
02199     SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
02200 
02201     drivebarBtn.idCommand = ID_DRIVE_SHELL_NS;
02202     SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
02203     drivebarBtn.iString++;
02204 #endif
02205 
02206     /* register windows drive root strings */
02207     SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)Globals.drives);
02208 #endif
02209 
02210     drivebarBtn.idCommand = ID_DRIVE_FIRST;
02211 
02212     for(p=Globals.drives; *p; ) {
02213 #ifdef _NO_EXTENSIONS
02214         /* insert drive letter */
02215         TCHAR b[3] = {tolower(*p)};
02216         SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b);
02217 #endif
02218         switch(GetDriveType(p)) {
02219             case DRIVE_REMOVABLE:   drivebarBtn.iBitmap = 1;    break;
02220             case DRIVE_CDROM:       drivebarBtn.iBitmap = 3;    break;
02221             case DRIVE_REMOTE:      drivebarBtn.iBitmap = 4;    break;
02222             case DRIVE_RAMDISK:     drivebarBtn.iBitmap = 5;    break;
02223             default:/*DRIVE_FIXED*/ drivebarBtn.iBitmap = 2;
02224         }
02225 
02226         SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
02227         drivebarBtn.idCommand++;
02228         drivebarBtn.iString++;
02229 
02230         while(*p++);
02231     }
02232 }
02233 
02234 
02235 /* refresh the drive toolbar */
02236 
02237 static void refresh_drives(void)
02238 {
02239     RECT rect;
02240 
02241     /* destroy drive bar */
02242     DestroyWindow(Globals.hdrivebar);
02243     Globals.hdrivebar = 0;
02244 
02245     /* re-create drive bar */
02246     create_drive_bar();
02247 
02248     /* update window layout */
02249     GetClientRect(Globals.hMainWnd, &rect);
02250     SendMessage(Globals.hMainWnd, WM_SIZE, 0, MAKELONG(rect.right, rect.bottom));
02251 }
02252 
02253 
02254 /* launch a executable or document */
02255 
02256 static BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow)
02257 {
02258     HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, cmd, NULL/*parameters*/, NULL/*dir*/, nCmdShow);
02259 
02260     if (PtrToUlong(hinst) <= 32) {
02261         display_error(hwnd, GetLastError());
02262         return FALSE;
02263     }
02264 
02265     return TRUE;
02266 }
02267 
02268 
02269 /* launch the file associated with a Winefile entry */
02270 
02271 static BOOL launch_entry(Entry* entry, HWND hwnd, UINT nCmdShow)
02272 {
02273     TCHAR cmd[MAX_PATH];
02274 
02275 #ifdef _SHELL_FOLDERS
02276     if (entry->etype == ET_SHELL) {
02277         BOOL ret = TRUE;
02278 
02279         SHELLEXECUTEINFO shexinfo;
02280 
02281         shexinfo.cbSize = sizeof(SHELLEXECUTEINFO);
02282         shexinfo.fMask = SEE_MASK_IDLIST;
02283         shexinfo.hwnd = hwnd;
02284         shexinfo.lpVerb = NULL;
02285         shexinfo.lpFile = NULL;
02286         shexinfo.lpParameters = NULL;
02287         shexinfo.lpDirectory = NULL;
02288         shexinfo.nShow = nCmdShow;
02289         shexinfo.lpIDList = get_to_absolute_pidl(entry, hwnd);
02290 
02291         if (!ShellExecuteEx(&shexinfo)) {
02292             display_error(hwnd, GetLastError());
02293             ret = FALSE;
02294         }
02295 
02296         if (shexinfo.lpIDList != entry->pidl)
02297             IMalloc_Free(Globals.iMalloc, shexinfo.lpIDList);
02298 
02299         return ret;
02300     }
02301 #endif
02302 
02303     get_path(entry, cmd);
02304 
02305     /* start program, open document... */
02306     return launch_file(hwnd, cmd, nCmdShow);
02307 }
02308 
02309 
02310 /* activate a Winefile entry (on double click or ENTER) */
02311 
02312 static void activate_entry(ChildWnd* child, Pane* pane, HWND hwnd)
02313 {
02314     Entry* entry = pane->cur;
02315 
02316     if (!entry)
02317         return;
02318 
02319     if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
02320         int scanned_old = entry->scanned;
02321 
02322         if (!scanned_old)
02323             scan_entry(child, entry, ListBox_GetCurSel(child->left.hwnd), hwnd);
02324 
02325 #ifndef _NO_EXTENSIONS
02326         if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='\0')
02327             return;
02328 #endif
02329 
02330         if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='.' && entry->data.cFileName[2]=='\0') {
02331             entry = child->left.cur->up;
02332             collapse_entry(&child->left, entry);
02333             goto focus_entry;
02334         } else if (entry->expanded)
02335             collapse_entry(pane, child->left.cur);
02336         else {
02337             expand_entry(child, child->left.cur);
02338 
02339             if (!pane->treePane) focus_entry: {
02340                 int idx = ListBox_FindItemData(child->left.hwnd, ListBox_GetCurSel(child->left.hwnd), entry);
02341                 (void)ListBox_SetCurSel(child->left.hwnd, idx);
02342                 set_curdir(child, entry, idx, hwnd);
02343             }
02344         }
02345 
02346         if (!scanned_old) {
02347             calc_widths(pane, FALSE);
02348 
02349 #ifndef _NO_EXTENSIONS
02350             set_header(pane);
02351 #endif
02352         }
02353     } else {
02354         if (GetKeyState(VK_MENU) < 0)
02355             show_properties_dlg(entry, child->hwnd);
02356         else
02357             launch_entry(entry, child->hwnd, SW_SHOWNORMAL);
02358     }
02359 }
02360 
02361 
02362 /* command handler for Winefile panes */
02363 
02364 static BOOL pane_command(Pane* pane, UINT cmd)
02365 {
02366     switch(cmd) {
02367         case ID_VIEW_NAME:
02368             if (pane->visible_cols) {
02369                 pane->visible_cols = 0;
02370                 calc_widths(pane, TRUE);
02371 #ifndef _NO_EXTENSIONS
02372                 set_header(pane);
02373 #endif
02374                 InvalidateRect(pane->hwnd, 0, TRUE);
02375                 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND|MF_CHECKED);
02376                 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND);
02377                 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
02378             }
02379             break;
02380 
02381         case ID_VIEW_ALL_ATTRIBUTES:
02382             if (pane->visible_cols != COL_ALL) {
02383                 pane->visible_cols = COL_ALL;
02384                 calc_widths(pane, TRUE);
02385 #ifndef _NO_EXTENSIONS
02386                 set_header(pane);
02387 #endif
02388                 InvalidateRect(pane->hwnd, 0, TRUE);
02389                 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND);
02390                 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND|MF_CHECKED);
02391                 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
02392             }
02393             break;
02394 
02395 #ifndef _NO_EXTENSIONS
02396         case ID_PREFERRED_SIZES: {
02397             calc_widths(pane, TRUE);
02398             set_header(pane);
02399             InvalidateRect(pane->hwnd, 0, TRUE);
02400             break;}
02401 #endif
02402 
02403                 /* TODO: more command ids... */
02404 
02405         default:
02406             return FALSE;
02407     }
02408 
02409     return TRUE;
02410 }
02411 
02412 
02413 /* set the sort order of a child window */
02414 
02415 static void set_sort_order(ChildWnd* child, enum SORT_ORDER sortOrder)
02416 {
02417     if (child->sortOrder != sortOrder) {
02418         child->sortOrder = sortOrder;
02419         refresh_child(child);
02420     }
02421 }
02422 
02423 
02424 /* update the check state of the view menu items */
02425 
02426 static void update_view_menu(ChildWnd* child)
02427 {
02428     CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_NAME, child->sortOrder==SORT_NAME? MF_CHECKED: MF_UNCHECKED);
02429     CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_TYPE, child->sortOrder==SORT_EXT? MF_CHECKED: MF_UNCHECKED);
02430     CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_SIZE, child->sortOrder==SORT_SIZE? MF_CHECKED: MF_UNCHECKED);
02431     CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_DATE, child->sortOrder==SORT_DATE? MF_CHECKED: MF_UNCHECKED);
02432 }
02433 
02434 
02435 /* utility function to check for directories at the given path */
02436 
02437 static BOOL is_directory(LPCTSTR target)
02438 {
02439     /*TODO correctly handle UNIX paths */
02440     DWORD target_attr = GetFileAttributes(target);
02441 
02442     if (target_attr == INVALID_FILE_ATTRIBUTES)
02443         return FALSE;
02444 
02445     return target_attr&FILE_ATTRIBUTE_DIRECTORY? TRUE: FALSE;
02446 }
02447 
02448 
02449 /* display a dialog to ask the user for a target path */
02450 
02451 static BOOL prompt_target(Pane* pane, LPTSTR source, LPTSTR target)
02452 {
02453     TCHAR path[MAX_PATH];
02454     int len;
02455 
02456     get_path(pane->cur, path);
02457 
02458     if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_SELECT_DESTINATION), pane->hwnd, DestinationDlgProc, (LPARAM)path) != IDOK)
02459         return FALSE;
02460 
02461     get_path(pane->cur, source);
02462 
02463     /* convert relative targets to absolute paths */
02464     if (path[0]!='/' && path[1]!=':') {
02465         get_path(pane->cur->up, target);
02466         len = lstrlen(target);
02467 
02468         if (target[len-1]!='\\' && target[len-1]!='/')
02469             target[len++] = '/';
02470 
02471         lstrcpy(target+len, path);
02472     } else
02473         lstrcpy(target, path);
02474 
02475     /* If the target already exists as directory, create a new target below this. */
02476     if (is_directory(path)) {
02477         TCHAR fname[_MAX_FNAME], ext[_MAX_EXT];
02478         static const TCHAR sAppend[] = {'%','s','/','%','s','%','s','\0'};
02479 
02480         _tsplitpath(source, NULL, NULL, fname, ext);
02481 
02482         wsprintf(target, sAppend, path, fname, ext);
02483     }
02484 
02485     return TRUE;
02486 }
02487 
02488 
02489 /* message handler funtion for the Winefile child windows */
02490 
02491 static LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
02492 {
02493     ChildWnd* child = (ChildWnd*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
02494     ASSERT(child);
02495 
02496     switch(nmsg) {
02497         case WM_DRAWITEM: {
02498             LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lparam;
02499             Entry* entry = (Entry*) dis->itemData;
02500 
02501             if (dis->CtlID == IDW_TREE_LEFT)
02502                 draw_item(&child->left, dis, entry, -1);
02503             else if (dis->CtlID == IDW_TREE_RIGHT)
02504                 draw_item(&child->right, dis, entry, -1);
02505             else
02506                 goto draw_menu_item;
02507 
02508             return TRUE;}
02509 
02510         case WM_CREATE:
02511             InitChildWindow(child);
02512             break;
02513 
02514         case WM_NCDESTROY:
02515             free_child_window(child);
02516             SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
02517             break;
02518 
02519         case WM_PAINT: {
02520             PAINTSTRUCT ps;
02521             HBRUSH lastBrush;
02522             RECT rt;
02523             GetClientRect(hwnd, &rt);
02524             BeginPaint(hwnd, &ps);
02525             rt.left = child->split_pos-SPLIT_WIDTH/2;
02526             rt.right = child->split_pos+SPLIT_WIDTH/2+1;
02527             lastBrush = SelectBrush(ps.hdc, (HBRUSH)GetStockObject(COLOR_SPLITBAR));
02528             Rectangle(ps.hdc, rt.left, rt.top-1, rt.right, rt.bottom+1);
02529             SelectObject(ps.hdc, lastBrush);
02530 #ifdef _NO_EXTENSIONS
02531             rt.top = rt.bottom - GetSystemMetrics(SM_CYHSCROLL);
02532             FillRect(ps.hdc, &rt, GetStockObject(BLACK_BRUSH));
02533 #endif
02534             EndPaint(hwnd, &ps);
02535             break;}
02536 
02537         case WM_SETCURSOR:
02538             if (LOWORD(lparam) == HTCLIENT) {
02539                 POINT pt;
02540                 GetCursorPos(&pt);
02541                 ScreenToClient(hwnd, &pt);
02542 
02543                 if (pt.x>=child->split_pos-SPLIT_WIDTH/2 && pt.x<child->split_pos+SPLIT_WIDTH/2+1) {
02544                     SetCursor(LoadCursor(0, IDC_SIZEWE));
02545                     return TRUE;
02546                 }
02547             }
02548             goto def;
02549 
02550         case WM_LBUTTONDOWN: {
02551             RECT rt;
02552             int x = GET_X_LPARAM(lparam);
02553 
02554             GetClientRect(hwnd, &rt);
02555 
02556             if (x>=child->split_pos-SPLIT_WIDTH/2 && x<child->split_pos+SPLIT_WIDTH/2+1) {
02557                 last_split = child->split_pos;
02558 #ifdef _NO_EXTENSIONS
02559                 draw_splitbar(hwnd, last_split);
02560 #endif
02561                 SetCapture(hwnd);
02562             }
02563 
02564             break;}
02565 
02566         case WM_LBUTTONUP:
02567             if (GetCapture() == hwnd) {
02568 #ifdef _NO_EXTENSIONS
02569                 RECT rt;
02570                 int x = LOWORD(lparam);
02571                 draw_splitbar(hwnd, last_split);
02572                 last_split = -1;
02573                 GetClientRect(hwnd, &rt);
02574                 child->split_pos = x;
02575                 resize_tree(child, rt.right, rt.bottom);
02576 #endif
02577                 ReleaseCapture();
02578             }
02579             break;
02580 
02581 #ifdef _NO_EXTENSIONS
02582         case WM_CAPTURECHANGED:
02583             if (GetCapture()==hwnd && last_split>=0)
02584                 draw_splitbar(hwnd, last_split);
02585             break;
02586 #endif
02587 
02588         case WM_KEYDOWN:
02589             if (wparam == VK_ESCAPE)
02590                 if (GetCapture() == hwnd) {
02591                     RECT rt;
02592 #ifdef _NO_EXTENSIONS
02593                     draw_splitbar(hwnd, last_split);
02594 #else
02595                     child->split_pos = last_split;
02596 #endif
02597                     GetClientRect(hwnd, &rt);
02598                     resize_tree(child, rt.right, rt.bottom);
02599                     last_split = -1;
02600                     ReleaseCapture();
02601                     SetCursor(LoadCursor(0, IDC_ARROW));
02602                 }
02603             break;
02604 
02605         case WM_MOUSEMOVE:
02606             if (GetCapture() == hwnd) {
02607                 RECT rt;
02608                 int x = LOWORD(lparam);
02609 
02610 #ifdef _NO_EXTENSIONS
02611                 HDC hdc = GetDC(hwnd);
02612                 GetClientRect(hwnd, &rt);
02613 
02614                 rt.left = last_split-SPLIT_WIDTH/2;
02615                 rt.right = last_split+SPLIT_WIDTH/2+1;
02616                 InvertRect(hdc, &rt);
02617 
02618                 last_split = x;
02619                 rt.left = x-SPLIT_WIDTH/2;
02620                 rt.right = x+SPLIT_WIDTH/2+1;
02621                 InvertRect(hdc, &rt);
02622 
02623                 ReleaseDC(hwnd, hdc);
02624 #else
02625                 GetClientRect(hwnd, &rt);
02626 
02627                 if (x>=0 && x<rt.right) {
02628                     child->split_pos = x;
02629                     resize_tree(child, rt.right, rt.bottom);
02630                     rt.left = x-SPLIT_WIDTH/2;
02631                     rt.right = x+SPLIT_WIDTH/2+1;
02632                     InvalidateRect(hwnd, &rt, FALSE);
02633                     UpdateWindow(child->left.hwnd);
02634                     UpdateWindow(hwnd);
02635                     UpdateWindow(child->right.hwnd);
02636                 }
02637 #endif
02638             }
02639             break;
02640 
02641 #ifndef _NO_EXTENSIONS
02642         case WM_GETMINMAXINFO:
02643             DefMDIChildProc(hwnd, nmsg, wparam, lparam);
02644 
02645             {LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
02646 
02647             lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
02648             lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
02649             break;}
02650 #endif /* _NO_EXTENSIONS */
02651 
02652         case WM_SETFOCUS:
02653             if (SetCurrentDirectory(child->path))
02654                 set_space_status();
02655             SetFocus(child->focus_pane? child->right.hwnd: child->left.hwnd);
02656             break;
02657 
02658         case WM_DISPATCH_COMMAND: {
02659             Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
02660 
02661             switch(LOWORD(wparam)) {
02662                 case ID_WINDOW_NEW: {
02663                     ChildWnd* new_child = alloc_child_window(child->path, NULL, hwnd);
02664 
02665                     if (!create_child_window(new_child))
02666                         heap_free(new_child);
02667 
02668                     break;}
02669 
02670                 case ID_REFRESH:
02671                     refresh_drives();
02672                     refresh_child(child);
02673                     break;
02674 
02675                 case ID_ACTIVATE:
02676                     activate_entry(child, pane, hwnd);
02677                     break;
02678 
02679                 case ID_FILE_MOVE: {
02680                     TCHAR source[BUFFER_LEN], target[BUFFER_LEN];
02681 
02682                     if (prompt_target(pane, source, target)) {
02683                         SHFILEOPSTRUCT shfo = {hwnd, FO_MOVE, source, target};
02684 
02685                         source[lstrlen(source)+1] = '\0';
02686                         target[lstrlen(target)+1] = '\0';
02687 
02688                         if (!SHFileOperation(&shfo))
02689                             refresh_child(child);
02690                     }
02691                     break;}
02692 
02693                 case ID_FILE_COPY: {
02694                     TCHAR source[BUFFER_LEN], target[BUFFER_LEN];
02695 
02696                     if (prompt_target(pane, source, target)) {
02697                         SHFILEOPSTRUCT shfo = {hwnd, FO_COPY, source, target};
02698 
02699                         source[lstrlen(source)+1] = '\0';
02700                         target[lstrlen(target)+1] = '\0';
02701 
02702                         if (!SHFileOperation(&shfo))
02703                             refresh_child(child);
02704                     }
02705                     break;}
02706 
02707                 case ID_FILE_DELETE: {
02708                     TCHAR path[BUFFER_LEN];
02709                     SHFILEOPSTRUCT shfo = {hwnd, FO_DELETE, path, NULL, FOF_ALLOWUNDO};
02710 
02711                     get_path(pane->cur, path);
02712 
02713                     path[lstrlen(path)+1] = '\0';
02714 
02715                     if (!SHFileOperation(&shfo))
02716                         refresh_child(child);
02717                     break;}
02718 
02719                 case ID_VIEW_SORT_NAME:
02720                     set_sort_order(child, SORT_NAME);
02721                     break;
02722 
02723                 case ID_VIEW_SORT_TYPE:
02724                     set_sort_order(child, SORT_EXT);
02725                     break;
02726 
02727                 case ID_VIEW_SORT_SIZE:
02728                     set_sort_order(child, SORT_SIZE);
02729                     break;
02730 
02731                 case ID_VIEW_SORT_DATE:
02732                     set_sort_order(child, SORT_DATE);
02733                     break;
02734 
02735                 case ID_VIEW_FILTER: {
02736                     struct FilterDialog dlg;
02737 
02738                     memset(&dlg, 0, sizeof(struct FilterDialog));
02739                     lstrcpy(dlg.pattern, child->filter_pattern);
02740                     dlg.flags = child->filter_flags;
02741 
02742                     if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_DIALOG_VIEW_TYPE), hwnd, FilterDialogDlgProc, (LPARAM)&dlg) == IDOK) {
02743                         lstrcpy(child->filter_pattern, dlg.pattern);
02744                         child->filter_flags = dlg.flags;
02745                         refresh_right_pane(child);
02746                     }
02747                     break;}
02748 
02749                 case ID_VIEW_SPLIT: {
02750                     last_split = child->split_pos;
02751 #ifdef _NO_EXTENSIONS
02752                     draw_splitbar(hwnd, last_split);
02753 #endif
02754                     SetCapture(hwnd);
02755                     break;}
02756 
02757                 case ID_EDIT_PROPERTIES:
02758                     show_properties_dlg(pane->cur, child->hwnd);
02759                     break;
02760 
02761                 default:
02762                     return pane_command(pane, LOWORD(wparam));
02763             }
02764 
02765             return TRUE;}
02766 
02767         case WM_COMMAND: {
02768             Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
02769 
02770             switch(HIWORD(wparam)) {
02771                 case LBN_SELCHANGE: {
02772                     int idx = ListBox_GetCurSel(pane->hwnd);
02773                     Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, idx);
02774 
02775                     if (pane == &child->left)
02776                         set_curdir(child, entry, idx, hwnd);
02777                     else
02778                         pane->cur = entry;
02779                     break;}
02780 
02781                 case LBN_DBLCLK:
02782                     activate_entry(child, pane, hwnd);
02783                     break;
02784             }
02785             break;}
02786 
02787 #ifndef _NO_EXTENSIONS
02788         case WM_NOTIFY: {
02789             NMHDR* pnmh = (NMHDR*) lparam;
02790             return pane_notify(pnmh->idFrom==IDW_HEADER_LEFT? &child->left: &child->right, pnmh);}
02791 #endif
02792 
02793 #ifdef _SHELL_FOLDERS
02794         case WM_CONTEXTMENU: {
02795             POINT pt, pt_clnt;
02796             Pane* pane;
02797             int idx;
02798 
02799             /* first select the current item in the listbox */
02800             HWND hpanel = (HWND) wparam;
02801             pt_clnt.x = pt.x = (short)LOWORD(lparam);
02802             pt_clnt.y = pt.y = (short)HIWORD(lparam);
02803             ScreenToClient(hpanel, &pt_clnt);
02804             SendMessage(hpanel, WM_LBUTTONDOWN, 0, MAKELONG(pt_clnt.x, pt_clnt.y));
02805             SendMessage(hpanel, WM_LBUTTONUP, 0, MAKELONG(pt_clnt.x, pt_clnt.y));
02806 
02807             /* now create the popup menu using shell namespace and IContextMenu */
02808             pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
02809             idx = ListBox_GetCurSel(pane->hwnd);
02810 
02811             if (idx != -1) {
02812                 Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, idx);
02813 
02814                 LPITEMIDLIST pidl_abs = get_to_absolute_pidl(entry, hwnd);
02815 
02816                 if (pidl_abs) {
02817                     IShellFolder* parentFolder;
02818                     LPCITEMIDLIST pidlLast;
02819 
02820                     /* get and use the parent folder to display correct context menu in all cases */
02821                     if (SUCCEEDED(SHBindToParent(pidl_abs, &IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast))) {
02822                         if (ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, pt.x, pt.y) == S_OK)
02823                             refresh_child(child);
02824 
02825                         IShellFolder_Release(parentFolder);
02826                     }
02827 
02828                     IMalloc_Free(Globals.iMalloc, pidl_abs);
02829                 }
02830             }
02831             break;}
02832 #endif
02833 
02834           case WM_MEASUREITEM:
02835           draw_menu_item:
02836             if (!wparam)    /* Is the message menu-related? */
02837                 if (CtxMenu_HandleMenuMsg(nmsg, wparam, lparam))
02838                     return TRUE;
02839 
02840             break;
02841 
02842           case WM_INITMENUPOPUP:
02843             if (CtxMenu_HandleMenuMsg(nmsg, wparam, lparam))
02844                 return 0;
02845 
02846             update_view_menu(child);
02847             break;
02848 
02849           case WM_MENUCHAR: /* only supported by IContextMenu3 */
02850            if (s_pctxmenu3) {
02851                LRESULT lResult = 0;
02852 
02853                (*s_pctxmenu3->lpVtbl->HandleMenuMsg2)(s_pctxmenu3, nmsg, wparam, lparam, &lResult);
02854 
02855                return lResult;
02856            }
02857 
02858            break;
02859 
02860         case WM_SIZE:
02861             if (wparam != SIZE_MINIMIZED)
02862                 resize_tree(child, LOWORD(lparam), HIWORD(lparam));
02863             /* fall through */
02864 
02865         default: def:
02866             return DefMDIChildProc(hwnd, nmsg, wparam, lparam);
02867     }
02868 
02869     return 0;
02870 }
02871 
02872 
02873 /* program initialisation */
02874 
02875 static void InitInstance(HINSTANCE hinstance)
02876 {
02877     static const TCHAR sFont[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
02878 
02879     WNDCLASSEX wcFrame;
02880     WNDCLASS wcChild;
02881     ATOM hChildClass;
02882     int col;
02883 
02884     INITCOMMONCONTROLSEX icc = {
02885         sizeof(INITCOMMONCONTROLSEX),
02886         ICC_BAR_CLASSES
02887     };
02888 
02889     HDC hdc = GetDC(0);
02890 
02891     setlocale(LC_COLLATE, "");  /* set collating rules to local settings for compareName */
02892 
02893     InitCommonControlsEx(&icc);
02894 
02895 
02896     /* register frame window class */
02897 
02898     wcFrame.cbSize        = sizeof(WNDCLASSEX);
02899     wcFrame.style         = 0;
02900     wcFrame.lpfnWndProc   = FrameWndProc;
02901     wcFrame.cbClsExtra    = 0;
02902     wcFrame.cbWndExtra    = 0;
02903     wcFrame.hInstance     = hinstance;
02904     wcFrame.hIcon         = LoadIcon(hinstance, MAKEINTRESOURCE(IDI_WINEFILE));
02905     wcFrame.hCursor       = LoadCursor(0, IDC_ARROW);
02906     wcFrame.hbrBackground = 0;
02907     wcFrame.lpszMenuName  = 0;
02908     wcFrame.lpszClassName = sWINEFILEFRAME;
02909     wcFrame.hIconSm       = (HICON)LoadImage(hinstance,
02910                                              MAKEINTRESOURCE(IDI_WINEFILE),
02911                                              IMAGE_ICON,
02912                                              GetSystemMetrics(SM_CXSMICON),
02913                                              GetSystemMetrics(SM_CYSMICON),
02914                                              LR_SHARED);
02915 
02916     Globals.hframeClass = RegisterClassEx(&wcFrame);
02917 
02918 
02919     /* register tree windows class */
02920 
02921     wcChild.style         = CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW;
02922     wcChild.lpfnWndProc   = ChildWndProc;
02923     wcChild.cbClsExtra    = 0;
02924     wcChild.cbWndExtra    = 0;
02925     wcChild.hInstance     = hinstance;
02926     wcChild.hIcon         = 0;
02927     wcChild.hCursor       = LoadCursor(0, IDC_ARROW);
02928     wcChild.hbrBackground = 0;
02929     wcChild.lpszMenuName  = 0;
02930     wcChild.lpszClassName = sWINEFILETREE;
02931 
02932     hChildClass = RegisterClass(&wcChild);
02933 
02934 
02935     Globals.haccel = LoadAccelerators(hinstance, MAKEINTRESOURCE(IDA_WINEFILE));
02936 
02937     Globals.hfont = CreateFont(-MulDiv(8,GetDeviceCaps(hdc,LOGPIXELSY),72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sFont);
02938 
02939     ReleaseDC(0, hdc);
02940 
02941     Globals.hInstance = hinstance;
02942 
02943 #ifdef _SHELL_FOLDERS
02944     CoInitialize(NULL);
02945     CoGetMalloc(MEMCTX_TASK, &Globals.iMalloc);
02946     SHGetDesktopFolder(&Globals.iDesktop);
02947 #ifdef __WINE__
02948     Globals.cfStrFName = RegisterClipboardFormatA(CFSTR_FILENAME);
02949 #else
02950     Globals.cfStrFName = RegisterClipboardFormat(CFSTR_FILENAME);
02951 #endif
02952 #endif
02953 
02954     /* load column strings */
02955     col = 1;
02956 
02957     load_string(g_pos_names[col++], IDS_COL_NAME);
02958     load_string(g_pos_names[col++], IDS_COL_SIZE);
02959     load_string(g_pos_names[col++], IDS_COL_CDATE);
02960 #ifndef _NO_EXTENSIONS
02961     load_string(g_pos_names[col++], IDS_COL_ADATE);
02962     load_string(g_pos_names[col++], IDS_COL_MDATE);
02963     load_string(g_pos_names[col++], IDS_COL_IDX);
02964     load_string(g_pos_names[col++], IDS_COL_LINKS);
02965 #endif
02966     load_string(g_pos_names[col++], IDS_COL_ATTR);
02967 #ifndef _NO_EXTENSIONS
02968     load_string(g_pos_names[col++], IDS_COL_SEC);
02969 #endif
02970 }
02971 
02972 
02973 /* display main frame window */
02974 
02975 static void show_frame(HWND hwndParent, int cmdshow, LPCTSTR path)
02976 {
02977     static const TCHAR sMDICLIENT[] = {'M','D','I','C','L','I','E','N','T','\0'};
02978 
02979     TCHAR buffer[MAX_PATH], b1[BUFFER_LEN];
02980     HMENU hMenuFrame, hMenuWindow;
02981     ChildWnd* child;
02982     struct WINDOW_OPTIONS opts;
02983 
02984     CLIENTCREATESTRUCT ccs;
02985 
02986     if (Globals.hMainWnd)
02987         return;
02988 
02989     load_registry_settings(&opts);
02990     hMenuFrame = LoadMenu(Globals.hInstance, MAKEINTRESOURCE(IDM_WINEFILE));
02991     hMenuWindow = GetSubMenu(hMenuFrame, GetMenuItemCount(hMenuFrame)-2);
02992 
02993     Globals.hMenuFrame = hMenuFrame;
02994     Globals.hMenuView = GetSubMenu(hMenuFrame, 3);
02995     Globals.hMenuOptions = GetSubMenu(hMenuFrame, 4);
02996 
02997     ccs.hWindowMenu  = hMenuWindow;
02998     ccs.idFirstChild = IDW_FIRST_CHILD;
02999 
03000 
03001     /* create main window */
03002     Globals.hMainWnd = CreateWindowEx(0, MAKEINTRESOURCE(Globals.hframeClass), RS(b1,IDS_WINE_FILE), WS_OVERLAPPEDWINDOW,
03003                     opts.start_x, opts.start_y, opts.width, opts.height,
03004                     hwndParent, Globals.hMenuFrame, Globals.hInstance, 0/*lpParam*/);
03005 
03006 
03007     Globals.hmdiclient = CreateWindowEx(0, sMDICLIENT, NULL,
03008                     WS_CHILD|WS_CLIPCHILDREN|WS_VSCROLL|WS_HSCROLL|WS_VISIBLE|WS_BORDER,
03009                     0, 0, 0, 0,
03010                     Globals.hMainWnd, 0, Globals.hInstance, &ccs);
03011 
03012 
03013     CheckMenuItem(Globals.hMenuOptions, ID_VIEW_DRIVE_BAR, MF_BYCOMMAND|MF_CHECKED);
03014     CheckMenuItem(Globals.hMenuOptions, ID_VIEW_SAVESETTINGS, MF_BYCOMMAND);
03015 
03016     create_drive_bar();
03017 
03018     {
03019         TBBUTTON toolbarBtns[] = {
03020             {0, 0, 0, BTNS_SEP, {0, 0}, 0, 0},
03021             {0, ID_WINDOW_NEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
03022             {1, ID_WINDOW_CASCADE, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
03023             {2, ID_WINDOW_TILE_HORZ, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
03024             {3, ID_WINDOW_TILE_VERT, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
03025 /*TODO
03026             {4, ID_... , TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
03027             {5, ID_... , TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
03028 */      };
03029 
03030         Globals.htoolbar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE,
03031             IDW_TOOLBAR, 2, Globals.hInstance, IDB_TOOLBAR, toolbarBtns,
03032             sizeof(toolbarBtns)/sizeof(TBBUTTON), 16, 15, 16, 15, sizeof(TBBUTTON));
03033         CheckMenuItem(Globals.hMenuOptions, ID_VIEW_TOOL_BAR, MF_BYCOMMAND|MF_CHECKED);
03034     }
03035 
03036     Globals.hstatusbar = CreateStatusWindow(WS_CHILD|WS_VISIBLE, 0, Globals.hMainWnd, IDW_STATUSBAR);
03037     CheckMenuItem(Globals.hMenuOptions, ID_VIEW_STATUSBAR, MF_BYCOMMAND|MF_CHECKED);
03038 
03039 /* CreateStatusWindow does not accept WS_BORDER
03040     Globals.hstatusbar = CreateWindowEx(WS_EX_NOPARENTNOTIFY, STATUSCLASSNAME, 0,
03041                     WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_BORDER|CCS_NODIVIDER, 0,0,0,0,
03042                     Globals.hMainWnd, (HMENU)IDW_STATUSBAR, hinstance, 0);*/
03043 
03044     /*TODO: read paths from registry */
03045 
03046     if (!path || !*path) {
03047         GetCurrentDirectory(MAX_PATH, buffer);
03048         path = buffer;
03049     }
03050 
03051     ShowWindow(Globals.hMainWnd, cmdshow);
03052 
03053 #if defined(_SHELL_FOLDERS) && 0 /* Display drive view as default. */
03054     /* display Shell Namespace */
03055     child = alloc_child_window(path, get_path_pidl(path,Globals.hMainWnd), Globals.hMainWnd);
03056 #else
03057     child = alloc_child_window(path, NULL, Globals.hMainWnd);
03058 #endif
03059 
03060     child->pos.showCmd = SW_SHOWMAXIMIZED;
03061     child->pos.rcNormalPosition.left = 0;
03062     child->pos.rcNormalPosition.top = 0;
03063     child->pos.rcNormalPosition.right = 320;
03064     child->pos.rcNormalPosition.bottom = 280;
03065 
03066     if (!create_child_window(child))
03067         heap_free(child);
03068 
03069     SetWindowPlacement(child->hwnd, &child->pos);
03070 
03071     Globals.himl = ImageList_LoadBitmap(Globals.hInstance, MAKEINTRESOURCE(IDB_IMAGES), 16, 0, RGB(0,255,0));
03072 
03073     Globals.prescan_node = FALSE;
03074 
03075     UpdateWindow(Globals.hMainWnd);
03076 
03077     if (path && path[0])
03078     {
03079         int index,count;
03080         TCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
03081         TCHAR fullname[_MAX_FNAME+_MAX_EXT+1];
03082 
03083         memset(name,0,sizeof(name));
03084         memset(name,0,sizeof(ext));
03085         _tsplitpath(path, drv, dir, name, ext);
03086         if (name[0])
03087         {
03088             count = ListBox_GetCount(child->right.hwnd);
03089             lstrcpy(fullname,name);
03090             lstrcat(fullname,ext);
03091 
03092             for (index = 0; index < count; index ++)
03093             {
03094                 Entry* entry = (Entry*) ListBox_GetItemData(child->right.hwnd, index);
03095                 if (lstrcmp(entry->data.cFileName,fullname)==0 ||
03096                         lstrcmp(entry->data.cAlternateFileName,fullname)==0)
03097                 {
03098                     (void)ListBox_SetCurSel(child->right.hwnd, index);
03099                     SetFocus(child->right.hwnd);
03100                     break;
03101                 }
03102             }
03103         }
03104     }
03105 }
03106 
03107 
03108 /* release memory on program termination */
03109 
03110 static void ExitInstance(void)
03111 {
03112 #ifdef _SHELL_FOLDERS
03113     IShellFolder_Release(Globals.iDesktop);
03114     IMalloc_Release(Globals.iMalloc);
03115     CoUninitialize();
03116 #endif
03117 
03118     DeleteObject(Globals.hfont);
03119     ImageList_Destroy(Globals.himl);
03120 }
03121 
03122 
03123 #ifdef _NO_EXTENSIONS
03124 
03125 /* search for already running win[e]file instances */
03126 
03127 static int g_foundPrevInstance = 0;
03128 
03129 /* callback fucntion to enumerate Win[e]file frame windows */
03130 static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lparam)
03131 {
03132     TCHAR cls[128];
03133 
03134     GetClassName(hwnd, cls, 128);
03135 
03136     if (!lstrcmp(cls, (LPCTSTR)lparam)) {
03137         g_foundPrevInstance++;
03138         return FALSE;
03139     }
03140 
03141     return TRUE;
03142 }
03143 
03144 /* search for window of given class name to allow only one running instance */
03145 static int find_window_class(LPCTSTR classname)
03146 {
03147     EnumWindows(EnumWndProc, (LPARAM)classname);
03148 
03149     if (g_foundPrevInstance)
03150         return 1;
03151 
03152     return 0;
03153 }
03154 
03155 #endif
03156 
03157 
03158 /* main function */
03159 
03160 static int winefile_main(HINSTANCE hinstance, int cmdshow, LPCTSTR path)
03161 {
03162     MSG msg;
03163 
03164     InitInstance(hinstance);
03165 
03166     show_frame(0, cmdshow, path);
03167 
03168     while(GetMessage(&msg, 0, 0, 0)) {
03169         if (Globals.hmdiclient && TranslateMDISysAccel(Globals.hmdiclient, &msg))
03170             continue;
03171 
03172         if (Globals.hMainWnd && TranslateAccelerator(Globals.hMainWnd, Globals.haccel, &msg))
03173             continue;
03174 
03175         TranslateMessage(&msg);
03176         DispatchMessage(&msg);
03177     }
03178 
03179     ExitInstance();
03180 
03181     return msg.wParam;
03182 }
03183 
03184 
03185 /* program entry function */
03186 
03187 #if defined(UNICODE) && defined(_MSC_VER)
03188 int APIENTRY wWinMain(HINSTANCE hinstance, HINSTANCE previnstance, LPWSTR cmdline, int cmdshow)
03189 #else
03190 int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow)
03191 #endif
03192 {
03193 #ifdef _NO_EXTENSIONS
03194     if (find_window_class(sWINEFILEFRAME))
03195         return 1;
03196 #endif
03197 
03198 #if defined(UNICODE) && !defined(_MSC_VER)
03199     { /* convert ANSI cmdline into WCS path string */
03200     TCHAR buffer[MAX_PATH];
03201     MultiByteToWideChar(CP_ACP, 0, cmdline, -1, buffer, MAX_PATH);
03202     winefile_main(hinstance, cmdshow, buffer);
03203     }
03204 #else
03205     winefile_main(hinstance, cmdshow, cmdline);
03206 #endif
03207 
03208     return 0;
03209 }

Winefile Source Code Documentation
generated on 15.09.2008 by doxygen

Winefile Homepage