summaryrefslogtreecommitdiff
path: root/src/Fl_Native_File_Chooser_WIN32.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fl_Native_File_Chooser_WIN32.cxx')
-rw-r--r--src/Fl_Native_File_Chooser_WIN32.cxx1061
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 */