diff --git a/base/project.js b/base/project.js index 9e6fa4c4..e0794cd5 100644 --- a/base/project.js +++ b/base/project.js @@ -70,7 +70,7 @@ if (!flags.lite) { } if (flags.physics) { - project.add_cfiles("sources/libs/asim/asim.c"); + project.add_cfiles("sources/libs/asim.c"); project.add_define("arm_physics"); } @@ -273,16 +273,16 @@ if (flags.with_eval) { project.add_define("WITH_EVAL"); project.add_cfiles("sources/libs/quickjs-amalgam.c"); project.add_define("QJS_BUILD_LIBC"); - if (platform === "linux") { - project.add_lib("m"); - project.add_define("_GNU_SOURCE"); - project.add_define("environ=__environ"); - project.add_define("sighandler_t=__sighandler_t"); - } - else if (platform === "windows") { - project.add_define("WIN32_LEAN_AND_MEAN"); - project.add_define("_WIN32_WINNT=0x0602"); - } + // if (platform === "linux") { + // project.add_lib("m"); + // project.add_define("_GNU_SOURCE"); + // project.add_define("environ=__environ"); + // project.add_define("sighandler_t=__sighandler_t"); + // } + // else if (platform === "windows") { + // project.add_define("WIN32_LEAN_AND_MEAN"); + // project.add_define("_WIN32_WINNT=0x0602"); + // } } if (flags.with_iron) { @@ -315,14 +315,8 @@ else if (platform === "ios") { if (flags.with_nfd && (platform === "windows" || platform === "linux" || platform === "macos")) { project.add_define("WITH_NFD"); - project.add_include_dir("sources/libs/nfd"); - project.add_cfiles("sources/libs/nfd/nfd_common.c"); - - if (platform === "windows") { - project.add_cfiles("sources/libs/nfd/nfd_win.cpp"); - } - else if (platform === "linux") { - project.add_cfiles("sources/libs/nfd/nfd_gtk.c"); + project.add_cfiles("sources/libs/nfd.c"); + if (platform === "linux") { project.add_include_dir("/usr/include/gtk-3.0"); project.add_include_dir("/usr/include/glib-2.0"); project.add_include_dir("/usr/lib/x86_64-linux-gnu/glib-2.0/include"); @@ -337,8 +331,8 @@ if (flags.with_nfd && (platform === "windows" || platform === "linux" || platfor project.add_lib("gobject-2.0"); project.add_lib("glib-2.0"); } - else { - project.add_cfiles("sources/libs/nfd/nfd_cocoa.m"); + else if (platform == "macos") { + project.add_cfiles("sources/libs/nfd.m"); } } diff --git a/base/sources/libs/asim/asim.c b/base/sources/libs/asim.c similarity index 100% rename from base/sources/libs/asim/asim.c rename to base/sources/libs/asim.c diff --git a/base/sources/libs/asim/asim.h b/base/sources/libs/asim.h similarity index 100% rename from base/sources/libs/asim/asim.h rename to base/sources/libs/asim.h diff --git a/base/sources/libs/nfd/nfd_win.cpp b/base/sources/libs/nfd.c similarity index 58% rename from base/sources/libs/nfd/nfd_win.cpp rename to base/sources/libs/nfd.c index 949da2b5..2bc6c8e7 100644 --- a/base/sources/libs/nfd/nfd_win.cpp +++ b/base/sources/libs/nfd.c @@ -1,9 +1,528 @@ -/* - Native File Dialog +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// https://github.com/mlabbe/nativefiledialog - http://www.frogtoss.com/labs - */ +#include +#include +#include +#include +#include "nfd.h" +#include "../iron_global.h" +static char g_errorstr[NFD_MAX_STRLEN] = {0}; + +/* public routines */ + +const char *NFD_GetError( void ) +{ + return g_errorstr; +} + +size_t NFD_PathSet_GetCount( const nfdpathset_t *pathset ) +{ + assert(pathset); + return pathset->count; +} + +nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathset, size_t num ) +{ + assert(pathset); + assert(num < pathset->count); + + return pathset->buf + pathset->indices[num]; +} + +void NFD_PathSet_Free( nfdpathset_t *pathset ) +{ + assert(pathset); + NFDi_Free( pathset->indices ); + NFDi_Free( pathset->buf ); +} + +/* internal routines */ + +void *NFDi_Malloc( size_t bytes ) +{ + void *ptr = malloc(bytes); + if ( !ptr ) + NFDi_SetError("NFDi_Malloc failed."); + + return ptr; +} + +void NFDi_Free( void *ptr ) +{ + assert(ptr); + free(ptr); +} + +void NFDi_SetError( const char *msg ) +{ + int bTruncate = NFDi_SafeStrncpy( g_errorstr, msg, NFD_MAX_STRLEN ); + assert( !bTruncate ); _NFD_UNUSED(bTruncate); +} + + +int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ) +{ + size_t n = maxCopy; + char *d = dst; + + assert( src ); + assert( dst ); + + while ( n > 0 && *src != '\0' ) + { + *d++ = *src++; + --n; + } + + /* Truncation case - + terminate string and return true */ + if ( n == 0 ) + { + dst[maxCopy-1] = '\0'; + return 1; + } + + /* No truncation. Append a single NULL and return. */ + *d = '\0'; + return 0; +} + + +/* adapted from microutf8 */ +int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ) +{ + /* This function doesn't properly check validity of UTF-8 character + sequence, it is supposed to use only with valid UTF-8 strings. */ + + int32_t character_count = 0; + int32_t i = 0; /* Counter used to iterate over string. */ + nfdchar_t maybe_bom[4]; + + /* If there is UTF-8 BOM ignore it. */ + if (strlen(str) > 2) + { + strncpy(maybe_bom, str, 3); + maybe_bom[3] = 0; + if (strcmp(maybe_bom, (nfdchar_t*)NFD_UTF8_BOM) == 0) + i += 3; + } + + while(str[i]) + { + if (str[i] >> 7 == 0) + { + /* If bit pattern begins with 0 we have ascii character. */ + ++character_count; + } + else if (str[i] >> 6 == 3) + { + /* If bit pattern begins with 11 it is beginning of UTF-8 byte sequence. */ + ++character_count; + } + else if (str[i] >> 6 == 2) + ; /* If bit pattern begins with 10 it is middle of utf-8 byte sequence. */ + else + { + /* In any other case this is not valid UTF-8. */ + return -1; + } + ++i; + } + + return character_count; +} + +int NFDi_IsFilterSegmentChar( char ch ) +{ + return (ch==','||ch==';'||ch=='\0'); +} + +#ifdef IRON_LINUX + +#include + +const char INIT_FAIL_MSG[] = "gtk_init_check failed to initilaize GTK+"; + +static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize ) +{ + const char SEP[] = ", "; + + size_t len = strlen(filterName); + if ( len != 0 ) + { + strncat( filterName, SEP, bufsize - len - 1 ); + len += strlen(SEP); + } + + strncat( filterName, typebuf, bufsize - len - 1 ); +} + +static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList ) +{ + GtkFileFilter *filter; + char typebuf[NFD_MAX_STRLEN] = {0}; + const char *p_filterList = filterList; + char *p_typebuf = typebuf; + char filterName[NFD_MAX_STRLEN] = {0}; + + if ( !filterList || strlen(filterList) == 0 ) + return; + + filter = gtk_file_filter_new(); + while ( 1 ) + { + + if ( NFDi_IsFilterSegmentChar(*p_filterList) ) + { + char typebufWildcard[NFD_MAX_STRLEN]; + /* add another type to the filter */ + assert( strlen(typebuf) > 0 ); + assert( strlen(typebuf) < NFD_MAX_STRLEN-1 ); + + snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf ); + AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN ); + + gtk_file_filter_add_pattern( filter, typebufWildcard ); + + p_typebuf = typebuf; + memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN ); + } + + if ( *p_filterList == ';' || *p_filterList == '\0' ) + { + /* end of filter -- add it to the dialog */ + + gtk_file_filter_set_name( filter, filterName ); + gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter ); + + filterName[0] = '\0'; + + if ( *p_filterList == '\0' ) + break; + + filter = gtk_file_filter_new(); + } + + if ( !NFDi_IsFilterSegmentChar( *p_filterList ) ) + { + *p_typebuf = *p_filterList; + p_typebuf++; + } + + p_filterList++; + } + + /* always append a wildcard option to the end*/ + + filter = gtk_file_filter_new(); + gtk_file_filter_set_name( filter, "*.*" ); + gtk_file_filter_add_pattern( filter, "*" ); + gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter ); +} + +static void SetDefaultPath( GtkWidget *dialog, const char *defaultPath ) +{ + if ( !defaultPath || strlen(defaultPath) == 0 ) + return; + + /* GTK+ manual recommends not specifically setting the default path. + We do it anyway in order to be consistent across platforms. + + If consistency with the native OS is preferred, this is the line + to comment out. -ml */ + gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog), defaultPath ); +} + +static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet ) +{ + size_t bufSize = 0; + GSList *node; + nfdchar_t *p_buf; + size_t count = 0; + + assert(fileList); + assert(pathSet); + + pathSet->count = (size_t)g_slist_length( fileList ); + assert( pathSet->count > 0 ); + + pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); + if ( !pathSet->indices ) + { + return NFD_ERROR; + } + + /* count the total space needed for buf */ + for ( node = fileList; node; node = node->next ) + { + assert(node->data); + bufSize += strlen( (const gchar*)node->data ) + 1; + } + + pathSet->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufSize ); + + /* fill buf */ + p_buf = pathSet->buf; + for ( node = fileList; node; node = node->next ) + { + nfdchar_t *path = (nfdchar_t*)(node->data); + size_t byteLen = strlen(path)+1; + ptrdiff_t index; + + memcpy( p_buf, path, byteLen ); + g_free(node->data); + + index = p_buf - pathSet->buf; + assert( index >= 0 ); + pathSet->indices[count] = (size_t)index; + + p_buf += byteLen; + ++count; + } + + g_slist_free( fileList ); + + return NFD_OKAY; +} + +static void WaitForCleanup(void) +{ + while (gtk_events_pending()) + gtk_main_iteration(); +} + +/* public */ + +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + GtkWidget *dialog; + nfdresult_t result; + + if ( !gtk_init_check( NULL, NULL ) ) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Open File", + NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL ); + + /* Build the filter list */ + AddFiltersToDialog(dialog, filterList); + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + char *filename; + + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); + + { + size_t len = strlen(filename); + *outPath = NFDi_Malloc( len + 1 ); + memcpy( *outPath, filename, len + 1 ); + if ( !*outPath ) + { + g_free( filename ); + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + } + g_free( filename ); + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} + + +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ) +{ + GtkWidget *dialog; + nfdresult_t result; + + if ( !gtk_init_check( NULL, NULL ) ) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Open Files", + NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Open", GTK_RESPONSE_ACCEPT, + NULL ); + gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER(dialog), TRUE ); + + /* Build the filter list */ + AddFiltersToDialog(dialog, filterList); + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + GSList *fileList = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER(dialog) ); + if ( AllocPathSet( fileList, outPaths ) == NFD_ERROR ) + { + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} + +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ) +{ + GtkWidget *dialog; + nfdresult_t result; + + if ( !gtk_init_check( NULL, NULL ) ) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Save File", + NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Save", GTK_RESPONSE_ACCEPT, + NULL ); + gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE ); + + /* Build the filter list */ + AddFiltersToDialog(dialog, filterList); + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + char *filename; + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); + + { + size_t len = strlen(filename); + *outPath = NFDi_Malloc( len + 1 ); + memcpy( *outPath, filename, len + 1 ); + if ( !*outPath ) + { + g_free( filename ); + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + } + g_free(filename); + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} + +nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, + nfdchar_t **outPath) +{ + GtkWidget *dialog; + nfdresult_t result; + + if (!gtk_init_check(NULL, NULL)) + { + NFDi_SetError(INIT_FAIL_MSG); + return NFD_ERROR; + } + + dialog = gtk_file_chooser_dialog_new( "Select folder", + NULL, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, + "_Cancel", GTK_RESPONSE_CANCEL, + "_Select", GTK_RESPONSE_ACCEPT, + NULL ); + gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE ); + + + /* Set the default path */ + SetDefaultPath(dialog, defaultPath); + + result = NFD_CANCEL; + if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) + { + char *filename; + filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); + + { + size_t len = strlen(filename); + *outPath = NFDi_Malloc( len + 1 ); + memcpy( *outPath, filename, len + 1 ); + if ( !*outPath ) + { + g_free( filename ); + gtk_widget_destroy(dialog); + return NFD_ERROR; + } + } + g_free(filename); + + result = NFD_OKAY; + } + + WaitForCleanup(); + gtk_widget_destroy(dialog); + WaitForCleanup(); + + return result; +} + +#endif + +#ifdef IRON_WINDOWS #ifdef __MINGW32__ // Explicitly setting NTDDI version, this is necessary for the MinGW compiler @@ -25,8 +544,6 @@ #include #include #include -#include "nfd_common.h" - #define COM_INITFLAGS ::COINIT_APARTMENTTHREADED | ::COINIT_DISABLE_OLE1DDE @@ -58,10 +575,10 @@ static void COMUninit(HRESULT coResult) // allocs the space in outPath -- call free() static void CopyWCharToNFDChar( const wchar_t *inStr, nfdchar_t **outStr ) { - int inStrCharacterCount = static_cast(wcslen(inStr)); + int inStrCharacterCount = static_cast(wcslen(inStr)); int bytesNeeded = WideCharToMultiByte( CP_UTF8, 0, inStr, inStrCharacterCount, - NULL, 0, NULL, NULL ); + NULL, 0, NULL, NULL ); assert( bytesNeeded ); bytesNeeded += 1; @@ -109,14 +626,14 @@ static void CopyNFDCharToWChar( const nfdchar_t *inStr, wchar_t **outStr ) int inStrByteCount = static_cast(strlen(inStr)); int charsNeeded = MultiByteToWideChar(CP_UTF8, 0, inStr, inStrByteCount, - NULL, 0 ); + NULL, 0 ); assert( charsNeeded ); assert( !*outStr ); charsNeeded += 1; // terminator - - *outStr = (wchar_t*)NFDi_Malloc( charsNeeded * sizeof(wchar_t) ); + + *outStr = (wchar_t*)NFDi_Malloc( charsNeeded * sizeof(wchar_t) ); if ( !*outStr ) - return; + return; int ret = MultiByteToWideChar(CP_UTF8, 0, inStr, inStrByteCount, @@ -131,13 +648,12 @@ static void CopyNFDCharToWChar( const nfdchar_t *inStr, wchar_t **outStr ) #endif } - /* ext is in format "jpg", no wildcards or separators */ static int AppendExtensionToSpecBuf( const char *ext, char *specBuf, size_t specBufLen ) { const char SEP[] = ";"; assert( specBufLen > strlen(ext)+3 ); - + if ( strlen(specBuf) > 0 ) { strncat( specBuf, SEP, specBufLen - strlen(specBuf) - 1 ); @@ -148,7 +664,7 @@ static int AppendExtensionToSpecBuf( const char *ext, char *specBuf, size_t spec int bytesWritten = sprintf_s( extWildcard, NFD_MAX_STRLEN, "*.%s", ext ); assert( bytesWritten == (int)(strlen(ext)+2) ); _NFD_UNUSED(bytesWritten); - + strncat( specBuf, extWildcard, specBufLen - strlen(specBuf) - 1 ); return NFD_OKAY; @@ -168,7 +684,7 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char { if ( *p_filterList == ';' ) ++filterCount; - } + } assert(filterCount); if ( !filterCount ) @@ -196,12 +712,12 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char char specbuf[NFD_MAX_STRLEN] = {0}; /* one per semicolon */ - while ( 1 ) + while ( 1 ) { if ( NFDi_IsFilterSegmentChar(*p_filterList) ) { /* append a type to the specbuf (pending filter) */ - AppendExtensionToSpecBuf( typebuf, specbuf, NFD_MAX_STRLEN ); + AppendExtensionToSpecBuf( typebuf, specbuf, NFD_MAX_STRLEN ); p_typebuf = typebuf; memset( typebuf, 0, sizeof(char)*NFD_MAX_STRLEN ); @@ -210,10 +726,10 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char if ( *p_filterList == ';' || *p_filterList == '\0' ) { /* end of filter -- add it to specList */ - + CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszName ); CopyNFDCharToWChar( specbuf, (wchar_t**)&specList[specIdx].pszSpec ); - + memset( specbuf, 0, sizeof(char)*NFD_MAX_STRLEN ); ++specIdx; if ( specIdx == filterCount ) @@ -232,7 +748,7 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char /* Add wildcard */ specList[specIdx].pszSpec = WILDCARD; specList[specIdx].pszName = WILDCARD; - + fileOpenDialog->SetFileTypes( filterCount+1, specList ); /* free speclist */ @@ -240,7 +756,7 @@ static nfdresult_t AddFiltersToDialog( ::IFileDialog *fileOpenDialog, const char { NFDi_Free( (void*)specList[i].pszSpec ); } - NFDi_Free( specList ); + NFDi_Free( specList ); return NFD_OKAY; } @@ -251,7 +767,7 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path assert(shellItems); assert(pathSet); - + // How many items in shellItems? DWORD numShellItems; HRESULT result = shellItems->GetCount(&numShellItems); @@ -298,7 +814,7 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path // Calculate length of name with UTF-8 encoding bufSize += GetUTF8ByteCountForWChar( name ); - + CoTaskMemFree(name); } @@ -339,14 +855,13 @@ static nfdresult_t AllocPathSet( IShellItemArray *shellItems, nfdpathset_t *path ptrdiff_t index = p_buf - pathSet->buf; assert( index >= 0 ); pathSet->indices[i] = static_cast(index); - - p_buf += bytesWritten; + + p_buf += bytesWritten; } - + return NFD_OKAY; } - static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath ) { if ( !defaultPath || strlen(defaultPath) == 0 ) @@ -371,39 +886,38 @@ static nfdresult_t SetDefaultPath( IFileDialog *dialog, const char *defaultPath NFDi_Free( defaultPathW ); return NFD_ERROR; } - + // Could also call SetDefaultFolder(), but this guarantees defaultPath -- more consistency across API. dialog->SetFolder( folder ); NFDi_Free( defaultPathW ); folder->Release(); - + return NFD_OKAY; } /* public */ - nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, nfdchar_t **outPath ) { nfdresult_t nfdResult = NFD_ERROR; - + HRESULT coResult = COMInit(); if (!COMIsInitialized(coResult)) - { + { NFDi_SetError("Could not initialize COM."); return nfdResult; } // Create dialog - ::IFileOpenDialog *fileOpenDialog(NULL); + ::IFileOpenDialog *fileOpenDialog(NULL); HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, CLSCTX_ALL, ::IID_IFileOpenDialog, reinterpret_cast(&fileOpenDialog) ); - + if ( !SUCCEEDED(result) ) { NFDi_SetError("Could not create dialog."); @@ -420,7 +934,7 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, if ( !SetDefaultPath( fileOpenDialog, defaultPath ) ) { goto end; - } + } // Show the dialog. result = fileOpenDialog->Show(NULL); @@ -470,7 +984,7 @@ end: fileOpenDialog->Release(); COMUninit(coResult); - + return nfdResult; } @@ -484,16 +998,16 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, HRESULT coResult = COMInit(); if (!COMIsInitialized(coResult)) { - NFDi_SetError("Could not initialize COM."); + NFDi_SetError("Could not initialize COM."); return nfdResult; } // Create dialog - ::IFileOpenDialog *fileOpenDialog(NULL); + ::IFileOpenDialog *fileOpenDialog(NULL); HRESULT result = ::CoCreateInstance(::CLSID_FileOpenDialog, NULL, CLSCTX_ALL, ::IID_IFileOpenDialog, reinterpret_cast(&fileOpenDialog) ); - + if ( !SUCCEEDED(result) ) { fileOpenDialog = NULL; @@ -527,7 +1041,7 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, NFDi_SetError("Could not set options."); goto end; } - + // Show the dialog. result = fileOpenDialog->Show(NULL); if ( SUCCEEDED(result) ) @@ -539,7 +1053,7 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, NFDi_SetError("Could not get shell items."); goto end; } - + if ( AllocPathSet( shellItems, outPaths ) == NFD_ERROR ) { shellItems->Release(); @@ -564,7 +1078,7 @@ end: fileOpenDialog->Release(); COMUninit(coResult); - + return nfdResult; } @@ -578,11 +1092,11 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, if (!COMIsInitialized(coResult)) { NFDi_SetError("Could not initialize COM."); - return nfdResult; + return nfdResult; } - + // Create dialog - ::IFileSaveDialog *fileSaveDialog(NULL); + ::IFileSaveDialog *fileSaveDialog(NULL); HRESULT result = ::CoCreateInstance(::CLSID_FileSaveDialog, NULL, CLSCTX_ALL, ::IID_IFileSaveDialog, reinterpret_cast(&fileSaveDialog) ); @@ -648,18 +1162,16 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, NFDi_SetError("File dialog box show failed."); nfdResult = NFD_ERROR; } - + end: if ( fileSaveDialog ) fileSaveDialog->Release(); COMUninit(coResult); - + return nfdResult; } - - nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, nfdchar_t **outPath) { @@ -680,7 +1192,7 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, CLSCTX_ALL, IID_PPV_ARGS(&fileDialog)); if ( !SUCCEEDED(result) ) - { + { NFDi_SetError("CoCreateInstance for CLSID_FileOpenDialog failed."); goto end; } @@ -725,7 +1237,7 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, result = shellItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &path); if ( !SUCCEEDED(result) ) { - NFDi_SetError("GetDisplayName for IShellItem failed."); + NFDi_SetError("GetDisplayName for IShellItem failed."); shellItem->Release(); goto end; } @@ -760,3 +1272,5 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, return nfdResult; } + +#endif diff --git a/base/sources/libs/nfd.h b/base/sources/libs/nfd.h new file mode 100644 index 00000000..b9e6302f --- /dev/null +++ b/base/sources/libs/nfd.h @@ -0,0 +1,64 @@ +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// https://github.com/mlabbe/nativefiledialog + +#pragma once + +#include +#include + +typedef char nfdchar_t; + +typedef struct { + nfdchar_t *buf; + size_t *indices; /* byte offsets into buf */ + size_t count; /* number of indices into buf */ +}nfdpathset_t; + +typedef enum { + NFD_ERROR, /* programmatic error */ + NFD_OKAY, /* user pressed okay, or successful return */ + NFD_CANCEL /* user pressed cancel */ +}nfdresult_t; + +nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ); + +nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdpathset_t *outPaths ); + +nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, + const nfdchar_t *defaultPath, + nfdchar_t **outPath ); + +nfdresult_t NFD_PickFolder( const nfdchar_t *defaultPath, + nfdchar_t **outPath); + +const char *NFD_GetError( void ); +size_t NFD_PathSet_GetCount( const nfdpathset_t *pathSet ); +nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathSet, size_t index ); +void NFD_PathSet_Free( nfdpathset_t *pathSet ); + +#define NFD_MAX_STRLEN 256 +#define _NFD_UNUSED(x) ((void)x) +#define NFD_UTF8_BOM "\xEF\xBB\xBF" + +void *NFDi_Malloc( size_t bytes ); +void NFDi_Free( void *ptr ); +void NFDi_SetError( const char *msg ); +int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); +int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ); +int NFDi_IsFilterSegmentChar( char ch ); diff --git a/base/sources/libs/nfd/nfd_cocoa.m b/base/sources/libs/nfd.m similarity index 81% rename from base/sources/libs/nfd/nfd_cocoa.m rename to base/sources/libs/nfd.m index 4fb06419..4da1862b 100644 --- a/base/sources/libs/nfd/nfd_cocoa.m +++ b/base/sources/libs/nfd.m @@ -1,21 +1,28 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs - */ +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// https://github.com/mlabbe/nativefiledialog #include #include "nfd.h" -#include "nfd_common.h" -static NSArray *BuildAllowedFileTypes( const char *filterList ) -{ +static NSArray *BuildAllowedFileTypes( const char *filterList ) { // Commas and semicolons are the same thing on this platform NSMutableArray *buildFilterList = [[NSMutableArray alloc] init]; char typebuf[NFD_MAX_STRLEN] = {0}; - + size_t filterListLen = strlen(filterList); char *p_typebuf = typebuf; for ( size_t i = 0; i < filterListLen+1; ++i ) @@ -45,8 +52,7 @@ static NSArray *BuildAllowedFileTypes( const char *filterList ) return returnArray; } -static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList ) -{ +static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList ) { if ( !filterList || strlen(filterList) == 0 ) return; @@ -57,26 +63,23 @@ static void AddFilterListToDialog( NSSavePanel *dialog, const char *filterList ) } } -static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath ) -{ +static void SetDefaultPath( NSSavePanel *dialog, const nfdchar_t *defaultPath ) { if ( !defaultPath || strlen(defaultPath) == 0 ) return; NSString *defaultPathString = [NSString stringWithUTF8String: defaultPath]; NSURL *url = [NSURL fileURLWithPath:defaultPathString isDirectory:YES]; - [dialog setDirectoryURL:url]; + [dialog setDirectoryURL:url]; } - /* fixme: pathset should be pathSet */ -static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) -{ +static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) { assert(pathset); assert([urls count]); pathset->count = (size_t)[urls count]; pathset->indices = NFDi_Malloc( sizeof(size_t)*pathset->count ); - if ( !pathset->indices ) + if ( !pathset->indices ) { return NFD_ERROR; } @@ -116,16 +119,12 @@ static nfdresult_t AllocPathSet( NSArray *urls, nfdpathset_t *pathset ) return NFD_OKAY; } -/* public */ - - nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ + nfdchar_t **outPath ) { // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; + NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; NSOpenPanel *dialog = [NSOpenPanel openPanel]; [dialog setAllowsMultipleSelection:NO]; @@ -148,7 +147,7 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, if ( !*outPath ) { // [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ @@ -160,14 +159,12 @@ nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, return nfdResult; } - nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ) -{ + nfdpathset_t *outPaths ) { // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; - + NSOpenPanel *dialog = [NSOpenPanel openPanel]; [dialog setAllowsMultipleSelection:YES]; @@ -176,7 +173,7 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, // Set the starting directory SetDefaultPath(dialog, defaultPath); - + nfdresult_t nfdResult = NFD_CANCEL; if ( [dialog runModal] == NSModalResponseOK ) { @@ -185,14 +182,14 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, if ( [urls count] == 0 ) { // [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_CANCEL; } if ( AllocPathSet( urls, outPaths ) == NFD_ERROR ) { // [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } @@ -200,21 +197,19 @@ nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, } // [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; + [keyWindow makeKeyAndOrderFront:nil]; return nfdResult; } - nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ + nfdchar_t **outPath ) { // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; - + NSSavePanel *dialog = [NSSavePanel savePanel]; [dialog setExtensionHidden:NO]; - + // Build the filter list. AddFilterListToDialog(dialog, filterList); @@ -228,12 +223,12 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, const char *utf8Path = [[url path] UTF8String]; size_t byteLen = [url.path lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1; - + *outPath = NFDi_Malloc( byteLen ); if ( !*outPath ) { // [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } memcpy( *outPath, utf8Path, byteLen ); @@ -246,8 +241,7 @@ nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, } nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, - nfdchar_t **outPath) -{ + nfdchar_t **outPath) { // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *keyWindow = [[NSApplication sharedApplication] keyWindow]; @@ -273,7 +267,7 @@ nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, if ( !*outPath ) { // [pool release]; - [keyWindow makeKeyAndOrderFront:nil]; + [keyWindow makeKeyAndOrderFront:nil]; return NFD_ERROR; } memcpy( *outPath, utf8Path, len+1 ); /* copy null term */ diff --git a/base/sources/libs/nfd/LICENSE b/base/sources/libs/nfd/LICENSE deleted file mode 100644 index 3ab103c5..00000000 --- a/base/sources/libs/nfd/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. -3. This notice may not be removed or altered from any source distribution. - diff --git a/base/sources/libs/nfd/common.h b/base/sources/libs/nfd/common.h deleted file mode 100644 index 7745d323..00000000 --- a/base/sources/libs/nfd/common.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - Native File Dialog - - Internal, common across platforms - - http://www.frogtoss.com/labs - */ - - -#ifndef _NFD_COMMON_H -#define _NFD_COMMON_H - -#define NFD_MAX_STRLEN 256 -#define _NFD_UNUSED(x) ((void)x) - -void *NFDi_Malloc( size_t bytes ); -void NFDi_Free( void *ptr ); -void NFDi_SetError( const char *msg ); -void NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); - -#endif diff --git a/base/sources/libs/nfd/nfd.h b/base/sources/libs/nfd/nfd.h deleted file mode 100644 index 74c92743..00000000 --- a/base/sources/libs/nfd/nfd.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - Native File Dialog - - User API - - http://www.frogtoss.com/labs - */ - - -#ifndef _NFD_H -#define _NFD_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* denotes UTF-8 char */ -typedef char nfdchar_t; - -/* opaque data structure -- see NFD_PathSet_* */ -typedef struct { - nfdchar_t *buf; - size_t *indices; /* byte offsets into buf */ - size_t count; /* number of indices into buf */ -}nfdpathset_t; - -typedef enum { - NFD_ERROR, /* programmatic error */ - NFD_OKAY, /* user pressed okay, or successful return */ - NFD_CANCEL /* user pressed cancel */ -}nfdresult_t; - - -/* nfd_.c */ - -/* single file open dialog */ -nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ); - -/* multiple file open dialog */ -nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ); - -/* save dialog */ -nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ); - - -/* select folder dialog */ -nfdresult_t NFD_PickFolder( const nfdchar_t *defaultPath, - nfdchar_t **outPath); - -/* nfd_common.c */ - -/* get last error -- set when nfdresult_t returns NFD_ERROR */ -const char *NFD_GetError( void ); -/* get the number of entries stored in pathSet */ -size_t NFD_PathSet_GetCount( const nfdpathset_t *pathSet ); -/* Get the UTF-8 path at offset index */ -nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathSet, size_t index ); -/* Free the pathSet */ -void NFD_PathSet_Free( nfdpathset_t *pathSet ); - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/base/sources/libs/nfd/nfd_common.c b/base/sources/libs/nfd/nfd_common.c deleted file mode 100644 index 55517f5d..00000000 --- a/base/sources/libs/nfd/nfd_common.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs - */ - -#include -#include -#include -#include "nfd_common.h" - -static char g_errorstr[NFD_MAX_STRLEN] = {0}; - -/* public routines */ - -const char *NFD_GetError( void ) -{ - return g_errorstr; -} - -size_t NFD_PathSet_GetCount( const nfdpathset_t *pathset ) -{ - assert(pathset); - return pathset->count; -} - -nfdchar_t *NFD_PathSet_GetPath( const nfdpathset_t *pathset, size_t num ) -{ - assert(pathset); - assert(num < pathset->count); - - return pathset->buf + pathset->indices[num]; -} - -void NFD_PathSet_Free( nfdpathset_t *pathset ) -{ - assert(pathset); - NFDi_Free( pathset->indices ); - NFDi_Free( pathset->buf ); -} - -/* internal routines */ - -void *NFDi_Malloc( size_t bytes ) -{ - void *ptr = malloc(bytes); - if ( !ptr ) - NFDi_SetError("NFDi_Malloc failed."); - - return ptr; -} - -void NFDi_Free( void *ptr ) -{ - assert(ptr); - free(ptr); -} - -void NFDi_SetError( const char *msg ) -{ - int bTruncate = NFDi_SafeStrncpy( g_errorstr, msg, NFD_MAX_STRLEN ); - assert( !bTruncate ); _NFD_UNUSED(bTruncate); -} - - -int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ) -{ - size_t n = maxCopy; - char *d = dst; - - assert( src ); - assert( dst ); - - while ( n > 0 && *src != '\0' ) - { - *d++ = *src++; - --n; - } - - /* Truncation case - - terminate string and return true */ - if ( n == 0 ) - { - dst[maxCopy-1] = '\0'; - return 1; - } - - /* No truncation. Append a single NULL and return. */ - *d = '\0'; - return 0; -} - - -/* adapted from microutf8 */ -int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ) -{ - /* This function doesn't properly check validity of UTF-8 character - sequence, it is supposed to use only with valid UTF-8 strings. */ - - int32_t character_count = 0; - int32_t i = 0; /* Counter used to iterate over string. */ - nfdchar_t maybe_bom[4]; - - /* If there is UTF-8 BOM ignore it. */ - if (strlen(str) > 2) - { - strncpy(maybe_bom, str, 3); - maybe_bom[3] = 0; - if (strcmp(maybe_bom, (nfdchar_t*)NFD_UTF8_BOM) == 0) - i += 3; - } - - while(str[i]) - { - if (str[i] >> 7 == 0) - { - /* If bit pattern begins with 0 we have ascii character. */ - ++character_count; - } - else if (str[i] >> 6 == 3) - { - /* If bit pattern begins with 11 it is beginning of UTF-8 byte sequence. */ - ++character_count; - } - else if (str[i] >> 6 == 2) - ; /* If bit pattern begins with 10 it is middle of utf-8 byte sequence. */ - else - { - /* In any other case this is not valid UTF-8. */ - return -1; - } - ++i; - } - - return character_count; -} - -int NFDi_IsFilterSegmentChar( char ch ) -{ - return (ch==','||ch==';'||ch=='\0'); -} - diff --git a/base/sources/libs/nfd/nfd_common.h b/base/sources/libs/nfd/nfd_common.h deleted file mode 100644 index 1a9ab162..00000000 --- a/base/sources/libs/nfd/nfd_common.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Native File Dialog - - Internal, common across platforms - - http://www.frogtoss.com/labs - */ - - -#ifndef _NFD_COMMON_H -#define _NFD_COMMON_H - -#include "nfd.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define NFD_MAX_STRLEN 256 -#define _NFD_UNUSED(x) ((void)x) - -#define NFD_UTF8_BOM "\xEF\xBB\xBF" - - -void *NFDi_Malloc( size_t bytes ); -void NFDi_Free( void *ptr ); -void NFDi_SetError( const char *msg ); -int NFDi_SafeStrncpy( char *dst, const char *src, size_t maxCopy ); -int32_t NFDi_UTF8_Strlen( const nfdchar_t *str ); -int NFDi_IsFilterSegmentChar( char ch ); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/base/sources/libs/nfd/nfd_gtk.c b/base/sources/libs/nfd/nfd_gtk.c deleted file mode 100644 index 6fa2123a..00000000 --- a/base/sources/libs/nfd/nfd_gtk.c +++ /dev/null @@ -1,379 +0,0 @@ -/* - Native File Dialog - - http://www.frogtoss.com/labs -*/ - -#include -#include -#include -#include -#include "nfd.h" -#include "nfd_common.h" - - -const char INIT_FAIL_MSG[] = "gtk_init_check failed to initilaize GTK+"; - - -static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize ) -{ - const char SEP[] = ", "; - - size_t len = strlen(filterName); - if ( len != 0 ) - { - strncat( filterName, SEP, bufsize - len - 1 ); - len += strlen(SEP); - } - - strncat( filterName, typebuf, bufsize - len - 1 ); -} - -static void AddFiltersToDialog( GtkWidget *dialog, const char *filterList ) -{ - GtkFileFilter *filter; - char typebuf[NFD_MAX_STRLEN] = {0}; - const char *p_filterList = filterList; - char *p_typebuf = typebuf; - char filterName[NFD_MAX_STRLEN] = {0}; - - if ( !filterList || strlen(filterList) == 0 ) - return; - - filter = gtk_file_filter_new(); - while ( 1 ) - { - - if ( NFDi_IsFilterSegmentChar(*p_filterList) ) - { - char typebufWildcard[NFD_MAX_STRLEN]; - /* add another type to the filter */ - assert( strlen(typebuf) > 0 ); - assert( strlen(typebuf) < NFD_MAX_STRLEN-1 ); - - snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf ); - AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN ); - - gtk_file_filter_add_pattern( filter, typebufWildcard ); - - p_typebuf = typebuf; - memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN ); - } - - if ( *p_filterList == ';' || *p_filterList == '\0' ) - { - /* end of filter -- add it to the dialog */ - - gtk_file_filter_set_name( filter, filterName ); - gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter ); - - filterName[0] = '\0'; - - if ( *p_filterList == '\0' ) - break; - - filter = gtk_file_filter_new(); - } - - if ( !NFDi_IsFilterSegmentChar( *p_filterList ) ) - { - *p_typebuf = *p_filterList; - p_typebuf++; - } - - p_filterList++; - } - - /* always append a wildcard option to the end*/ - - filter = gtk_file_filter_new(); - gtk_file_filter_set_name( filter, "*.*" ); - gtk_file_filter_add_pattern( filter, "*" ); - gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(dialog), filter ); -} - -static void SetDefaultPath( GtkWidget *dialog, const char *defaultPath ) -{ - if ( !defaultPath || strlen(defaultPath) == 0 ) - return; - - /* GTK+ manual recommends not specifically setting the default path. - We do it anyway in order to be consistent across platforms. - - If consistency with the native OS is preferred, this is the line - to comment out. -ml */ - gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog), defaultPath ); -} - -static nfdresult_t AllocPathSet( GSList *fileList, nfdpathset_t *pathSet ) -{ - size_t bufSize = 0; - GSList *node; - nfdchar_t *p_buf; - size_t count = 0; - - assert(fileList); - assert(pathSet); - - pathSet->count = (size_t)g_slist_length( fileList ); - assert( pathSet->count > 0 ); - - pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count ); - if ( !pathSet->indices ) - { - return NFD_ERROR; - } - - /* count the total space needed for buf */ - for ( node = fileList; node; node = node->next ) - { - assert(node->data); - bufSize += strlen( (const gchar*)node->data ) + 1; - } - - pathSet->buf = NFDi_Malloc( sizeof(nfdchar_t) * bufSize ); - - /* fill buf */ - p_buf = pathSet->buf; - for ( node = fileList; node; node = node->next ) - { - nfdchar_t *path = (nfdchar_t*)(node->data); - size_t byteLen = strlen(path)+1; - ptrdiff_t index; - - memcpy( p_buf, path, byteLen ); - g_free(node->data); - - index = p_buf - pathSet->buf; - assert( index >= 0 ); - pathSet->indices[count] = (size_t)index; - - p_buf += byteLen; - ++count; - } - - g_slist_free( fileList ); - - return NFD_OKAY; -} - -static void WaitForCleanup(void) -{ - while (gtk_events_pending()) - gtk_main_iteration(); -} - -/* public */ - -nfdresult_t NFD_OpenDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - GtkWidget *dialog; - nfdresult_t result; - - if ( !gtk_init_check( NULL, NULL ) ) - { - NFDi_SetError(INIT_FAIL_MSG); - return NFD_ERROR; - } - - dialog = gtk_file_chooser_dialog_new( "Open File", - NULL, - GTK_FILE_CHOOSER_ACTION_OPEN, - "_Cancel", GTK_RESPONSE_CANCEL, - "_Open", GTK_RESPONSE_ACCEPT, - NULL ); - - /* Build the filter list */ - AddFiltersToDialog(dialog, filterList); - - /* Set the default path */ - SetDefaultPath(dialog, defaultPath); - - result = NFD_CANCEL; - if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) - { - char *filename; - - filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); - - { - size_t len = strlen(filename); - *outPath = NFDi_Malloc( len + 1 ); - memcpy( *outPath, filename, len + 1 ); - if ( !*outPath ) - { - g_free( filename ); - gtk_widget_destroy(dialog); - return NFD_ERROR; - } - } - g_free( filename ); - - result = NFD_OKAY; - } - - WaitForCleanup(); - gtk_widget_destroy(dialog); - WaitForCleanup(); - - return result; -} - - -nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdpathset_t *outPaths ) -{ - GtkWidget *dialog; - nfdresult_t result; - - if ( !gtk_init_check( NULL, NULL ) ) - { - NFDi_SetError(INIT_FAIL_MSG); - return NFD_ERROR; - } - - dialog = gtk_file_chooser_dialog_new( "Open Files", - NULL, - GTK_FILE_CHOOSER_ACTION_OPEN, - "_Cancel", GTK_RESPONSE_CANCEL, - "_Open", GTK_RESPONSE_ACCEPT, - NULL ); - gtk_file_chooser_set_select_multiple( GTK_FILE_CHOOSER(dialog), TRUE ); - - /* Build the filter list */ - AddFiltersToDialog(dialog, filterList); - - /* Set the default path */ - SetDefaultPath(dialog, defaultPath); - - result = NFD_CANCEL; - if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) - { - GSList *fileList = gtk_file_chooser_get_filenames( GTK_FILE_CHOOSER(dialog) ); - if ( AllocPathSet( fileList, outPaths ) == NFD_ERROR ) - { - gtk_widget_destroy(dialog); - return NFD_ERROR; - } - - result = NFD_OKAY; - } - - WaitForCleanup(); - gtk_widget_destroy(dialog); - WaitForCleanup(); - - return result; -} - -nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList, - const nfdchar_t *defaultPath, - nfdchar_t **outPath ) -{ - GtkWidget *dialog; - nfdresult_t result; - - if ( !gtk_init_check( NULL, NULL ) ) - { - NFDi_SetError(INIT_FAIL_MSG); - return NFD_ERROR; - } - - dialog = gtk_file_chooser_dialog_new( "Save File", - NULL, - GTK_FILE_CHOOSER_ACTION_SAVE, - "_Cancel", GTK_RESPONSE_CANCEL, - "_Save", GTK_RESPONSE_ACCEPT, - NULL ); - gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE ); - - /* Build the filter list */ - AddFiltersToDialog(dialog, filterList); - - /* Set the default path */ - SetDefaultPath(dialog, defaultPath); - - result = NFD_CANCEL; - if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) - { - char *filename; - filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); - - { - size_t len = strlen(filename); - *outPath = NFDi_Malloc( len + 1 ); - memcpy( *outPath, filename, len + 1 ); - if ( !*outPath ) - { - g_free( filename ); - gtk_widget_destroy(dialog); - return NFD_ERROR; - } - } - g_free(filename); - - result = NFD_OKAY; - } - - WaitForCleanup(); - gtk_widget_destroy(dialog); - WaitForCleanup(); - - return result; -} - -nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath, - nfdchar_t **outPath) -{ - GtkWidget *dialog; - nfdresult_t result; - - if (!gtk_init_check(NULL, NULL)) - { - NFDi_SetError(INIT_FAIL_MSG); - return NFD_ERROR; - } - - dialog = gtk_file_chooser_dialog_new( "Select folder", - NULL, - GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, - "_Cancel", GTK_RESPONSE_CANCEL, - "_Select", GTK_RESPONSE_ACCEPT, - NULL ); - gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(dialog), TRUE ); - - - /* Set the default path */ - SetDefaultPath(dialog, defaultPath); - - result = NFD_CANCEL; - if ( gtk_dialog_run( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) - { - char *filename; - filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog) ); - - { - size_t len = strlen(filename); - *outPath = NFDi_Malloc( len + 1 ); - memcpy( *outPath, filename, len + 1 ); - if ( !*outPath ) - { - g_free( filename ); - gtk_widget_destroy(dialog); - return NFD_ERROR; - } - } - g_free(filename); - - result = NFD_OKAY; - } - - WaitForCleanup(); - gtk_widget_destroy(dialog); - WaitForCleanup(); - - return result; -} diff --git a/base/sources/libs/nfd/simple_exec.h b/base/sources/libs/nfd/simple_exec.h deleted file mode 100644 index 6308dfe0..00000000 --- a/base/sources/libs/nfd/simple_exec.h +++ /dev/null @@ -1,218 +0,0 @@ -// copied from: https://github.com/wheybags/simple_exec/blob/5a74c507c4ce1b2bb166177ead4cca7cfa23cb35/simple_exec.h - -// simple_exec.h, single header library to run external programs + retrieve their status code and output (unix only for now) -// -// do this: -// #define SIMPLE_EXEC_IMPLEMENTATION -// before you include this file in *one* C or C++ file to create the implementation. -// i.e. it should look like this: -// #define SIMPLE_EXEC_IMPLEMENTATION -// #include "simple_exec.h" - -#ifndef SIMPLE_EXEC_H -#define SIMPLE_EXEC_H - -int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...); -int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs); - -#endif // SIMPLE_EXEC_H - -#ifdef SIMPLE_EXEC_IMPLEMENTATION - -#include -#include -#include -#include -#include -#include -#include -#include - -#define release_assert(exp) { if (!(exp)) { abort(); } } - -enum PIPE_FILE_DESCRIPTORS -{ - READ_FD = 0, - WRITE_FD = 1 -}; - -enum RUN_COMMAND_ERROR -{ - COMMAND_RAN_OK = 0, - COMMAND_NOT_FOUND = 1 -}; - -int runCommandArray(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* const* allArgs) -{ - // adapted from: https://stackoverflow.com/a/479103 - - int bufferSize = 256; - char buffer[bufferSize + 1]; - - int dataReadFromChildDefaultSize = bufferSize * 5; - int dataReadFromChildSize = dataReadFromChildDefaultSize; - int dataReadFromChildUsed = 0; - char* dataReadFromChild = (char*)malloc(dataReadFromChildSize); - - - int parentToChild[2]; - release_assert(pipe(parentToChild) == 0); - - int childToParent[2]; - release_assert(pipe(childToParent) == 0); - - int errPipe[2]; - release_assert(pipe(errPipe) == 0); - - pid_t pid; - switch( pid = fork() ) - { - case -1: - { - release_assert(0 && "Fork failed"); - break; - } - - case 0: // child - { - release_assert(dup2(parentToChild[READ_FD ], STDIN_FILENO ) != -1); - release_assert(dup2(childToParent[WRITE_FD], STDOUT_FILENO) != -1); - - if(includeStdErr) - { - release_assert(dup2(childToParent[WRITE_FD], STDERR_FILENO) != -1); - } - else - { - int devNull = open("/dev/null", O_WRONLY); - release_assert(dup2(devNull, STDERR_FILENO) != -1); - } - - // unused - release_assert(close(parentToChild[WRITE_FD]) == 0); - release_assert(close(childToParent[READ_FD ]) == 0); - release_assert(close(errPipe[READ_FD]) == 0); - - const char* command = allArgs[0]; - execvp(command, allArgs); - - char err = 1; - ssize_t result = write(errPipe[WRITE_FD], &err, 1); - release_assert(result != -1); - - close(errPipe[WRITE_FD]); - close(parentToChild[READ_FD]); - close(childToParent[WRITE_FD]); - - exit(0); - } - - - default: // parent - { - // unused - release_assert(close(parentToChild[READ_FD]) == 0); - release_assert(close(childToParent[WRITE_FD]) == 0); - release_assert(close(errPipe[WRITE_FD]) == 0); - - while(1) - { - ssize_t bytesRead = 0; - switch(bytesRead = read(childToParent[READ_FD], buffer, bufferSize)) - { - case 0: // End-of-File, or non-blocking read. - { - int status = 0; - release_assert(waitpid(pid, &status, 0) == pid); - - // done with these now - release_assert(close(parentToChild[WRITE_FD]) == 0); - release_assert(close(childToParent[READ_FD]) == 0); - - char errChar = 0; - ssize_t result = read(errPipe[READ_FD], &errChar, 1); - release_assert(result != -1); - close(errPipe[READ_FD]); - - if(errChar) - { - free(dataReadFromChild); - return COMMAND_NOT_FOUND; - } - - // free any un-needed memory with realloc + add a null terminator for convenience - dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildUsed + 1); - dataReadFromChild[dataReadFromChildUsed] = '\0'; - - if(stdOut != NULL) - *stdOut = dataReadFromChild; - else - free(dataReadFromChild); - - if(stdOutByteCount != NULL) - *stdOutByteCount = dataReadFromChildUsed; - if(returnCode != NULL) - *returnCode = WEXITSTATUS(status); - - return COMMAND_RAN_OK; - } - case -1: - { - release_assert(0 && "read() failed"); - break; - } - - default: - { - if(dataReadFromChildUsed + bytesRead + 1 >= dataReadFromChildSize) - { - dataReadFromChildSize += dataReadFromChildDefaultSize; - dataReadFromChild = (char*)realloc(dataReadFromChild, dataReadFromChildSize); - } - - memcpy(dataReadFromChild + dataReadFromChildUsed, buffer, bytesRead); - dataReadFromChildUsed += bytesRead; - break; - } - } - } - } - } -} - -int runCommand(char** stdOut, int* stdOutByteCount, int* returnCode, int includeStdErr, char* command, ...) -{ - va_list vl; - va_start(vl, command); - - char* currArg = NULL; - - int allArgsInitialSize = 16; - int allArgsSize = allArgsInitialSize; - char** allArgs = (char**)malloc(sizeof(char*) * allArgsSize); - allArgs[0] = command; - - int i = 1; - do - { - currArg = va_arg(vl, char*); - allArgs[i] = currArg; - - i++; - - if(i >= allArgsSize) - { - allArgsSize += allArgsInitialSize; - allArgs = (char**)realloc(allArgs, sizeof(char*) * allArgsSize); - } - - } while(currArg != NULL); - - va_end(vl); - - int retval = runCommandArray(stdOut, stdOutByteCount, returnCode, includeStdErr, allArgs); - free(allArgs); - return retval; -} - -#endif //SIMPLE_EXEC_IMPLEMENTATION diff --git a/base/sources/ts/physics_body.ts b/base/sources/ts/physics_body.ts index 364a75aa..d9fb399e 100644 --- a/base/sources/ts/physics_body.ts +++ b/base/sources/ts/physics_body.ts @@ -1,7 +1,7 @@ ///if arm_physics -///include "../libs/asim/asim.h" +///include "../libs/asim.h" declare function asim_body_create(shape: i32, mass: f32, dimx: f32, dimy: f32, dimz: f32, x: f32, y: f32, z: f32, triangles: f32[]): any; declare function asim_body_apply_impulse(body: any, x: f32, y: f32, z: f32): void; diff --git a/base/sources/ts/physics_world.ts b/base/sources/ts/physics_world.ts index 3200b165..084e304c 100644 --- a/base/sources/ts/physics_world.ts +++ b/base/sources/ts/physics_world.ts @@ -1,7 +1,7 @@ ///if arm_physics -///include "../libs/asim/asim.h" +///include "../libs/asim.h" declare function asim_world_create(): void; declare function asim_world_destroy(): void; diff --git a/base/tests/fall/project.js b/base/tests/fall/project.js index 6017b167..7f3bf8a2 100644 --- a/base/tests/fall/project.js +++ b/base/tests/fall/project.js @@ -6,7 +6,7 @@ flags.lite = true; let project = new Project("test"); project.add_project("../../"); project.add_tsfiles("sources"); -project.add_cfiles("../../sources/libs/asim/asim.c"); +project.add_cfiles("../../sources/libs/asim.c"); project.add_tsfiles("../../sources/ts/iron"); project.add_shaders("../../shaders/draw/*.glsl"); project.add_shaders("shaders/*.glsl"); diff --git a/base/tests/fall/sources/main.ts b/base/tests/fall/sources/main.ts index a1749811..6eed8af4 100644 --- a/base/tests/fall/sources/main.ts +++ b/base/tests/fall/sources/main.ts @@ -1,6 +1,6 @@ // ../../../make --graphics vulkan --run -///include "../../sources/libs/asim/asim.h" +///include "../../sources/libs/asim.h" function main() { let ops: iron_window_options_t = {