DISTRHO Plugin Framework
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.

203 lines
5.8KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. // needed for IDE
  17. #include "DistrhoPluginInfo.h"
  18. #include "DistrhoUI.hpp"
  19. // Extra includes for current path and fifo stuff
  20. #include <dlfcn.h>
  21. #include <fcntl.h>
  22. #include <sys/stat.h>
  23. #include <sys/types.h>
  24. START_NAMESPACE_DISTRHO
  25. // TODO: generate a random, not-yet-existing, filename
  26. const char* const kFifoFilename = "/tmp/dpf-fifo-test";
  27. // Helper to get current path of this plugin
  28. static const char* getCurrentPluginFilename()
  29. {
  30. Dl_info exeInfo;
  31. void* localSymbol = (void*)kFifoFilename;
  32. dladdr(localSymbol, &exeInfo);
  33. return exeInfo.dli_fname;
  34. }
  35. // Helper to check if a file exists
  36. static bool fileExists(const char* const filename)
  37. {
  38. return access(filename, F_OK) != -1;
  39. }
  40. // Helper function to keep trying to write until it succeeds or really errors out
  41. static ssize_t
  42. writeRetry(int fd, const void* src, size_t size)
  43. {
  44. ssize_t error;
  45. int attempts = 0;
  46. do {
  47. error = write(fd, src, size);
  48. } while (error == -1 && (errno == EINTR || errno == EPIPE) && ++attempts < 5);
  49. return error;
  50. }
  51. // -----------------------------------------------------------------------------------------------------------
  52. class ExternalExampleUI : public UI
  53. {
  54. public:
  55. ExternalExampleUI()
  56. : UI(405, 256),
  57. fFifo(-1),
  58. fValue(0.0f),
  59. fExternalScript(getNextBundlePath())
  60. {
  61. if (fExternalScript.isEmpty())
  62. {
  63. fExternalScript = getCurrentPluginFilename();
  64. fExternalScript.truncate(fExternalScript.rfind('/'));
  65. }
  66. fExternalScript += "/ExternalLauncher.sh";
  67. d_stdout("External script = %s", fExternalScript.buffer());
  68. }
  69. protected:
  70. /* --------------------------------------------------------------------------------------------------------
  71. * DSP/Plugin Callbacks */
  72. /**
  73. A parameter has changed on the plugin side.
  74. This is called by the host to inform the UI about parameter changes.
  75. */
  76. void parameterChanged(uint32_t index, float value) override
  77. {
  78. if (index != 0)
  79. return;
  80. fValue = value;
  81. if (fFifo == -1)
  82. return;
  83. // NOTE: This is a terrible way to pass values, also locale might get in the way...
  84. char valueStr[24];
  85. std::memset(valueStr, 0, sizeof(valueStr));
  86. std::snprintf(valueStr, 23, "%i\n", static_cast<int>(value + 0.5f));
  87. DISTRHO_SAFE_ASSERT(writeRetry(fFifo, valueStr, 24) == sizeof(valueStr));
  88. }
  89. /* --------------------------------------------------------------------------------------------------------
  90. * External Window overrides */
  91. /**
  92. Keep-alive.
  93. */
  94. void uiIdle() override
  95. {
  96. if (fFifo == -1)
  97. return;
  98. writeRetry(fFifo, "idle\n", 5);
  99. }
  100. /**
  101. Manage external process and IPC when UI is requested to be visible.
  102. */
  103. void setVisible(const bool yesNo) override
  104. {
  105. if (yesNo)
  106. {
  107. DISTRHO_SAFE_ASSERT_RETURN(fileExists(fExternalScript),);
  108. mkfifo(kFifoFilename, 0666);
  109. sync();
  110. char winIdStr[24];
  111. std::memset(winIdStr, 0, sizeof(winIdStr));
  112. std::snprintf(winIdStr, 23, "%lu", getTransientWindowId());
  113. const char* args[] = {
  114. fExternalScript.buffer(),
  115. kFifoFilename,
  116. "--progressbar", "External UI example",
  117. "--title", getTitle(),
  118. nullptr,
  119. };
  120. DISTRHO_SAFE_ASSERT_RETURN(startExternalProcess(args),);
  121. // NOTE: this can lockup the current thread if the other side does not read the file!
  122. fFifo = open(kFifoFilename, O_WRONLY);
  123. DISTRHO_SAFE_ASSERT_RETURN(fFifo != -1,);
  124. parameterChanged(0, fValue);
  125. }
  126. else
  127. {
  128. if (fFifo != -1)
  129. {
  130. if (isRunning())
  131. {
  132. DISTRHO_SAFE_ASSERT(writeRetry(fFifo, "quit\n", 5) == 5);
  133. fsync(fFifo);
  134. }
  135. ::close(fFifo);
  136. fFifo = -1;
  137. }
  138. unlink(kFifoFilename);
  139. terminateAndWaitForExternalProcess();
  140. }
  141. UI::setVisible(yesNo);
  142. }
  143. // -------------------------------------------------------------------------------------------------------
  144. private:
  145. // IPC Stuff
  146. int fFifo;
  147. // Current value, cached for when UI becomes visible
  148. float fValue;
  149. // Path to external ui script
  150. String fExternalScript;
  151. /**
  152. Set our UI class as non-copyable and add a leak detector just in case.
  153. */
  154. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ExternalExampleUI)
  155. };
  156. /* ------------------------------------------------------------------------------------------------------------
  157. * UI entry point, called by DPF to create a new UI instance. */
  158. UI* createUI()
  159. {
  160. return new ExternalExampleUI();
  161. }
  162. // -----------------------------------------------------------------------------------------------------------
  163. END_NAMESPACE_DISTRHO