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.

222 lines
6.7KB

  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. void titleChanged(const char* const title) override
  107. {
  108. d_stdout("visibilityChanged %s", title);
  109. #if defined(DISTRHO_OS_MAC)
  110. #elif defined(DISTRHO_OS_WINDOWS)
  111. #else
  112. DISTRHO_SAFE_ASSERT_RETURN(fWindow != 0,);
  113. XStoreName(fDisplay, fWindow, title);
  114. #endif
  115. }
  116. void transientWindowChanged(const uintptr_t winId) override
  117. {
  118. d_stdout("transientWindowChanged %lu", winId);
  119. #if defined(DISTRHO_OS_MAC)
  120. #elif defined(DISTRHO_OS_WINDOWS)
  121. #else
  122. DISTRHO_SAFE_ASSERT_RETURN(fWindow != 0,);
  123. XSetTransientForHint(fDisplay, fWindow, (::Window)winId);
  124. #endif
  125. }
  126. void visibilityChanged(const bool visible) override
  127. {
  128. d_stdout("visibilityChanged %d", visible);
  129. #if defined(DISTRHO_OS_MAC)
  130. #elif defined(DISTRHO_OS_WINDOWS)
  131. #else
  132. DISTRHO_SAFE_ASSERT_RETURN(fWindow != 0,);
  133. if (visible)
  134. XMapRaised(fDisplay, fWindow);
  135. else
  136. XUnmapWindow(fDisplay, fWindow);
  137. #endif
  138. }
  139. void uiIdle() override
  140. {
  141. // d_stdout("uiIdle");
  142. #if defined(DISTRHO_OS_MAC)
  143. #elif defined(DISTRHO_OS_WINDOWS)
  144. #else
  145. if (fDisplay == nullptr)
  146. return;
  147. for (XEvent event; XPending(fDisplay) > 0;)
  148. {
  149. XNextEvent(fDisplay, &event);
  150. if (! isVisible())
  151. continue;
  152. switch (event.type)
  153. {
  154. case ClientMessage:
  155. if (char* const type = XGetAtomName(fDisplay, event.xclient.message_type))
  156. {
  157. if (std::strcmp(type, "WM_PROTOCOLS") == 0)
  158. hide();
  159. }
  160. break;
  161. case KeyRelease:
  162. if (event.xkey.keycode == X11Key_Escape)
  163. hide();
  164. break;
  165. }
  166. }
  167. #endif
  168. }
  169. // -------------------------------------------------------------------------------------------------------
  170. private:
  171. // Current value, cached for when UI becomes visible
  172. float fValue;
  173. /**
  174. Set our UI class as non-copyable and add a leak detector just in case.
  175. */
  176. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EmbedExternalExampleUI)
  177. };
  178. /* ------------------------------------------------------------------------------------------------------------
  179. * UI entry point, called by DPF to create a new UI instance. */
  180. UI* createUI()
  181. {
  182. return new EmbedExternalExampleUI();
  183. }
  184. // -----------------------------------------------------------------------------------------------------------
  185. END_NAMESPACE_DISTRHO