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.

209 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. static bool exeIsAvailable (const char* const executable)
  20. {
  21. ChildProcess child;
  22. const bool ok = child.start ("which " + String (executable))
  23. && child.readAllProcessOutput().trim().isNotEmpty();
  24. child.waitForProcessToFinish (60 * 1000);
  25. return ok;
  26. }
  27. bool FileChooser::isPlatformDialogAvailable()
  28. {
  29. #if JUCE_DISABLE_NATIVE_FILECHOOSERS
  30. return false;
  31. #else
  32. static bool canUseNativeBox = exeIsAvailable ("zenity") || exeIsAvailable ("kdialog");
  33. return canUseNativeBox;
  34. #endif
  35. }
  36. static uint64 getTopWindowID() noexcept
  37. {
  38. if (TopLevelWindow* top = TopLevelWindow::getActiveTopLevelWindow())
  39. return (uint64) (pointer_sized_uint) top->getWindowHandle();
  40. return 0;
  41. }
  42. static bool isKdeFullSession()
  43. {
  44. return SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String())
  45. .equalsIgnoreCase ("true");
  46. }
  47. static void addKDialogArgs (StringArray& args, String& separator,
  48. const String& title, const File& file, const String& filters,
  49. bool isDirectory, bool isSave, bool selectMultipleFiles)
  50. {
  51. args.add ("kdialog");
  52. if (title.isNotEmpty())
  53. args.add ("--title=" + title);
  54. if (uint64 topWindowID = getTopWindowID())
  55. {
  56. args.add ("--attach");
  57. args.add (String (topWindowID));
  58. }
  59. if (selectMultipleFiles)
  60. {
  61. separator = "\n";
  62. args.add ("--multiple");
  63. args.add ("--separate-output");
  64. args.add ("--getopenfilename");
  65. }
  66. else
  67. {
  68. if (isSave) args.add ("--getsavefilename");
  69. else if (isDirectory) args.add ("--getexistingdirectory");
  70. else args.add ("--getopenfilename");
  71. }
  72. File startPath;
  73. if (file.exists())
  74. {
  75. startPath = file;
  76. }
  77. else if (file.getParentDirectory().exists())
  78. {
  79. startPath = file.getParentDirectory();
  80. }
  81. else
  82. {
  83. startPath = File::getSpecialLocation (File::userHomeDirectory);
  84. if (isSave)
  85. startPath = startPath.getChildFile (file.getFileName());
  86. }
  87. args.add (startPath.getFullPathName());
  88. args.add (filters.replaceCharacter (';', ' '));
  89. }
  90. static void addZenityArgs (StringArray& args, String& separator,
  91. const String& title, const File& file, const String& filters,
  92. bool isDirectory, bool isSave, bool selectMultipleFiles)
  93. {
  94. args.add ("zenity");
  95. args.add ("--file-selection");
  96. if (title.isNotEmpty())
  97. args.add ("--title=" + title);
  98. if (selectMultipleFiles)
  99. {
  100. separator = ":";
  101. args.add ("--multiple");
  102. args.add ("--separator=" + separator);
  103. }
  104. else
  105. {
  106. if (isDirectory) args.add ("--directory");
  107. if (isSave) args.add ("--save");
  108. }
  109. if (filters.isNotEmpty() && filters != "*" && filters != "*.*")
  110. {
  111. StringArray tokens;
  112. tokens.addTokens (filters, ";,|", "\"");
  113. for (int i = 0; i < tokens.size(); ++i)
  114. args.add ("--file-filter=" + tokens[i]);
  115. }
  116. if (file.isDirectory())
  117. file.setAsCurrentWorkingDirectory();
  118. else if (file.getParentDirectory().exists())
  119. file.getParentDirectory().setAsCurrentWorkingDirectory();
  120. else
  121. File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory();
  122. if (! file.getFileName().isEmpty())
  123. args.add ("--filename=" + file.getFileName());
  124. // supplying the window ID of the topmost window makes sure that Zenity pops up..
  125. if (uint64 topWindowID = getTopWindowID())
  126. setenv ("WINDOWID", String (topWindowID).toRawUTF8(), true);
  127. }
  128. void FileChooser::showPlatformDialog (Array<File>& results,
  129. const String& title, const File& file, const String& filters,
  130. bool isDirectory, bool /* selectsFiles */,
  131. bool isSave, bool /* warnAboutOverwritingExistingFiles */,
  132. bool /*treatFilePackagesAsDirs*/,
  133. bool selectMultipleFiles, FilePreviewComponent*)
  134. {
  135. const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
  136. StringArray args;
  137. String separator;
  138. // use kdialog for KDE sessions or if zenity is missing
  139. if (exeIsAvailable ("kdialog") && (isKdeFullSession() || ! exeIsAvailable ("zenity")))
  140. addKDialogArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
  141. else
  142. addZenityArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
  143. ChildProcess child;
  144. if (child.start (args, ChildProcess::wantStdOut))
  145. {
  146. if (MessageManager::getInstance()->isThisTheMessageThread())
  147. {
  148. while (child.isRunning())
  149. {
  150. if (! MessageManager::getInstance()->runDispatchLoopUntil(20))
  151. break;
  152. }
  153. }
  154. const String result (child.readAllProcessOutput().trim());
  155. if (result.isNotEmpty())
  156. {
  157. StringArray tokens;
  158. if (selectMultipleFiles)
  159. tokens.addTokens (result, separator, "\"");
  160. else
  161. tokens.add (result);
  162. for (int i = 0; i < tokens.size(); ++i)
  163. results.add (File::getCurrentWorkingDirectory().getChildFile (tokens[i]));
  164. }
  165. child.waitForProcessToFinish (60 * 1000);
  166. }
  167. previousWorkingDirectory.setAsCurrentWorkingDirectory();
  168. }