nfd_zenity.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. Native File Dialog
  3. http://www.frogtoss.com/labs
  4. */
  5. #include <stdio.h>
  6. #include <assert.h>
  7. #include <string.h>
  8. #include "nfd.h"
  9. #include "nfd_common.h"
  10. #define SIMPLE_EXEC_IMPLEMENTATION
  11. #include "simple_exec.h"
  12. const char NO_ZENITY_MSG[] = "zenity not installed";
  13. static void AddTypeToFilterName( const char *typebuf, char *filterName, size_t bufsize )
  14. {
  15. size_t len = strlen(filterName);
  16. if( len > 0 )
  17. strncat( filterName, " *.", bufsize - len - 1 );
  18. else
  19. strncat( filterName, "--file-filter=*.", bufsize - len - 1 );
  20. len = strlen(filterName);
  21. strncat( filterName, typebuf, bufsize - len - 1 );
  22. }
  23. static void AddFiltersToCommandArgs(char** commandArgs, int commandArgsLen, const char *filterList )
  24. {
  25. char typebuf[NFD_MAX_STRLEN] = {0};
  26. const char *p_filterList = filterList;
  27. char *p_typebuf = typebuf;
  28. char filterName[NFD_MAX_STRLEN] = {0};
  29. int i;
  30. if ( !filterList || strlen(filterList) == 0 )
  31. return;
  32. while ( 1 )
  33. {
  34. if ( NFDi_IsFilterSegmentChar(*p_filterList) )
  35. {
  36. char typebufWildcard[NFD_MAX_STRLEN];
  37. /* add another type to the filter */
  38. assert( strlen(typebuf) > 0 );
  39. assert( strlen(typebuf) < NFD_MAX_STRLEN-1 );
  40. snprintf( typebufWildcard, NFD_MAX_STRLEN, "*.%s", typebuf );
  41. AddTypeToFilterName( typebuf, filterName, NFD_MAX_STRLEN );
  42. p_typebuf = typebuf;
  43. memset( typebuf, 0, sizeof(char) * NFD_MAX_STRLEN );
  44. }
  45. if ( *p_filterList == ';' || *p_filterList == '\0' )
  46. {
  47. /* end of filter -- add it to the dialog */
  48. for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++);
  49. commandArgs[i] = strdup(filterName);
  50. filterName[0] = '\0';
  51. if ( *p_filterList == '\0' )
  52. break;
  53. }
  54. if ( !NFDi_IsFilterSegmentChar( *p_filterList ) )
  55. {
  56. *p_typebuf = *p_filterList;
  57. p_typebuf++;
  58. }
  59. p_filterList++;
  60. }
  61. /* always append a wildcard option to the end*/
  62. for(i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++);
  63. commandArgs[i] = strdup("--file-filter=*.*");
  64. }
  65. static nfdresult_t ZenityCommon(char** command, int commandLen, const char* defaultPath, const char* filterList, char** stdOut)
  66. {
  67. if(defaultPath != NULL)
  68. {
  69. char* prefix = "--filename";
  70. int len = strlen(prefix) + strlen(defaultPath) + 1;
  71. char* tmp = (char*) calloc(len, 1);
  72. strcat(tmp, prefix);
  73. strcat(tmp, defaultPath);
  74. int i;
  75. for(i = 0; command[i] != NULL && i < commandLen; i++);
  76. command[i] = tmp;
  77. }
  78. AddFiltersToCommandArgs(command, commandLen, filterList);
  79. int byteCount = 0;
  80. int exitCode = 0;
  81. int processInvokeError = runCommandArray(stdOut, &byteCount, &exitCode, 0, command);
  82. for(int i = 0; command[i] != NULL && i < commandLen; i++)
  83. free(command[i]);
  84. nfdresult_t result = NFD_OKAY;
  85. if(processInvokeError == COMMAND_NOT_FOUND)
  86. {
  87. NFDi_SetError(NO_ZENITY_MSG);
  88. result = NFD_ERROR;
  89. }
  90. else
  91. {
  92. if(exitCode == 1)
  93. result = NFD_CANCEL;
  94. }
  95. return result;
  96. }
  97. static nfdresult_t AllocPathSet(char* zenityList, nfdpathset_t *pathSet )
  98. {
  99. size_t bufSize = 0;
  100. nfdchar_t *p_buf;
  101. size_t count = 0;
  102. assert(zenityList);
  103. assert(pathSet);
  104. size_t len = strlen(zenityList) + 1;
  105. pathSet->buf = NFDi_Malloc(len);
  106. int numEntries = 1;
  107. for(size_t i = 0; i < len; i++)
  108. {
  109. char ch = zenityList[i];
  110. if(ch == '|')
  111. {
  112. numEntries++;
  113. ch = '\0';
  114. }
  115. pathSet->buf[i] = ch;
  116. }
  117. pathSet->count = numEntries;
  118. assert( pathSet->count > 0 );
  119. pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count );
  120. int entry = 0;
  121. pathSet->indices[0] = 0;
  122. for(size_t i = 0; i < len; i++)
  123. {
  124. char ch = zenityList[i];
  125. if(ch == '|')
  126. {
  127. entry++;
  128. pathSet->indices[entry] = i + 1;
  129. }
  130. }
  131. return NFD_OKAY;
  132. }
  133. /* public */
  134. nfdresult_t NFD_OpenDialog( const char *filterList,
  135. const nfdchar_t *defaultPath,
  136. nfdchar_t **outPath )
  137. {
  138. int commandLen = 100;
  139. char* command[commandLen];
  140. memset(command, 0, commandLen * sizeof(char*));
  141. command[0] = strdup("zenity");
  142. command[1] = strdup("--file-selection");
  143. command[2] = strdup("--title=Open File");
  144. char* stdOut = NULL;
  145. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
  146. if(stdOut != NULL)
  147. {
  148. size_t len = strlen(stdOut);
  149. *outPath = NFDi_Malloc(len);
  150. memcpy(*outPath, stdOut, len);
  151. (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator
  152. free(stdOut);
  153. }
  154. else
  155. {
  156. *outPath = NULL;
  157. }
  158. return result;
  159. }
  160. nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
  161. const nfdchar_t *defaultPath,
  162. nfdpathset_t *outPaths )
  163. {
  164. int commandLen = 100;
  165. char* command[commandLen];
  166. memset(command, 0, commandLen * sizeof(char*));
  167. command[0] = strdup("zenity");
  168. command[1] = strdup("--file-selection");
  169. command[2] = strdup("--title=Open Files");
  170. command[3] = strdup("--multiple");
  171. char* stdOut = NULL;
  172. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
  173. if(stdOut != NULL)
  174. {
  175. size_t len = strlen(stdOut);
  176. stdOut[len-1] = '\0'; // remove trailing newline
  177. if ( AllocPathSet( stdOut, outPaths ) == NFD_ERROR )
  178. result = NFD_ERROR;
  179. free(stdOut);
  180. }
  181. else
  182. {
  183. result = NFD_ERROR;
  184. }
  185. return result;
  186. }
  187. nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
  188. const nfdchar_t *defaultPath,
  189. nfdchar_t **outPath )
  190. {
  191. int commandLen = 100;
  192. char* command[commandLen];
  193. memset(command, 0, commandLen * sizeof(char*));
  194. command[0] = strdup("zenity");
  195. command[1] = strdup("--file-selection");
  196. command[2] = strdup("--title=Save File");
  197. command[3] = strdup("--save");
  198. char* stdOut = NULL;
  199. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
  200. if(stdOut != NULL)
  201. {
  202. size_t len = strlen(stdOut);
  203. *outPath = NFDi_Malloc(len);
  204. memcpy(*outPath, stdOut, len);
  205. (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator
  206. free(stdOut);
  207. }
  208. else
  209. {
  210. *outPath = NULL;
  211. }
  212. return result;
  213. }
  214. nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
  215. nfdchar_t **outPath)
  216. {
  217. int commandLen = 100;
  218. char* command[commandLen];
  219. memset(command, 0, commandLen * sizeof(char*));
  220. command[0] = strdup("zenity");
  221. command[1] = strdup("--file-selection");
  222. command[2] = strdup("--directory");
  223. command[3] = strdup("--title=Select folder");
  224. char* stdOut = NULL;
  225. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, "", &stdOut);
  226. if(stdOut != NULL)
  227. {
  228. size_t len = strlen(stdOut);
  229. *outPath = NFDi_Malloc(len);
  230. memcpy(*outPath, stdOut, len);
  231. (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator
  232. free(stdOut);
  233. }
  234. else
  235. {
  236. *outPath = NULL;
  237. }
  238. return result;
  239. }