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.

232 lines
6.9KB

  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. #if defined(DISTRHO_OS_MAC)
  20. #elif defined(DISTRHO_OS_WINDOWS)
  21. #else
  22. # include <sys/types.h>
  23. # include <X11/Xatom.h>
  24. # include <X11/Xlib.h>
  25. # include <X11/Xutil.h>
  26. # define X11Key_Escape 9
  27. #endif
  28. START_NAMESPACE_DISTRHO
  29. // -----------------------------------------------------------------------------------------------------------
  30. class EmbedExternalExampleUI : public UI
  31. {
  32. #if defined(DISTRHO_OS_MAC)
  33. #elif defined(DISTRHO_OS_WINDOWS)
  34. #else
  35. ::Display* fDisplay;
  36. ::Window fWindow;
  37. #endif
  38. public:
  39. EmbedExternalExampleUI()
  40. : UI(512, 256),
  41. fDisplay(nullptr),
  42. fWindow(0),
  43. fValue(0.0f)
  44. {
  45. #if defined(DISTRHO_OS_MAC)
  46. #elif defined(DISTRHO_OS_WINDOWS)
  47. #else
  48. fDisplay = XOpenDisplay(nullptr);
  49. DISTRHO_SAFE_ASSERT_RETURN(fDisplay != nullptr,);
  50. const int screen = DefaultScreen(fDisplay);
  51. const ::Window root = RootWindow(fDisplay, screen);
  52. const ::Window parent = isEmbed() ? (::Window)getParentWindowHandle() : root;
  53. fWindow = XCreateSimpleWindow(fDisplay, parent, 0, 0, getWidth(), getHeight(), 0, 0, 0);
  54. DISTRHO_SAFE_ASSERT_RETURN(fWindow != 0,);
  55. XSizeHints sizeHints = {};
  56. sizeHints.flags = PMinSize;
  57. sizeHints.min_width = getWidth();
  58. sizeHints.min_height = getHeight();
  59. XSetNormalHints(fDisplay, fWindow, &sizeHints);
  60. XStoreName(fDisplay, fWindow, getTitle());
  61. if (parent == root)
  62. {
  63. // grab Esc key for auto-close
  64. XGrabKey(fDisplay, X11Key_Escape, AnyModifier, fWindow, 1, GrabModeAsync, GrabModeAsync);
  65. // destroy window on close
  66. Atom wmDelete = XInternAtom(fDisplay, "WM_DELETE_WINDOW", True);
  67. XSetWMProtocols(fDisplay, fWindow, &wmDelete, 1);
  68. // set pid WM hint
  69. const pid_t pid = getpid();
  70. const Atom _nwp = XInternAtom(fDisplay, "_NET_WM_PID", False);
  71. XChangeProperty(fDisplay, fWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1);
  72. // set the window to both dialog and normal to produce a decorated floating dialog
  73. // order is important: DIALOG needs to come before NORMAL
  74. const Atom _wt = XInternAtom(fDisplay, "_NET_WM_WINDOW_TYPE", False);
  75. const Atom _wts[2] = {
  76. XInternAtom(fDisplay, "_NET_WM_WINDOW_TYPE_DIALOG", False),
  77. XInternAtom(fDisplay, "_NET_WM_WINDOW_TYPE_NORMAL", False)
  78. };
  79. XChangeProperty(fDisplay, fWindow, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, 2);
  80. }
  81. #endif
  82. }
  83. ~EmbedExternalExampleUI()
  84. {
  85. if (fDisplay == nullptr)
  86. return;
  87. if (fWindow != 0)
  88. XDestroyWindow(fDisplay, fWindow);
  89. XCloseDisplay(fDisplay);
  90. }
  91. protected:
  92. /* --------------------------------------------------------------------------------------------------------
  93. * DSP/Plugin Callbacks */
  94. /**
  95. A parameter has changed on the plugin side.
  96. This is called by the host to inform the UI about parameter changes.
  97. */
  98. void parameterChanged(uint32_t index, float value) override
  99. {
  100. if (index != 0)
  101. return;
  102. fValue = value;
  103. }
  104. /* --------------------------------------------------------------------------------------------------------
  105. * External Window overrides */
  106. uintptr_t getNativeWindowHandle() const noexcept override
  107. {
  108. #if defined(DISTRHO_OS_MAC)
  109. #elif defined(DISTRHO_OS_WINDOWS)
  110. #else
  111. return (uintptr_t)fWindow;
  112. #endif
  113. return 0;
  114. }
  115. void titleChanged(const char* const title) override
  116. {
  117. d_stdout("visibilityChanged %s", title);
  118. #if defined(DISTRHO_OS_MAC)
  119. #elif defined(DISTRHO_OS_WINDOWS)
  120. #else
  121. DISTRHO_SAFE_ASSERT_RETURN(fWindow != 0,);
  122. XStoreName(fDisplay, fWindow, title);
  123. #endif
  124. }
  125. void transientWindowChanged(const uintptr_t winId) override
  126. {
  127. d_stdout("transientWindowChanged %lu", winId);
  128. #if defined(DISTRHO_OS_MAC)
  129. #elif defined(DISTRHO_OS_WINDOWS)
  130. #else
  131. DISTRHO_SAFE_ASSERT_RETURN(fWindow != 0,);
  132. XSetTransientForHint(fDisplay, fWindow, (::Window)winId);
  133. #endif
  134. }
  135. void visibilityChanged(const bool visible) override
  136. {
  137. d_stdout("visibilityChanged %d", visible);
  138. #if defined(DISTRHO_OS_MAC)
  139. #elif defined(DISTRHO_OS_WINDOWS)
  140. #else
  141. DISTRHO_SAFE_ASSERT_RETURN(fWindow != 0,);
  142. if (visible)
  143. XMapRaised(fDisplay, fWindow);
  144. else
  145. XUnmapWindow(fDisplay, fWindow);
  146. #endif
  147. }
  148. void uiIdle() override
  149. {
  150. // d_stdout("uiIdle");
  151. #if defined(DISTRHO_OS_MAC)
  152. #elif defined(DISTRHO_OS_WINDOWS)
  153. #else
  154. if (fDisplay == nullptr)
  155. return;
  156. for (XEvent event; XPending(fDisplay) > 0;)
  157. {
  158. XNextEvent(fDisplay, &event);
  159. if (! isVisible())
  160. continue;
  161. switch (event.type)
  162. {
  163. case ClientMessage:
  164. if (char* const type = XGetAtomName(fDisplay, event.xclient.message_type))
  165. {
  166. if (std::strcmp(type, "WM_PROTOCOLS") == 0)
  167. hide();
  168. }
  169. break;
  170. case KeyRelease:
  171. if (event.xkey.keycode == X11Key_Escape)
  172. hide();
  173. break;
  174. }
  175. }
  176. #endif
  177. }
  178. // -------------------------------------------------------------------------------------------------------
  179. private:
  180. // Current value, cached for when UI becomes visible
  181. float fValue;
  182. /**
  183. Set our UI class as non-copyable and add a leak detector just in case.
  184. */
  185. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EmbedExternalExampleUI)
  186. };
  187. /* ------------------------------------------------------------------------------------------------------------
  188. * UI entry point, called by DPF to create a new UI instance. */
  189. UI* createUI()
  190. {
  191. return new EmbedExternalExampleUI();
  192. }
  193. // -----------------------------------------------------------------------------------------------------------
  194. END_NAMESPACE_DISTRHO