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.

300 lines
8.0KB

  1. /*
  2. * DISTRHO Ildaeil Plugin
  3. * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. #include "src/DistrhoDefines.h"
  18. #if defined(DISTRHO_OS_HAIKU)
  19. #elif defined(DISTRHO_OS_MAC)
  20. # import <Cocoa/Cocoa.h>
  21. #elif defined(DISTRHO_OS_WINDOWS)
  22. #else
  23. # define ILDAEIL_X11
  24. # include <X11/Xlib.h>
  25. # include <X11/Xutil.h>
  26. # include <pthread.h>
  27. #endif
  28. #include "PluginHostWindow.hpp"
  29. #ifdef DISTRHO_OS_MAC
  30. @interface IldaeilPluginView : NSView
  31. - (void)resizeWithOldSuperviewSize:(NSSize)oldSize;
  32. @end
  33. @implementation IldaeilPluginView
  34. - (void)resizeWithOldSuperviewSize:(NSSize)oldSize
  35. {
  36. [super resizeWithOldSuperviewSize:oldSize];
  37. }
  38. @end
  39. #endif
  40. START_NAMESPACE_DGL
  41. #if defined(DISTRHO_OS_HAIKU)
  42. #elif defined(DISTRHO_OS_MAC)
  43. #elif defined(DISTRHO_OS_WINDOWS)
  44. #else
  45. static pthread_mutex_t gErrorMutex = PTHREAD_MUTEX_INITIALIZER;
  46. static bool gErrorTriggered = false;
  47. static int ildaeilErrorHandler(Display*, XErrorEvent*)
  48. {
  49. gErrorTriggered = true;
  50. return 0;
  51. }
  52. #endif
  53. struct PluginHostWindow::PrivateData
  54. {
  55. Window& parentWindow;
  56. const uintptr_t parentWindowId;
  57. Callbacks* const pluginWindowCallbacks;
  58. #if defined(DISTRHO_OS_HAIKU)
  59. #elif defined(DISTRHO_OS_MAC)
  60. IldaeilPluginView* view;
  61. #elif defined(DISTRHO_OS_WINDOWS)
  62. #else
  63. ::Display* display;
  64. ::Window pluginWindow;
  65. uint xOffset, yOffset;
  66. #endif
  67. bool lookingForChildren;
  68. PrivateData(Window& pw, Callbacks* const cbs)
  69. : parentWindow(pw),
  70. parentWindowId(pw.getNativeWindowHandle()),
  71. pluginWindowCallbacks(cbs),
  72. #if defined(DISTRHO_OS_HAIKU)
  73. #elif defined(DISTRHO_OS_MAC)
  74. view(nullptr),
  75. #elif defined(DISTRHO_OS_WINDOWS)
  76. #else
  77. display(nullptr),
  78. pluginWindow(0),
  79. xOffset(0),
  80. yOffset(0),
  81. #endif
  82. lookingForChildren(false)
  83. {
  84. #if defined(DISTRHO_OS_HAIKU)
  85. #elif defined(DISTRHO_OS_MAC)
  86. view = [[IldaeilPluginView new]retain];
  87. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr,)
  88. [view setAutoresizingMask:NSViewNotSizable];
  89. [view setAutoresizesSubviews:YES];
  90. [view setHidden:YES];
  91. [(NSView*)parentWindowId addSubview:view];
  92. #elif defined(DISTRHO_OS_WINDOWS)
  93. #else
  94. display = XOpenDisplay(nullptr);
  95. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr,)
  96. #endif
  97. }
  98. ~PrivateData()
  99. {
  100. #if defined(DISTRHO_OS_HAIKU)
  101. #elif defined(DISTRHO_OS_MAC)
  102. if (view != nullptr)
  103. [view release];
  104. #elif defined(DISTRHO_OS_WINDOWS)
  105. #else
  106. if (display != nullptr)
  107. XCloseDisplay(display);
  108. #endif
  109. }
  110. void* attachAndGetWindowHandle()
  111. {
  112. lookingForChildren = true;
  113. #if defined(DISTRHO_OS_HAIKU)
  114. return nullptr;
  115. #elif defined(DISTRHO_OS_MAC)
  116. return view;
  117. #elif defined(DISTRHO_OS_WINDOWS)
  118. return nullptr;
  119. #else
  120. return (void*)parentWindowId;
  121. #endif
  122. }
  123. void hide()
  124. {
  125. #if defined(DISTRHO_OS_HAIKU)
  126. #elif defined(DISTRHO_OS_MAC)
  127. if (view != nullptr)
  128. [view setHidden:YES];
  129. #elif defined(DISTRHO_OS_WINDOWS)
  130. #else
  131. pluginWindow = 0;
  132. #endif
  133. }
  134. void idle()
  135. {
  136. if (lookingForChildren)
  137. {
  138. #if defined(DISTRHO_OS_HAIKU)
  139. #elif defined(DISTRHO_OS_MAC)
  140. if (view == nullptr)
  141. return;
  142. for (NSView* subview in [view subviews])
  143. {
  144. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  145. const NSSize size = [subview frame].size;
  146. const double width = size.width;
  147. const double height = size.height;
  148. if (width <= 1 || height <= 1)
  149. break;
  150. lookingForChildren = false;
  151. [view setFrameSize:size];
  152. [view setHidden:NO];
  153. [view setNeedsDisplay:YES];
  154. pluginWindowCallbacks->pluginWindowResized(width * scaleFactor, height * scaleFactor);
  155. break;
  156. }
  157. #elif defined(DISTRHO_OS_WINDOWS)
  158. #else
  159. if (pluginWindow == 0)
  160. {
  161. ::Window rootWindow, parentWindow;
  162. ::Window* childWindows = nullptr;
  163. uint numChildren = 0;
  164. XQueryTree(display, parentWindowId, &rootWindow, &parentWindow, &childWindows, &numChildren);
  165. if (numChildren > 0 && childWindows != nullptr)
  166. {
  167. pluginWindow = childWindows[0];
  168. XFree(childWindows);
  169. }
  170. }
  171. if (pluginWindow != 0)
  172. {
  173. int width = 0;
  174. int height = 0;
  175. XWindowAttributes attrs;
  176. memset(&attrs, 0, sizeof(attrs));
  177. pthread_mutex_lock(&gErrorMutex);
  178. const XErrorHandler oldErrorHandler = XSetErrorHandler(ildaeilErrorHandler);
  179. gErrorTriggered = false;
  180. if (XGetWindowAttributes(display, pluginWindow, &attrs) && ! gErrorTriggered)
  181. {
  182. width = attrs.width;
  183. height = attrs.height;
  184. }
  185. XSetErrorHandler(oldErrorHandler);
  186. pthread_mutex_unlock(&gErrorMutex);
  187. if (width == 0 && height == 0)
  188. {
  189. XSizeHints sizeHints;
  190. memset(&sizeHints, 0, sizeof(sizeHints));
  191. if (XGetNormalHints(display, pluginWindow, &sizeHints))
  192. {
  193. if (sizeHints.flags & PSize)
  194. {
  195. width = sizeHints.width;
  196. height = sizeHints.height;
  197. }
  198. else if (sizeHints.flags & PBaseSize)
  199. {
  200. width = sizeHints.base_width;
  201. height = sizeHints.base_height;
  202. }
  203. }
  204. }
  205. d_stdout("child window bounds %u %u", width, height);
  206. if (width > 1 && height > 1)
  207. {
  208. lookingForChildren = false;
  209. XMoveWindow(display, pluginWindow, xOffset, yOffset);
  210. pluginWindowCallbacks->pluginWindowResized(width, height);
  211. }
  212. }
  213. #endif
  214. }
  215. #ifdef ILDAEIL_X11
  216. for (XEvent event; XPending(display) > 0;)
  217. XNextEvent(display, &event);
  218. #endif
  219. }
  220. void setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  221. {
  222. #if defined(DISTRHO_OS_HAIKU)
  223. #elif defined(DISTRHO_OS_MAC)
  224. if (view != nullptr)
  225. {
  226. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  227. [view setFrame:NSMakeRect(x / scaleFactor, y / scaleFactor, width / scaleFactor, height / scaleFactor)];
  228. }
  229. #elif defined(DISTRHO_OS_WINDOWS)
  230. #else
  231. xOffset = x;
  232. yOffset = y;
  233. // unused
  234. (void)width;
  235. (void)height;
  236. #endif
  237. }
  238. };
  239. PluginHostWindow::PluginHostWindow(Window& parentWindow, Callbacks* const cbs)
  240. : pData(new PrivateData(parentWindow, cbs)) {}
  241. PluginHostWindow::~PluginHostWindow()
  242. {
  243. delete pData;
  244. }
  245. void* PluginHostWindow::attachAndGetWindowHandle()
  246. {
  247. return pData->attachAndGetWindowHandle();
  248. }
  249. void PluginHostWindow::hide()
  250. {
  251. pData->hide();
  252. }
  253. void PluginHostWindow::idle()
  254. {
  255. pData->idle();
  256. }
  257. void PluginHostWindow::setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  258. {
  259. pData->setPositionAndSize(x, y, width, height);
  260. }
  261. END_NAMESPACE_DGL