diff options
| author | maxim nikonov <maxim.nikonov@hqo.co> | 2026-02-05 15:21:34 +0500 |
|---|---|---|
| committer | maxim nikonov <maxim.nikonov@hqo.co> | 2026-02-05 15:21:34 +0500 |
| commit | db214d1145e46d527a46d1fc2519548d2c4d23f1 (patch) | |
| tree | cf0fd9922e4d54f6beb63888f9b28c8e2a787bdf /src/Fl_Native_File_Chooser_WIN32.cxx | |
| parent | 75fc94d6c71fe686f6dde5b41ad91cba2f6bdd6f (diff) | |
wip: fork
Diffstat (limited to 'src/Fl_Native_File_Chooser_WIN32.cxx')
| -rw-r--r-- | src/Fl_Native_File_Chooser_WIN32.cxx | 1061 |
1 files changed, 0 insertions, 1061 deletions
diff --git a/src/Fl_Native_File_Chooser_WIN32.cxx b/src/Fl_Native_File_Chooser_WIN32.cxx deleted file mode 100644 index f33af11c8..000000000 --- a/src/Fl_Native_File_Chooser_WIN32.cxx +++ /dev/null @@ -1,1061 +0,0 @@ -// -// FLTK native OS file chooser widget -// -// Copyright 1998-2021 by Bill Spitzak and others. -// Copyright 2004 Greg Ercolano. -// API changes + filter improvements by Nathan Vander Wilt 2005 -// -// This library is free software. Distribution and use rights are outlined in -// the file "COPYING" which should have been included with this file. If this -// file is missing or damaged, see the license at: -// -// https://www.fltk.org/COPYING.php -// -// Please see the following page on how to report bugs and issues: -// -// https://www.fltk.org/bugs.php -// - -// Any application to multi-folder implementation: -// http://www.codeproject.com/dialog/selectfolder.asp -// - -#ifndef FL_DOXYGEN // PREVENT DOXYGEN'S USE OF THIS FILE -#include <FL/Enumerations.H> - -#include <stdlib.h> // malloc -#include <stdio.h> // snprintf -#include <wchar.h> - -#define FNFC_MAX_PATH 32768 // XXX: MAX_PATH under win32 is 260, too small for modern use - -#include <FL/fl_string_functions.h> // fl_strdup() -#include "flstring.h" // fl_strlcpy()/cat() -#include <FL/Fl_Native_File_Chooser.H> -# include <windows.h> -# include <commdlg.h> // OPENFILENAMEW, GetOpenFileName() -# include <shlobj.h> // BROWSEINFOW, SHBrowseForFolder() -# include <FL/filename.H> // FL_EXPORT -#include <FL/platform.H> // fl_open_display - - -class Fl_WinAPI_Native_File_Chooser_Driver : public Fl_Native_File_Chooser_Driver { -private: - int _btype; // kind-of browser to show() - int _options; // general options - OPENFILENAMEW *_ofn_ptr; // GetOpenFileName() & GetSaveFileName() struct - BROWSEINFOW *_binf_ptr; // SHBrowseForFolder() struct - WCHAR *_wpattern; // pattern buffer for filter - char **_pathnames; // array of pathnames - int _tpathnames; // total pathnames - char *_directory; // default pathname to use - char *_title; // title for window - char *_filter; // user-side search filter - char *_parsedfilt; // filter parsed for Windows dialog - int _nfilters; // number of filters parse_filter counted - char *_preset_file; // the file to preselect - char *_errmsg; // error message - - // Private methods - void errmsg(const char *msg); - - void clear_pathnames(); - void set_single_pathname(const char *s); - void add_pathname(const char *s); - - void ClearOFN(); - void ClearBINF(); - void Win2Unix(char *s); - void Unix2Win(char *s); - bool IsUnixPath(const char *s); - int showfile(); - int showdir(); - - void parse_filter(const char *); - void clear_filters(); - void add_filter(const char *, const char *); -public: - Fl_WinAPI_Native_File_Chooser_Driver(int val); - ~Fl_WinAPI_Native_File_Chooser_Driver(); - void type(int t) FL_OVERRIDE; - int type() const FL_OVERRIDE; - void options(int o) FL_OVERRIDE; - int options() const FL_OVERRIDE; - int count() const FL_OVERRIDE; - const char *filename() const FL_OVERRIDE; - const char *filename(int i) const FL_OVERRIDE; - void directory(const char *val) FL_OVERRIDE; - const char *directory() const FL_OVERRIDE; - void title(const char *t) FL_OVERRIDE; - const char* title() const FL_OVERRIDE; - const char *filter() const FL_OVERRIDE; - void filter(const char *f) FL_OVERRIDE; - int filters() const FL_OVERRIDE; - void filter_value(int i) FL_OVERRIDE; - int filter_value() const FL_OVERRIDE; - void preset_file(const char*f) FL_OVERRIDE; - const char* preset_file() const FL_OVERRIDE; - const char *errmsg() const FL_OVERRIDE; - int show() FL_OVERRIDE; -}; - - -Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { - platform_fnfc = new Fl_WinAPI_Native_File_Chooser_Driver(val); -} - - -static LPCWSTR utf8towchar(const char *in); -static char *wchartoutf8(LPCWSTR in); - - -#define LCURLY_CHR '{' -#define RCURLY_CHR '}' -#define LBRACKET_CHR '[' -#define RBRACKET_CHR ']' - -// STATIC: Print Windows 'double-null' string (debug) -#ifdef DEBUG -#include <stdio.h> -static void dnullprint(char *wp) { - if ( ! wp ) return; - for ( int t=0; true; t++ ) { - if ( wp[t] == '\0' && wp[t+1] == '\0' ) { - printf("\\0\\0"); - fflush(stdout); - return; - } else if ( wp[t] == '\0' ) { - printf("\\0"); - } else { - printf("%c",wp[t]); - } - } -} -#endif - -// Return length of double-null string -// Includes single nulls in count, excludes trailing double-null. -// -// 1234 567 -// |||/\||| -// IN: "one\0two\0\0" -// OUT: 7 -// -static int dnulllen(const char *wp) { - int len = 0; - while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) ) { - ++wp; - ++len; - } - return(len); -} - -// STATIC: Append a string to another, leaving terminated with DOUBLE NULL. -// Automatically handles extending length of string. -// wp can be NULL (a new wp will be allocated and initialized). -// string must be NULL terminated. -// The pointer wp may be modified on return. -// -static void dnullcat(char*&wp, const char *string, int n = -1 ) { - //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n"); - size_t inlen = ( n < 0 ) ? strlen(string) : n; - char *wp2 = 0; // used to point at end of last string - if ( ! wp ) { - wp = new char[inlen + 4]; - *(wp+0) = '\0'; - *(wp+1) = '\0'; - wp2 = wp; // no "last string", point at begin of buffer - } else { - int wplen = dnulllen(wp); - // Make copy of wp into larger buffer - char *tmp = new char[wplen + inlen + 4]; - memcpy(tmp, wp, wplen+2); // copy of wp plus doublenull - delete[] wp; // delete old wp - wp = tmp; // use new copy - wp2 = wp + wplen + 1; // point at second null - //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen); - } - - // *wp2 points at second null; the buffer is large enough to copy the string! - strcpy(wp2, string); - *(wp2+inlen+1) = '\0'; // Leave string double-null terminated - //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n"); -} - -// CTOR -Fl_WinAPI_Native_File_Chooser_Driver::Fl_WinAPI_Native_File_Chooser_Driver(int val) : - Fl_Native_File_Chooser_Driver(val) { - _btype = val; - _options = Fl_Native_File_Chooser::NO_OPTIONS; - _ofn_ptr = new OPENFILENAMEW; - _binf_ptr = new BROWSEINFOW; - _wpattern = 0; - memset((void*)_ofn_ptr, 0, sizeof(OPENFILENAMEW)); - _ofn_ptr->lStructSize = sizeof(OPENFILENAMEW); - _ofn_ptr->hwndOwner = 0L; - memset((void*)_binf_ptr, 0, sizeof(BROWSEINFOW)); - _pathnames = NULL; - _tpathnames = 0; - _directory = NULL; - _title = NULL; - _filter = NULL; - _parsedfilt = NULL; - _nfilters = 0; - _preset_file = NULL; - _errmsg = NULL; -} - -// DTOR -Fl_WinAPI_Native_File_Chooser_Driver::~Fl_WinAPI_Native_File_Chooser_Driver() { - //_pathnames // managed by clear_pathnames() - //_tpathnames // managed by clear_pathnames() - _directory = strfree(_directory); - _title = strfree(_title); - _filter = strfree(_filter); - //_parsedfilt // managed by clear_filters() - //_nfilters // managed by clear_filters() - _preset_file = strfree(_preset_file); - _errmsg = strfree(_errmsg); - clear_filters(); - clear_pathnames(); - ClearOFN(); - ClearBINF(); - delete _binf_ptr; - delete _ofn_ptr; - if ( _wpattern ) delete[] _wpattern; -} - -// SET TYPE OF BROWSER -void Fl_WinAPI_Native_File_Chooser_Driver::type(int val) { - _btype = val; -} - -// GET TYPE OF BROWSER -int Fl_WinAPI_Native_File_Chooser_Driver::type() const { - return( _btype ); -} - -// SET OPTIONS -void Fl_WinAPI_Native_File_Chooser_Driver::options(int val) { - _options = val; -} - -// GET OPTIONS -int Fl_WinAPI_Native_File_Chooser_Driver::options() const { - return(_options); -} - -// PRIVATE: SET ERROR MESSAGE -void Fl_WinAPI_Native_File_Chooser_Driver::errmsg(const char *val) { - _errmsg = strfree(_errmsg); - _errmsg = strnew(val); -} - -// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS -void Fl_WinAPI_Native_File_Chooser_Driver::clear_pathnames() { - if ( _pathnames ) { - while ( --_tpathnames >= 0 ) { - _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); - } - delete[] _pathnames; - _pathnames = NULL; - } - _tpathnames = 0; -} - -// SET A SINGLE PATHNAME -void Fl_WinAPI_Native_File_Chooser_Driver::set_single_pathname(const char *s) { - clear_pathnames(); - _pathnames = new char*[1]; - _pathnames[0] = strnew(s); - _tpathnames = 1; -} - -// ADD PATHNAME TO EXISTING ARRAY -void Fl_WinAPI_Native_File_Chooser_Driver::add_pathname(const char *s) { - if ( ! _pathnames ) { - // Create first element in array - ++_tpathnames; - _pathnames = new char*[_tpathnames]; - } else { - // Grow array by 1 - char **tmp = new char*[_tpathnames+1]; // create new buffer - memcpy((void*)tmp, (void*)_pathnames, - sizeof(char*)*_tpathnames); // copy old - delete[] _pathnames; // delete old - _pathnames = tmp; // use new - ++_tpathnames; - } - _pathnames[_tpathnames-1] = strnew(s); -} - -// FREE A PIDL (Pointer to IDentity List) -static void FreePIDL(LPITEMIDLIST pidl) { - IMalloc *imalloc = NULL; - if ( SUCCEEDED(SHGetMalloc(&imalloc)) ) { - imalloc->Free(pidl); - imalloc->Release(); - imalloc = NULL; - } -} - -// CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS -void Fl_WinAPI_Native_File_Chooser_Driver::ClearOFN() { - // Free any previously allocated lpstrFile before zeroing out _ofn_ptr - if ( _ofn_ptr->lpstrFile ) { - delete[] _ofn_ptr->lpstrFile; - _ofn_ptr->lpstrFile = NULL; - } - if ( _ofn_ptr->lpstrInitialDir ) { - delete[] (TCHAR*) _ofn_ptr->lpstrInitialDir; //msvc6 compilation fix - _ofn_ptr->lpstrInitialDir = NULL; - } - _ofn_ptr->lpstrFilter = NULL; // (deleted elsewhere) - int temp = _ofn_ptr->nFilterIndex; // keep the filter_value - memset((void*)_ofn_ptr, 0, sizeof(OPENFILENAMEW)); - _ofn_ptr->lStructSize = sizeof(OPENFILENAMEW); - _ofn_ptr->nFilterIndex = temp; -} - -// CLEAR MICROSOFT BINF (BROWSER INFO) CLASS -void Fl_WinAPI_Native_File_Chooser_Driver::ClearBINF() { - if ( _binf_ptr->pidlRoot ) { - FreePIDL((ITEMIDLIST*)_binf_ptr->pidlRoot); - _binf_ptr->pidlRoot = NULL; - } - memset((void*)_binf_ptr, 0, sizeof(BROWSEINFOW)); -} - -// CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES -void Fl_WinAPI_Native_File_Chooser_Driver::Win2Unix(char *s) { - while ( (s=strchr(s,'\\')) ) *s = '/'; -} - -// CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES -void Fl_WinAPI_Native_File_Chooser_Driver::Unix2Win(char *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 -// Returns a malloc()ed copy of the cwd that can -// later be freed with RestoreCWD(). May return 0 on error. -// -static char *SaveCWD() { - char *thecwd = 0; - DWORD thecwdsz = GetCurrentDirectory(0,0); - if ( thecwdsz > 0 ) { - thecwd = (char*)malloc(thecwdsz); - if (GetCurrentDirectory(thecwdsz, thecwd) == 0 ) { - free(thecwd); thecwd = 0; - } - } - return thecwd; -} - -// RESTORES THE CWD SAVED BY SaveCWD(), FREES STRING -// Always returns NULL (string was freed). -// -static void RestoreCWD(char *thecwd) { - if ( !thecwd ) return; - SetCurrentDirectory(thecwd); - free(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; - _ofn_ptr->Flags |= OFN_NOVALIDATE; // prevent disabling of front slashes - _ofn_ptr->Flags |= OFN_HIDEREADONLY; // hide goofy readonly flag - // USE NEW BROWSER - _ofn_ptr->Flags |= OFN_EXPLORER; // use newer explorer windows - _ofn_ptr->Flags |= OFN_ENABLESIZING; // allow window to be resized (hey, why not?) - _ofn_ptr->Flags |= OFN_NOCHANGEDIR; // XXX: docs say ineffective on XP/2K/NT, but set it anyway.. - - switch ( _btype ) { - case Fl_Native_File_Chooser::BROWSE_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY: - abort(); // never happens: handled by showdir() - case Fl_Native_File_Chooser::BROWSE_FILE: - break; - case Fl_Native_File_Chooser::BROWSE_MULTI_FILE: - _ofn_ptr->Flags |= OFN_ALLOWMULTISELECT; - break; - case Fl_Native_File_Chooser::BROWSE_SAVE_FILE: - if ( options() & Fl_Native_File_Chooser::SAVEAS_CONFIRM && type() == Fl_Native_File_Chooser::BROWSE_SAVE_FILE ) { - _ofn_ptr->Flags |= OFN_OVERWRITEPROMPT; - } - break; - } - // SPACE FOR RETURNED FILENAME - _ofn_ptr->lpstrFile = new WCHAR[fsize]; - _ofn_ptr->nMaxFile = (DWORD)(fsize-1); - _ofn_ptr->lpstrFile[0] = 0; - _ofn_ptr->lpstrFile[1] = 0; // dnull - // PARENT WINDOW - _ofn_ptr->hwndOwner = GetForegroundWindow(); - // DIALOG TITLE - if (_title) { - static WCHAR wtitle[200]; - wcsncpy(wtitle, utf8towchar(_title), 200); - wtitle[200-1] = 0; - _ofn_ptr->lpstrTitle = wtitle; - } else { - _ofn_ptr->lpstrTitle = NULL; - } - // FILTER - if (_parsedfilt != NULL) { // to convert a null-containing char string into a widechar string - // NEW - if ( !_wpattern ) _wpattern = new WCHAR[FNFC_MAX_PATH]; - const char *p = _parsedfilt; - while(*(p + strlen(p) + 1) != 0) p += strlen(p) + 1; - p += strlen(p) + 2; - MultiByteToWideChar(CP_UTF8, 0, _parsedfilt, (int) (p - _parsedfilt), _wpattern, FNFC_MAX_PATH); - _ofn_ptr->lpstrFilter = _wpattern; - } else { - _ofn_ptr->lpstrFilter = NULL; - } - // PRESET FILE - // If set, supercedes _directory. See KB Q86920 for details - // XXX: this doesn't preselect the item in the listview.. why? - // - if ( _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]; - snprintf(msg, 80, "preset_file() filename is too long: %ld is >=%ld", (long)len, (long)fsize); - errmsg(msg); - return(-1); - } - 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 ) { - // 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); - // 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 - // - char *save_cwd = SaveCWD(); // must be freed with RestoreCWD() - // OPEN THE DIALOG WINDOW - int err; - if ( _btype == Fl_Native_File_Chooser::BROWSE_SAVE_FILE ) { - err = GetSaveFileNameW(_ofn_ptr); - } else { - err = GetOpenFileNameW(_ofn_ptr); - } - // GET EXTENDED ERROR - int exterr = CommDlgExtendedError(); - // RESTORE CURRENT DIRECTORY - RestoreCWD(save_cwd); save_cwd = 0; // also frees save_cwd - // ERROR OR CANCEL? - if ( err == 0 ) { - if ( exterr == 0 ) return(1); // user hit cancel - // Otherwise, an error occurred.. - char msg[80]; - snprintf(msg, 80, "CommDlgExtendedError() code=%d", exterr); - errmsg(msg); - return(-1); - } - // PREPARE PATHNAMES FOR RETURN - switch ( _btype ) { - case Fl_Native_File_Chooser::BROWSE_FILE: - case Fl_Native_File_Chooser::BROWSE_SAVE_FILE: - set_single_pathname(wchartoutf8(_ofn_ptr->lpstrFile)); - if ( unixpath ) Win2Unix(_pathnames[_tpathnames-1]); // preserve unix style path - break; - case Fl_Native_File_Chooser::BROWSE_MULTI_FILE: { - // EXTRACT MULTIPLE FILENAMES - const WCHAR *dirname = _ofn_ptr->lpstrFile; - size_t dirlen = wcslen(dirname); - if ( dirlen > 0 ) { - // WALK STRING SEARCHING FOR 'DOUBLE-NULL' - // eg. "/dir/name\0foo1\0foo2\0foo3\0\0" - // - char pathname[FNFC_MAX_PATH]; - for ( const WCHAR *s = dirname + dirlen + 1; *s; s += (wcslen(s)+1)) { - // ISSUE #206: replace strncpy/cat with fl_strlcpy/cat - fl_strlcpy(pathname, wchartoutf8(dirname), FNFC_MAX_PATH); - fl_strlcat(pathname, "\\", FNFC_MAX_PATH); - fl_strlcat(pathname, wchartoutf8(s), FNFC_MAX_PATH); - add_pathname(pathname); - } - } - // XXX - // Work around problem where pasted forward-slash pathname - // into the file browser causes new "Explorer" interface - // not to grok forward slashes, passing back as a 'filename'..! - // - if ( _tpathnames == 0 ) { - add_pathname(wchartoutf8(dirname)); - } - // Caller specified unix path? Return unix paths - if ( unixpath ) { - for ( int t=0; t<_tpathnames; t++ ) { - Win2Unix(_pathnames[t]); - } - } - break; - } - case Fl_Native_File_Chooser::BROWSE_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY: - case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY: - abort(); // never happens: handled by showdir() - } - return(0); -} - -// Used by SHBrowseForFolder(), sets initial selected dir. -// Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes -// Subject: How to specify to select an initial folder .." -// -static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) { - switch (msg) { - case BFFM_INITIALIZED: - if (data) ::SendMessageW(win, BFFM_SETSELECTIONW, TRUE, data); - break; - case BFFM_SELCHANGED: - TCHAR path[FNFC_MAX_PATH]; - if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) { - ::SendMessage(win, BFFM_ENABLEOK, 0, 1); - } else { - // disable ok button if not a path - ::SendMessage(win, BFFM_ENABLEOK, 0, 0); - } - break; - case BFFM_VALIDATEFAILED: - // we could pop up an annoying message here. - // also needs set ulFlags |= BIF_VALIDATE - break; - default: - break; - } - return(0); -} - -// 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(); - clear_pathnames(); - // PARENT WINDOW - _binf_ptr->hwndOwner = GetForegroundWindow(); - // DIALOG TITLE - //_binf_ptr->lpszTitle = _title ? _title : NULL; - if (_title) { - static WCHAR wtitle[256]; - wcsncpy(wtitle, utf8towchar(_title), 256); - wtitle[255] = 0; - _binf_ptr->lpszTitle = wtitle; - } else { - _binf_ptr->lpszTitle = NULL; - } - - // FLAGS - _binf_ptr->ulFlags = 0; // initialize - - // TBD: make sure matches to runtime system, if need be. - //(what if _WIN32_IE doesn't match system? does the program not run?) - // - // TBD: match all 3 types of directories - // - // NOTE: *Don't* use BIF_SHAREABLE. It /disables/ mapped network shares - // from being visible in BROWSE_DIRECTORY mode. Walter Garm's comments: - // - // --- Garms, Walter (GE EntSol, Security) wrote: - // With your help I was able to solve the problem of the network drives. - // For Version 6.0, at least, the BIF_SHAREABLE flag seems to have the - // opposite sense: With BIF_SHAREABLE not set I see the mapped network - // drives, and with BIF_SHAREABLE set I do not. - // --- - -#if defined(BIF_NONEWFOLDERBUTTON) // Version 6.0 - if ( _btype == Fl_Native_File_Chooser::BROWSE_DIRECTORY ) _binf_ptr->ulFlags |= BIF_NONEWFOLDERBUTTON; - _binf_ptr->ulFlags |= BIF_USENEWUI | BIF_RETURNONLYFSDIRS; -#elif defined(BIF_USENEWUI) // Version 5.0 - if ( _btype == Fl_Native_File_Chooser::BROWSE_DIRECTORY ) _binf_ptr->ulFlags |= BIF_EDITBOX; - else if ( _btype == Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY ) _binf_ptr->ulFlags |= BIF_USENEWUI; - _binf_ptr->ulFlags |= BIF_RETURNONLYFSDIRS; -#elif defined(BIF_EDITBOX) // Version 4.71 - _binf_ptr->ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX; -#else // Version Old - _binf_ptr->ulFlags |= BIF_RETURNONLYFSDIRS; -#endif - - // BUFFER - //char displayname[FNFC_MAX_PATH]; - WCHAR displayname[FNFC_MAX_PATH]; - _binf_ptr->pszDisplayName = displayname; - - // PRESET DIR - WCHAR presetname[FNFC_MAX_PATH]; - if ( _directory ) { - // 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; - // OPEN BROWSER - LPITEMIDLIST pidl = SHBrowseForFolderW(_binf_ptr); - // CANCEL? - if ( pidl == NULL ) return(1); - - // GET THE PATHNAME(S) THE USER SELECTED - // TBD: expand NetHood shortcuts from this PIDL?? - // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp - - WCHAR path[FNFC_MAX_PATH]; - if ( SHGetPathFromIDListW(pidl, 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 - return(0); -} - -// RETURNS: -// 0 - user picked a file -// 1 - user cancelled -// -1 - failed; errmsg() has reason -// -int Fl_WinAPI_Native_File_Chooser_Driver::show() { - int retval; - if ( _btype == Fl_Native_File_Chooser::BROWSE_DIRECTORY || - _btype == Fl_Native_File_Chooser::BROWSE_MULTI_DIRECTORY || - _btype == Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY ) { - retval = showdir(); - } else { - retval = showfile(); - } - // restore the correct state of mouse buttons and keyboard modifier keys (STR #3221) - HWND h = GetForegroundWindow(); - if (h) { - WNDPROC windproc = (WNDPROC)GetWindowLongPtrW(h, GWLP_WNDPROC); - CallWindowProc(windproc, h, WM_ACTIVATEAPP, 1, 0); - } - return retval; -} - -// RETURN ERROR MESSAGE -const char *Fl_WinAPI_Native_File_Chooser_Driver::errmsg() const { - return(_errmsg ? _errmsg : "No error"); -} - -// GET FILENAME -const char* Fl_WinAPI_Native_File_Chooser_Driver::filename() const { - if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); - return(""); -} - -// GET FILENAME FROM LIST OF FILENAMES -const char* Fl_WinAPI_Native_File_Chooser_Driver::filename(int i) const { - if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); - return(""); -} - -// GET TOTAL FILENAMES CHOSEN -int Fl_WinAPI_Native_File_Chooser_Driver::count() const { - return(_tpathnames); -} - -// PRESET PATHNAME -// Can be NULL if no preset is desired. -// -void Fl_WinAPI_Native_File_Chooser_Driver::directory(const char *val) { - _directory = strfree(_directory); - _directory = strnew(val); -} - -// GET PRESET PATHNAME -// Can return NULL if none set. -// -const char *Fl_WinAPI_Native_File_Chooser_Driver::directory() const { - return(_directory); -} - -// SET TITLE -// Can be NULL if no title desired. -// -void Fl_WinAPI_Native_File_Chooser_Driver::title(const char *val) { - _title = strfree(_title); - _title = strnew(val); -} - -// GET TITLE -// Can return NULL if none set. -// -const char *Fl_WinAPI_Native_File_Chooser_Driver::title() const { - return(_title); -} - -// SET FILTER -// Can be NULL if no filter needed -// -void Fl_WinAPI_Native_File_Chooser_Driver::filter(const char *val) { - _filter = strfree(_filter); - clear_filters(); - if ( val ) { - _filter = strnew(val); - parse_filter(_filter); - } - add_filter("All Files", "*.*"); // always include 'all files' option - -#ifdef DEBUG - dnullprint(_parsedfilt); -#endif /*DEBUG*/ -} - -// GET FILTER -// Can return NULL if none set. -// -const char *Fl_WinAPI_Native_File_Chooser_Driver::filter() const { - return(_filter); -} - -// CLEAR FILTERS -void Fl_WinAPI_Native_File_Chooser_Driver::clear_filters() { - _nfilters = 0; - _parsedfilt = strfree(_parsedfilt); -} - -// ADD A FILTER -void Fl_WinAPI_Native_File_Chooser_Driver::add_filter(const char *name_in, // name of filter (optional: can be null) - const char *winfilter) { // windows style filter (eg. "*.cxx;*.h") - // No name? Make one.. - char name[1024]; - if ( !name_in || name_in[0] == '\0' ) { - snprintf(name, sizeof(name), "%.*s Files", int(sizeof(name)-10), winfilter); - } else { - if ((strlen(name_in)+strlen(winfilter)+3) < sizeof(name)) { - snprintf(name, sizeof(name), "%s (%s)", name_in, winfilter); - } else { - snprintf(name, sizeof(name), "%.*s", int(sizeof(name))-1, name_in); - } - } - dnullcat(_parsedfilt, name); - dnullcat(_parsedfilt, winfilter); - _nfilters++; - //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter); -} - -// RETURN HOW MANY DIFFERENT FILTERS WERE SPECIFIED -// In: "foo.[CH]" or "foo.{C,H}" -// Out: 2 -// -static int count_filters(const char *filter) { - int count = 0; - char mode = 0; - const char *in = filter; - while (*in) { - switch(*in) { - case '\\': // escape next character - ++in; if ( *in == 0 ) continue; // skip escape. EOL? done - ++in; // skip escaped char - continue; - case LCURLY_CHR: // start "{aaa,bbb}" - mode = *in; // set mode, parse over curly - ++count; // at least +1 wildcard - break; - case RCURLY_CHR: // end "{aaa,bbb}" - if ( mode == LCURLY_CHR ) // disable curly mode (if on) - mode = 0; - break; - case LBRACKET_CHR: // start "[xyz]" - mode = *in; // set mode, parse over bracket - break; - case RBRACKET_CHR: // end "[xyz]" - if ( mode == LBRACKET_CHR ) // disable bracket mode (if on) - mode = 0; - break; - default: // any other char - switch (mode) { // handle {} or [] modes - case LCURLY_CHR: // handle "{aaa,bbb}" - if (*in==',' || *in=='|') // ',' and '|' adds filters - ++count; - break; - case LBRACKET_CHR: // handle "[xyz]" - ++count; // all chars in []'s add new filter - break; - } - break; - } - ++in; // parse past char - } - return count > 0 ? count : 1; // return at least 1 -} - -// Convert FLTK style pattern matches to windows 'double-null' pattern -// Returns with the parsed double-null result in '_parsedfilt'. -// -// Handles: -// IN OUT -// ----------- ----------------------------- -// *.{ma,mb} "*.{ma,mb} Files\0*.ma;*.mb\0\0" -// *.[abc] "*.[abc] Files\0*.a;*.b;*.c\0\0" -// *.txt "*.txt Files\0*.txt\0\0" -// C Files\t*.[ch] "C Files\0*.c;*.h\0\0" -// -// Example: -// IN: "*.{ma,mb}" -// OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0" -// --------------- --------- --------- --- -// | | | | -// Title Wildcards Title Wildcards -// -// Parsing Mode: -// IN:"C Files\t*.{cxx,h}" -// ||||||| ||||||||| -// mode: nnnnnnn ww{{{{{{{ -// \_____/ \_______/ -// Name Wildcard -// -void Fl_WinAPI_Native_File_Chooser_Driver::parse_filter(const char *in) { - clear_filters(); - if ( ! in || in[0] == '\0' ) return; - - int has_name = strchr(in, '\t') ? 1 : 0; - char mode = has_name ? 'n' : 'w'; // parse mode: n=name, w=wildcard - - // whatever input string is, our output won't be much longer in length.. - // use double length just for safety. - size_t slen = strlen(in); - char *wildprefix = new char[(slen+1)*2]; wildprefix[0] = 0; - char *comp = new char[(slen+1)*2]; comp[0] = 0; - char *name = new char[(slen+1)*2]; name[0] = 0; - - // Init - int nwildcards = 0; - int maxfilters = count_filters(in) + 1; // count wildcard seps - char **wildcards = new char*[maxfilters]; // parsed wildcards (can be several) - int t; - for ( t=0; t<maxfilters; t++ ) { - wildcards[t] = new char[slen+1]; - wildcards[t][0] = '\0'; - } - - // Parse - for ( ; 1; in++ ) { - - // DEBUG - // printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n", - // *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]); - - switch (*in) { - case ',': - case '|': - if ( mode == LCURLY_CHR ) { - // create new wildcard, copy in prefix - strcat(wildcards[nwildcards++], wildprefix); - continue; - } else { - goto regchar; - } - continue; - - // FINISHED PARSING A NAME? - case '\t': - if ( mode != 'n' ) goto regchar; - // finish parsing name? switch to wildcard mode - mode = 'w'; - break; - - // ESCAPE NEXT CHAR - case '\\': - ++in; - goto regchar; - - // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? - case '\r': - case '\n': - case '\0': - { - if ( mode == 'w' ) { // finished parsing wildcard? - if ( nwildcards == 0 ) { - strcpy(wildcards[nwildcards++], wildprefix); - } - // Append wildcards in Microsoft's "*.one;*.two" format - comp[0] = 0; - for ( t=0; t<nwildcards; t++ ) { - if ( t != 0 ) strcat(comp, ";"); - strcat(comp, wildcards[t]); - } - // Add if not empty - if ( comp[0] ) { - add_filter(name, comp); - } - } - // RESET - for ( t=0; t<maxfilters; t++ ) { - wildcards[t][0] = '\0'; - } - nwildcards = 0; - wildprefix[0] = name[0] = '\0'; - mode = strchr(in,'\t') ? 'n' : 'w'; - // DONE? - if ( *in == '\0' ) { // done - // Free everything - delete[] wildprefix; - delete[] comp; - delete[] name; - for ( t=0; t<maxfilters; t++ ) delete[] wildcards[t]; - delete[] wildcards; - return; - } - continue; // not done yet, more filters - } - - // STARTING A WILDCARD? - case LBRACKET_CHR: - case LCURLY_CHR: - mode = *in; - if ( *in == LCURLY_CHR ) { - // create new wildcard - strcat(wildcards[nwildcards++], wildprefix); - } - continue; - - // ENDING A WILDCARD? - case RBRACKET_CHR: - case RCURLY_CHR: - mode = 'w'; // back to wildcard mode - continue; - - // ALL OTHER NON-SPECIAL CHARACTERS - default: - regchar: // handle regular char - switch ( mode ) { - case LBRACKET_CHR: - // create new wildcard - ++nwildcards; - // copy in prefix - strcpy(wildcards[nwildcards-1], wildprefix); - // append search char - chrcat(wildcards[nwildcards-1], *in); - continue; - - case LCURLY_CHR: - if ( nwildcards > 0 ) { - chrcat(wildcards[nwildcards-1], *in); - } - continue; - - case 'n': - chrcat(name, *in); - continue; - - case 'w': - chrcat(wildprefix, *in); - for ( t=0; t<nwildcards; t++ ) { - chrcat(wildcards[t], *in); - } - continue; - } - break; - } - } -} - -// SET 'CURRENTLY SELECTED FILTER' -void Fl_WinAPI_Native_File_Chooser_Driver::filter_value(int i) { - _ofn_ptr->nFilterIndex = i + 1; -} - -// RETURN VALUE OF 'CURRENTLY SELECTED FILTER' -int Fl_WinAPI_Native_File_Chooser_Driver::filter_value() const { - return(_ofn_ptr->nFilterIndex ? _ofn_ptr->nFilterIndex-1 : _nfilters+1); -} - -// PRESET FILENAME FOR 'SAVE AS' CHOOSER -void Fl_WinAPI_Native_File_Chooser_Driver::preset_file(const char* val) { - _preset_file = strfree(_preset_file); - _preset_file = strnew(val); -} - -// GET PRESET FILENAME FOR 'SAVE AS' CHOOSER -const char* Fl_WinAPI_Native_File_Chooser_Driver::preset_file() const { - return(_preset_file); -} - -int Fl_WinAPI_Native_File_Chooser_Driver::filters() const { - return(_nfilters); -} - -static char *wchartoutf8(LPCWSTR in) { - static char *out = NULL; - static int lchar = 0; - if (in == NULL)return NULL; - int utf8len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL); - if (utf8len > lchar) { - lchar = utf8len; - out = (char *)realloc(out, lchar * sizeof(char)); - } - WideCharToMultiByte(CP_UTF8, 0, in, -1, out, utf8len, NULL, NULL); - return out; -} - -static LPCWSTR utf8towchar(const char *in) { - static WCHAR *wout = NULL; - static int lwout = 0; - if (in == NULL)return NULL; - int wlen = MultiByteToWideChar(CP_UTF8, 0, in, -1, NULL, 0); - if (wlen > lwout) { - lwout = wlen; - wout = (WCHAR *)realloc(wout, lwout * sizeof(WCHAR)); - } - MultiByteToWideChar(CP_UTF8, 0, in, -1, wout, wlen); - return wout; -} - -#endif /* !FL_DOXYGEN */ |
