nfd_zenity.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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. assert(zenityList);
  100. assert(pathSet);
  101. size_t len = strlen(zenityList) + 1;
  102. pathSet->buf = NFDi_Malloc(len);
  103. int numEntries = 1;
  104. for(size_t i = 0; i < len; i++)
  105. {
  106. char ch = zenityList[i];
  107. if(ch == '|')
  108. {
  109. numEntries++;
  110. ch = '\0';
  111. }
  112. pathSet->buf[i] = ch;
  113. }
  114. pathSet->count = numEntries;
  115. assert( pathSet->count > 0 );
  116. pathSet->indices = NFDi_Malloc( sizeof(size_t)*pathSet->count );
  117. int entry = 0;
  118. pathSet->indices[0] = 0;
  119. for(size_t i = 0; i < len; i++)
  120. {
  121. char ch = zenityList[i];
  122. if(ch == '|')
  123. {
  124. entry++;
  125. pathSet->indices[entry] = i + 1;
  126. }
  127. }
  128. return NFD_OKAY;
  129. }
  130. /* public */
  131. nfdresult_t NFD_OpenDialog( const char *filterList,
  132. const nfdchar_t *defaultPath,
  133. nfdchar_t **outPath )
  134. {
  135. int commandLen = 100;
  136. char* command[commandLen];
  137. memset(command, 0, commandLen * sizeof(char*));
  138. command[0] = strdup("zenity");
  139. command[1] = strdup("--file-selection");
  140. command[2] = strdup("--title=Open File");
  141. char* stdOut = NULL;
  142. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
  143. if(stdOut != NULL)
  144. {
  145. size_t len = strlen(stdOut);
  146. *outPath = NFDi_Malloc(len);
  147. memcpy(*outPath, stdOut, len);
  148. (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator
  149. free(stdOut);
  150. }
  151. else
  152. {
  153. *outPath = NULL;
  154. }
  155. return result;
  156. }
  157. nfdresult_t NFD_OpenDialogMultiple( const nfdchar_t *filterList,
  158. const nfdchar_t *defaultPath,
  159. nfdpathset_t *outPaths )
  160. {
  161. int commandLen = 100;
  162. char* command[commandLen];
  163. memset(command, 0, commandLen * sizeof(char*));
  164. command[0] = strdup("zenity");
  165. command[1] = strdup("--file-selection");
  166. command[2] = strdup("--title=Open Files");
  167. command[3] = strdup("--multiple");
  168. char* stdOut = NULL;
  169. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
  170. if(stdOut != NULL)
  171. {
  172. size_t len = strlen(stdOut);
  173. stdOut[len-1] = '\0'; // remove trailing newline
  174. if ( AllocPathSet( stdOut, outPaths ) == NFD_ERROR )
  175. result = NFD_ERROR;
  176. free(stdOut);
  177. }
  178. else
  179. {
  180. result = NFD_ERROR;
  181. }
  182. return result;
  183. }
  184. nfdresult_t NFD_SaveDialog( const nfdchar_t *filterList,
  185. const nfdchar_t *defaultPath,
  186. nfdchar_t **outPath )
  187. {
  188. int commandLen = 100;
  189. char* command[commandLen];
  190. memset(command, 0, commandLen * sizeof(char*));
  191. command[0] = strdup("zenity");
  192. command[1] = strdup("--file-selection");
  193. command[2] = strdup("--title=Save File");
  194. command[3] = strdup("--save");
  195. char* stdOut = NULL;
  196. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
  197. if(stdOut != NULL)
  198. {
  199. size_t len = strlen(stdOut);
  200. *outPath = NFDi_Malloc(len);
  201. memcpy(*outPath, stdOut, len);
  202. (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator
  203. free(stdOut);
  204. }
  205. else
  206. {
  207. *outPath = NULL;
  208. }
  209. return result;
  210. }
  211. nfdresult_t NFD_PickFolder(const nfdchar_t *defaultPath,
  212. nfdchar_t **outPath)
  213. {
  214. int commandLen = 100;
  215. char* command[commandLen];
  216. memset(command, 0, commandLen * sizeof(char*));
  217. command[0] = strdup("zenity");
  218. command[1] = strdup("--file-selection");
  219. command[2] = strdup("--directory");
  220. command[3] = strdup("--title=Select folder");
  221. char* stdOut = NULL;
  222. nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, "", &stdOut);
  223. if(stdOut != NULL)
  224. {
  225. size_t len = strlen(stdOut);
  226. *outPath = NFDi_Malloc(len);
  227. memcpy(*outPath, stdOut, len);
  228. (*outPath)[len-1] = '\0'; // trim out the final \n with a null terminator
  229. free(stdOut);
  230. }
  231. else
  232. {
  233. *outPath = NULL;
  234. }
  235. return result;
  236. }