Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
6.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. static bool exeIsAvailable (const char* const executable)
  22. {
  23. ChildProcess child;
  24. const bool ok = child.start ("which " + String (executable))
  25. && child.readAllProcessOutput().trim().isNotEmpty();
  26. child.waitForProcessToFinish (60 * 1000);
  27. return ok;
  28. }
  29. bool FileChooser::isPlatformDialogAvailable()
  30. {
  31. #if JUCE_DISABLE_NATIVE_FILECHOOSERS
  32. return false;
  33. #else
  34. static bool canUseNativeBox = exeIsAvailable ("zenity") || exeIsAvailable ("kdialog");
  35. return canUseNativeBox;
  36. #endif
  37. }
  38. static uint64 getTopWindowID() noexcept
  39. {
  40. if (TopLevelWindow* top = TopLevelWindow::getActiveTopLevelWindow())
  41. return (uint64) (pointer_sized_uint) top->getWindowHandle();
  42. return 0;
  43. }
  44. static bool isKdeFullSession()
  45. {
  46. return SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String())
  47. .equalsIgnoreCase ("true");
  48. }
  49. static void addKDialogArgs (StringArray& args, String& separator,
  50. const String& title, const File& file, const String& filters,
  51. bool isDirectory, bool isSave, bool selectMultipleFiles)
  52. {
  53. args.add ("kdialog");
  54. if (title.isNotEmpty())
  55. args.add ("--title=" + title);
  56. if (uint64 topWindowID = getTopWindowID())
  57. {
  58. args.add ("--attach");
  59. args.add (String (topWindowID));
  60. }
  61. if (selectMultipleFiles)
  62. {
  63. separator = "\n";
  64. args.add ("--multiple");
  65. args.add ("--separate-output");
  66. args.add ("--getopenfilename");
  67. }
  68. else
  69. {
  70. if (isSave) args.add ("--getsavefilename");
  71. else if (isDirectory) args.add ("--getexistingdirectory");
  72. else args.add ("--getopenfilename");
  73. }
  74. File startPath;
  75. if (file.exists())
  76. {
  77. startPath = file;
  78. }
  79. else if (file.getParentDirectory().exists())
  80. {
  81. startPath = file.getParentDirectory();
  82. }
  83. else
  84. {
  85. startPath = File::getSpecialLocation (File::userHomeDirectory);
  86. if (isSave)
  87. startPath = startPath.getChildFile (file.getFileName());
  88. }
  89. args.add (startPath.getFullPathName());
  90. args.add (filters.replaceCharacter (';', ' '));
  91. }
  92. static void addZenityArgs (StringArray& args, String& separator,
  93. const String& title, const File& file, const String& filters,
  94. bool isDirectory, bool isSave, bool selectMultipleFiles)
  95. {
  96. args.add ("zenity");
  97. args.add ("--file-selection");
  98. if (title.isNotEmpty())
  99. args.add ("--title=" + title);
  100. if (selectMultipleFiles)
  101. {
  102. separator = ":";
  103. args.add ("--multiple");
  104. args.add ("--separator=" + separator);
  105. }
  106. else
  107. {
  108. if (isDirectory) args.add ("--directory");
  109. if (isSave) args.add ("--save");
  110. }
  111. if (filters.isNotEmpty() && filters != "*" && filters != "*.*")
  112. {
  113. StringArray tokens;
  114. tokens.addTokens (filters, ";,|", "\"");
  115. for (int i = 0; i < tokens.size(); ++i)
  116. args.add ("--file-filter=" + tokens[i]);
  117. }
  118. if (file.isDirectory())
  119. file.setAsCurrentWorkingDirectory();
  120. else if (file.getParentDirectory().exists())
  121. file.getParentDirectory().setAsCurrentWorkingDirectory();
  122. else
  123. File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory();
  124. if (! file.getFileName().isEmpty())
  125. args.add ("--filename=" + file.getFileName());
  126. // supplying the window ID of the topmost window makes sure that Zenity pops up..
  127. if (uint64 topWindowID = getTopWindowID())
  128. setenv ("WINDOWID", String (topWindowID).toRawUTF8(), true);
  129. }
  130. void FileChooser::showPlatformDialog (Array<File>& results,
  131. const String& title, const File& file, const String& filters,
  132. bool isDirectory, bool /* selectsFiles */,
  133. bool isSave, bool /* warnAboutOverwritingExistingFiles */,
  134. bool /*treatFilePackagesAsDirs*/,
  135. bool selectMultipleFiles, FilePreviewComponent*)
  136. {
  137. const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
  138. StringArray args;
  139. String separator;
  140. // use kdialog for KDE sessions or if zenity is missing
  141. if (exeIsAvailable ("kdialog") && (isKdeFullSession() || ! exeIsAvailable ("zenity")))
  142. addKDialogArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
  143. else
  144. addZenityArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
  145. ChildProcess child;
  146. if (child.start (args, ChildProcess::wantStdOut))
  147. {
  148. if (MessageManager::getInstance()->isThisTheMessageThread())
  149. {
  150. while (child.isRunning())
  151. {
  152. if (! MessageManager::getInstance()->runDispatchLoopUntil(20))
  153. break;
  154. }
  155. }
  156. const String result (child.readAllProcessOutput().trim());
  157. if (result.isNotEmpty())
  158. {
  159. StringArray tokens;
  160. if (selectMultipleFiles)
  161. tokens.addTokens (result, separator, "\"");
  162. else
  163. tokens.add (result);
  164. for (int i = 0; i < tokens.size(); ++i)
  165. results.add (File::getCurrentWorkingDirectory().getChildFile (tokens[i]));
  166. }
  167. child.waitForProcessToFinish (60 * 1000);
  168. }
  169. previousWorkingDirectory.setAsCurrentWorkingDirectory();
  170. }
  171. } // namespace juce