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.

199 lines
6.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. static bool exeIsAvailable (const char* const executable)
  18. {
  19. ChildProcess child;
  20. const bool ok = child.start ("which " + String (executable))
  21. && child.readAllProcessOutput().trim().isNotEmpty();
  22. child.waitForProcessToFinish (60 * 1000);
  23. return ok;
  24. }
  25. bool FileChooser::isPlatformDialogAvailable()
  26. {
  27. #if JUCE_DISABLE_NATIVE_FILECHOOSERS
  28. return false;
  29. #else
  30. static bool canUseNativeBox = exeIsAvailable ("zenity") || exeIsAvailable ("kdialog");
  31. return canUseNativeBox;
  32. #endif
  33. }
  34. static uint64 getTopWindowID() noexcept
  35. {
  36. if (TopLevelWindow* top = TopLevelWindow::getActiveTopLevelWindow())
  37. return (uint64) (pointer_sized_uint) top->getWindowHandle();
  38. return 0;
  39. }
  40. static bool isKdeFullSession()
  41. {
  42. return SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String())
  43. .equalsIgnoreCase ("true");
  44. }
  45. static void addKDialogArgs (StringArray& args, String& separator,
  46. const String& title, const File& file, const String& filters,
  47. bool isDirectory, bool isSave, bool selectMultipleFiles)
  48. {
  49. args.add ("kdialog");
  50. if (title.isNotEmpty())
  51. args.add ("--title=" + title);
  52. if (uint64 topWindowID = getTopWindowID())
  53. {
  54. args.add ("--attach");
  55. args.add (String (topWindowID));
  56. }
  57. if (selectMultipleFiles)
  58. {
  59. separator = "\n";
  60. args.add ("--multiple");
  61. args.add ("--separate-output");
  62. args.add ("--getopenfilename");
  63. }
  64. else
  65. {
  66. if (isSave) args.add ("--getsavefilename");
  67. else if (isDirectory) args.add ("--getexistingdirectory");
  68. else args.add ("--getopenfilename");
  69. }
  70. File startPath;
  71. if (file.exists())
  72. {
  73. startPath = file;
  74. }
  75. else if (file.getParentDirectory().exists())
  76. {
  77. startPath = file.getParentDirectory();
  78. }
  79. else
  80. {
  81. startPath = File::getSpecialLocation (File::userHomeDirectory);
  82. if (isSave)
  83. startPath = startPath.getChildFile (file.getFileName());
  84. }
  85. args.add (startPath.getFullPathName());
  86. args.add (filters.replaceCharacter (';', ' '));
  87. }
  88. static void addZenityArgs (StringArray& args, String& separator,
  89. const String& title, const File& file, const String& filters,
  90. bool isDirectory, bool isSave, bool selectMultipleFiles)
  91. {
  92. args.add ("zenity");
  93. args.add ("--file-selection");
  94. if (title.isNotEmpty())
  95. args.add ("--title=" + title);
  96. if (selectMultipleFiles)
  97. {
  98. separator = ":";
  99. args.add ("--multiple");
  100. args.add ("--separator=" + separator);
  101. }
  102. else
  103. {
  104. if (isDirectory) args.add ("--directory");
  105. if (isSave) args.add ("--save");
  106. }
  107. if (filters.isNotEmpty() && filters != "*" && filters != "*.*")
  108. {
  109. args.add ("--file-filter");
  110. args.add (filters.replaceCharacter (';', ' '));
  111. args.add ("--file-filter");
  112. args.add ("All files | *");
  113. }
  114. if (file.isDirectory())
  115. file.setAsCurrentWorkingDirectory();
  116. else if (file.getParentDirectory().exists())
  117. file.getParentDirectory().setAsCurrentWorkingDirectory();
  118. else
  119. File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory();
  120. if (! file.getFileName().isEmpty())
  121. args.add ("--filename=" + file.getFileName());
  122. // supplying the window ID of the topmost window makes sure that Zenity pops up..
  123. if (uint64 topWindowID = getTopWindowID())
  124. setenv ("WINDOWID", String (topWindowID).toRawUTF8(), true);
  125. }
  126. void FileChooser::showPlatformDialog (Array<File>& results,
  127. const String& title, const File& file, const String& filters,
  128. bool isDirectory, bool /* selectsFiles */,
  129. bool isSave, bool /* warnAboutOverwritingExistingFiles */,
  130. bool selectMultipleFiles, FilePreviewComponent*)
  131. {
  132. const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
  133. StringArray args;
  134. String separator;
  135. // use kdialog for KDE sessions or if zenity is missing
  136. if (exeIsAvailable ("kdialog") && (isKdeFullSession() || ! exeIsAvailable ("zenity")))
  137. addKDialogArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
  138. else
  139. addZenityArgs (args, separator, title, file, filters, isDirectory, isSave, selectMultipleFiles);
  140. args.add ("2>/dev/null"); // (to avoid logging info ending up in the results)
  141. ChildProcess child;
  142. if (child.start (args, ChildProcess::wantStdOut))
  143. {
  144. const String result (child.readAllProcessOutput().trim());
  145. if (result.isNotEmpty())
  146. {
  147. StringArray tokens;
  148. if (selectMultipleFiles)
  149. tokens.addTokens (result, separator, "\"");
  150. else
  151. tokens.add (result);
  152. for (int i = 0; i < tokens.size(); ++i)
  153. results.add (File::getCurrentWorkingDirectory().getChildFile (tokens[i]));
  154. }
  155. child.waitForProcessToFinish (60 * 1000);
  156. }
  157. previousWorkingDirectory.setAsCurrentWorkingDirectory();
  158. }