FLTK logo

[master] 0da41da - Allow unix style paths for windows native filechooser

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] 0da41da - Allow unix style paths for windows native filechooser "Greg Ercolano" Aug 08, 2020  
 
commit 0da41da713ff5674207334a7c205c958364c18aa
Author:     Greg Ercolano <erco@seriss.com>
AuthorDate: Sat Aug 8 19:10:57 2020 -0700
Commit:     Greg Ercolano <erco@seriss.com>
CommitDate: Sat Aug 8 19:10:57 2020 -0700

    Allow unix style paths for windows native filechooser
    
    Allows and preserves unix style paths if user specifies them,
    otherwise uses Windows style. This allows end users to use either
    style path and get behavior they expect in cross-platform environments.
    
    Addresses problems raised by issue #122

 src/Fl_Native_File_Chooser_WIN32.cxx | 94 ++++++++++++++++++++++++++----------
 test/native-filechooser.cxx          | 18 +++++--
 2 files changed, 82 insertions(+), 30 deletions(-)

diff --git src/Fl_Native_File_Chooser_WIN32.cxx src/Fl_Native_File_Chooser_WIN32.cxx
index 580e6e2..4b982a6 100644
--- src/Fl_Native_File_Chooser_WIN32.cxx
+++ src/Fl_Native_File_Chooser_WIN32.cxx
@@ -29,6 +29,7 @@
 
 #define FNFC_MAX_PATH 32768     // XXX: MAX_PATH under win32 is 260, too small for modern use
 
+#include <FL/fl_string.h>       // fl_strdup()
 #include <FL/Fl_Native_File_Chooser.H>
 #  include <windows.h>
 #  include <commdlg.h>          // OPENFILENAMEW, GetOpenFileName()
@@ -65,6 +66,7 @@ private:
   void ClearBINF();
   void Win2Unix(char *s);
   void Unix2Win(char *s);
+  bool IsUnixPath(const char *s);
   int showfile();
   int showdir();
 
@@ -338,14 +340,24 @@ void Fl_WinAPI_Native_File_Chooser_Driver::ClearBINF() {
 
 // CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES
 void Fl_WinAPI_Native_File_Chooser_Driver::Win2Unix(char *s) {
-  for ( ; *s; s++ )
-    if ( *s == '\\' ) *s = '/';
+  while ( s=strchr(s,'\\') ) *s = '/';
 }
 
 // CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES
 void Fl_WinAPI_Native_File_Chooser_Driver::Unix2Win(char *s) {
-  for ( ; *s; s++ )
-    if ( *s == '/' ) *s = '\\';
+  while ( s=strchr(s,'/') ) *s = '\\';
+}
+
+// SEE IF PATH IS FRONT SLASH OR BACKSLASH STYLE
+//    Use this to preserve path style after windows dialog appears.
+//    If no slashes are specified, windows is assumed.
+//    If a mix of both path styles is used, windows is assumed.
+//
+bool Fl_WinAPI_Native_File_Chooser_Driver::IsUnixPath(const char *s) {
+  if ( !s ) return false;               // NULL?
+  if ( strchr(s, '\\') ) return false;  // windows style?
+  if ( strchr(s, '/')  ) return true;   // unix style?
+  return false;                         // no slashes? assume native windows
 }
 
 // SAVE THE CURRENT WORKING DIRECTORY
@@ -375,6 +387,7 @@ static void RestoreCWD(char *thecwd) {
 
 // SHOW FILE BROWSER
 int Fl_WinAPI_Native_File_Chooser_Driver::showfile() {
+  bool unixpath = IsUnixPath(_directory) | IsUnixPath(_preset_file);    // caller uses unix paths?
   ClearOFN();
   clear_pathnames();
   size_t fsize = FNFC_MAX_PATH;
@@ -403,7 +416,7 @@ int Fl_WinAPI_Native_File_Chooser_Driver::showfile() {
   }
   // SPACE FOR RETURNED FILENAME
   _ofn_ptr->lpstrFile    = new WCHAR[fsize];
-  _ofn_ptr->nMaxFile     = (DWORD) fsize-1;
+  _ofn_ptr->nMaxFile     = (DWORD)(fsize-1);
   _ofn_ptr->lpstrFile[0] = 0;
   _ofn_ptr->lpstrFile[1] = 0;           // dnull
   // PARENT WINDOW
@@ -434,27 +447,40 @@ int Fl_WinAPI_Native_File_Chooser_Driver::showfile() {
   //     XXX: this doesn't preselect the item in the listview.. why?
   //
   if ( _preset_file ) {
-    size_t len = strlen(_preset_file);
+    // Temp copy of _dirname we can convert to windows path if needed
+    char *winpath = fl_strdup(_preset_file);
+    if ( unixpath ) Unix2Win(winpath);
+    size_t len = strlen(winpath);
     if ( len >= _ofn_ptr->nMaxFile ) {
       char msg[80];
       sprintf(msg, "preset_file() filename is too long: %ld is >=%ld", (long)len, (long)fsize);
       errmsg(msg);
       return(-1);
     }
-    wcscpy(_ofn_ptr->lpstrFile, utf8towchar(_preset_file));
-    // Unix2Win(_ofn_ptr->lpstrFile);
+    wcscpy(_ofn_ptr->lpstrFile, utf8towchar(winpath));
     len = wcslen(_ofn_ptr->lpstrFile);
     _ofn_ptr->lpstrFile[len+0] = 0;     // multiselect needs dnull
     _ofn_ptr->lpstrFile[len+1] = 0;
+    free(winpath);  // free temp copy now that we have a new wchar
+    //wprintf(L"lpstrFile is '%ls'\n", (WCHAR*)(_ofn_ptr->lpstrFile));
   }
+  // PRESET DIR
+  //     XXX: See KB Q86920 for doc bug:
+  //     http://support.microsoft.com/default.aspx?scid=kb;en-us;86920
+  //
   if ( _directory ) {
-    // PRESET DIR
-    //     XXX: See KB Q86920 for doc bug:
-    //     http://support.microsoft.com/default.aspx?scid=kb;en-us;86920
+    // Temp copy of _dirname we can convert to windows path if needed
+    char *winpath = fl_strdup(_directory);
+    // Caller specified unix front slash path?
+    //     If so, convert to backslashes; windows native browser mishandles unix style paths.
+    //     We'll convert back to unix style when dialog completes.
     //
-    _ofn_ptr->lpstrInitialDir    = new WCHAR[FNFC_MAX_PATH];
-    wcscpy((WCHAR *)_ofn_ptr->lpstrInitialDir, utf8towchar(_directory));
-    // Unix2Win((char*)_ofn_ptr->lpstrInitialDir);
+    if ( unixpath ) Unix2Win(winpath);
+    // Make a wide char version of potentially utf8 string
+    _ofn_ptr->lpstrInitialDir = new WCHAR[FNFC_MAX_PATH];
+    wcscpy((WCHAR *)_ofn_ptr->lpstrInitialDir, utf8towchar(winpath));
+    free(winpath);  // free temp copy now that we have a new wchar
+    //wprintf(L"lpstrInitialDir is '%ls'\n", (WCHAR*)(_ofn_ptr->lpstrInitialDir));
   }
   // SAVE THE CURRENT DIRECTORY
   //     See above warning (XXX) for OFN_NOCHANGEDIR
@@ -485,7 +511,7 @@ int Fl_WinAPI_Native_File_Chooser_Driver::showfile() {
     case Fl_Native_File_Chooser::BROWSE_FILE:
     case Fl_Native_File_Chooser::BROWSE_SAVE_FILE:
       set_single_pathname(wchartoutf8(_ofn_ptr->lpstrFile));
-      // Win2Unix(_pathnames[_tpathnames-1]);
+      if ( unixpath ) Win2Unix(_pathnames[_tpathnames-1]); // preserve unix style path
       break;
     case Fl_Native_File_Chooser::BROWSE_MULTI_FILE: {
       // EXTRACT MULTIPLE FILENAMES
@@ -497,11 +523,12 @@ int Fl_WinAPI_Native_File_Chooser_Driver::showfile() {
         //
         char pathname[FNFC_MAX_PATH];
         for ( const WCHAR *s = dirname + dirlen + 1;
-                 *s; s+= (wcslen(s)+1)) {
-                strcpy(pathname, wchartoutf8(dirname));
-                strcat(pathname, "\\");
-                strcat(pathname, wchartoutf8(s));
-                add_pathname(pathname);
+              *s; s += (wcslen(s)+1)) {
+          strncpy(pathname, wchartoutf8(dirname), FNFC_MAX_PATH);
+          strncat(pathname, "\\",                 FNFC_MAX_PATH);
+          strncat(pathname, wchartoutf8(s),       FNFC_MAX_PATH);
+	  pathname[FNFC_MAX_PATH-1] = 0;
+          add_pathname(pathname);
         }
       }
       // XXX
@@ -511,7 +538,12 @@ int Fl_WinAPI_Native_File_Chooser_Driver::showfile() {
       //
       if ( _tpathnames == 0 ) {
         add_pathname(wchartoutf8(dirname));
-        // Win2Unix(_pathnames[_tpathnames-1]);
+      }
+      // Caller specified unix path? Return unix paths
+      if ( unixpath ) {
+        for ( int t=0; t<_tpathnames; t++ ) {
+          Win2Unix(_pathnames[t]);
+        }
       }
       break;
     }
@@ -553,6 +585,7 @@ static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) {
 
 // SHOW DIRECTORY BROWSER
 int Fl_WinAPI_Native_File_Chooser_Driver::showdir() {
+  bool unixpath = IsUnixPath(_directory);      // caller uses unix paths?
   // initialize OLE only once
   fl_open_display();            // init needed by BIF_USENEWUI
   ClearBINF();
@@ -609,10 +642,20 @@ int Fl_WinAPI_Native_File_Chooser_Driver::showdir() {
   // PRESET DIR
   WCHAR presetname[FNFC_MAX_PATH];
   if ( _directory ) {
-    // Unix2Win(presetname);
-    wcsncpy(presetname, utf8towchar(_directory), FNFC_MAX_PATH);
-    presetname[FNFC_MAX_PATH-1] = 0;
+    // Temp copy of _dirname we can convert to windows path if needed
+    char *winpath = fl_strdup(_directory);
+    // Caller specified unix front slash path?
+    //     If so, convert to backslashes; windows native browser mishandles unix style paths.
+    //     We'll convert back to unix style when dialog completes.
+    //
+    if ( unixpath ) Unix2Win(winpath);
+    // Wide char version of potentially utf8 string
+    wcsncpy(presetname, utf8towchar(winpath), FNFC_MAX_PATH);
+    free(winpath);  // free temp copy now that we have a new wchar
+    presetname[FNFC_MAX_PATH-1] = 0; // dnull
+    presetname[FNFC_MAX_PATH-2] = 0;
     _binf_ptr->lParam = (LPARAM)presetname;
+    //wprintf(L"presetname is '%ls'\n", (WCHAR*)(presetname));
   }
   else _binf_ptr->lParam = 0;
   _binf_ptr->lpfn = Dir_CB;
@@ -627,9 +670,8 @@ int Fl_WinAPI_Native_File_Chooser_Driver::showdir() {
 
   WCHAR path[FNFC_MAX_PATH];
   if ( SHGetPathFromIDListW(pidl, path) ) {
-    // Win2Unix(path);
-    //add_pathname(path);
     add_pathname(wchartoutf8(path));
+    if ( unixpath ) Win2Unix(_pathnames[_tpathnames-1]); // preserve unix style path
   }
   FreePIDL(pidl);
   if ( !wcslen(path) ) return(1);             // don't return empty pathnames
diff --git test/native-filechooser.cxx test/native-filechooser.cxx
index dd0c481..df24330 100644
--- test/native-filechooser.cxx
+++ test/native-filechooser.cxx
@@ -93,10 +93,15 @@ int main(int argc, char **argv) {
   int argn = 1;
 #ifdef __APPLE__
   // OS X may add the process number as the first argument - ignore
-  if (argc>argn && strncmp(argv[1], "-psn_", 5)==0)
-    argn++;
+  if (argc>argn && strncmp(argv[argn], "-psn_", 5)==0) ++argn;
 #endif
 
+  // Parse preset filename (if any)
+  char *filename = 0;
+  if ( argc>argn && argv[argn][0] != '-' ) {
+    filename = argv[argn++];
+  }
+
   Fl_Window *win = new Fl_Window(640, 400+TERMINAL_HEIGHT, "Native File Chooser Test");
   win->size_range(win->w(), win->h(), 0, 0);
   win->begin();
@@ -105,7 +110,7 @@ int main(int argc, char **argv) {
 
     int x = 80, y = 10;
     G_filename = new Fl_Input(x, y, win->w()-80-10, 25, "Filename");
-    G_filename->value(argc <= argn ? "." : argv[argn]);
+    G_filename->value(filename ? filename : ".");
     G_filename->tooltip("Default filename");
 
     y += G_filename->h() + 10;
@@ -148,6 +153,11 @@ int main(int argc, char **argv) {
     win->resizable(G_filter);
   }
   win->end();
-  win->show(argc, argv);
+  // Pass show() remaining args we haven't already parsed..
+  {
+    char **args = argv+(argn-1);
+    int   nargs = argc-(argn-1);
+    win->show(nargs, args);
+  }
   return(Fl::run());
 }
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.