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.

302 lines
8.1KB

  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. pluginWindow = 0;
  121. return (void*)parentWindowId;
  122. #endif
  123. }
  124. void hide()
  125. {
  126. #if defined(DISTRHO_OS_HAIKU)
  127. #elif defined(DISTRHO_OS_MAC)
  128. if (view != nullptr)
  129. [view setHidden:YES];
  130. [NSOpenGLContext clearCurrentContext];
  131. #elif defined(DISTRHO_OS_WINDOWS)
  132. #else
  133. pluginWindow = 0;
  134. #endif
  135. }
  136. void idle()
  137. {
  138. if (lookingForChildren)
  139. {
  140. #if defined(DISTRHO_OS_HAIKU)
  141. #elif defined(DISTRHO_OS_MAC)
  142. if (view == nullptr)
  143. return;
  144. for (NSView* subview in [view subviews])
  145. {
  146. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  147. const NSSize size = [subview frame].size;
  148. const double width = size.width;
  149. const double height = size.height;
  150. if (width <= 1 || height <= 1)
  151. break;
  152. lookingForChildren = false;
  153. [view setFrameSize:size];
  154. [view setHidden:NO];
  155. [view setNeedsDisplay:YES];
  156. pluginWindowCallbacks->pluginWindowResized(width * scaleFactor, height * scaleFactor);
  157. break;
  158. }
  159. #elif defined(DISTRHO_OS_WINDOWS)
  160. #else
  161. if (pluginWindow == 0)
  162. {
  163. ::Window rootWindow, parentWindow;
  164. ::Window* childWindows = nullptr;
  165. uint numChildren = 0;
  166. XQueryTree(display, parentWindowId, &rootWindow, &parentWindow, &childWindows, &numChildren);
  167. if (numChildren > 0 && childWindows != nullptr)
  168. {
  169. pluginWindow = childWindows[0];
  170. XFree(childWindows);
  171. }
  172. }
  173. if (pluginWindow != 0)
  174. {
  175. int width = 0;
  176. int height = 0;
  177. XWindowAttributes attrs;
  178. memset(&attrs, 0, sizeof(attrs));
  179. pthread_mutex_lock(&gErrorMutex);
  180. const XErrorHandler oldErrorHandler = XSetErrorHandler(ildaeilErrorHandler);
  181. gErrorTriggered = false;
  182. if (XGetWindowAttributes(display, pluginWindow, &attrs) && ! gErrorTriggered)
  183. {
  184. width = attrs.width;
  185. height = attrs.height;
  186. }
  187. XSetErrorHandler(oldErrorHandler);
  188. pthread_mutex_unlock(&gErrorMutex);
  189. if (width == 0 && height == 0)
  190. {
  191. XSizeHints sizeHints;
  192. memset(&sizeHints, 0, sizeof(sizeHints));
  193. if (XGetNormalHints(display, pluginWindow, &sizeHints))
  194. {
  195. if (sizeHints.flags & PSize)
  196. {
  197. width = sizeHints.width;
  198. height = sizeHints.height;
  199. }
  200. else if (sizeHints.flags & PBaseSize)
  201. {
  202. width = sizeHints.base_width;
  203. height = sizeHints.base_height;
  204. }
  205. }
  206. }
  207. d_stdout("child window bounds %u %u | offset %u %u", width, height, xOffset, yOffset);
  208. if (width > 1 && height > 1)
  209. {
  210. lookingForChildren = false;
  211. XMoveWindow(display, pluginWindow, xOffset, yOffset);
  212. pluginWindowCallbacks->pluginWindowResized(width, height);
  213. }
  214. }
  215. #endif
  216. }
  217. #ifdef ILDAEIL_X11
  218. for (XEvent event; XPending(display) > 0;)
  219. XNextEvent(display, &event);
  220. #endif
  221. }
  222. void setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  223. {
  224. #if defined(DISTRHO_OS_HAIKU)
  225. #elif defined(DISTRHO_OS_MAC)
  226. if (view != nullptr)
  227. {
  228. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  229. [view setFrame:NSMakeRect(x / scaleFactor, y / scaleFactor, width / scaleFactor, height / scaleFactor)];
  230. }
  231. #elif defined(DISTRHO_OS_WINDOWS)
  232. #else
  233. xOffset = x;
  234. yOffset = y;
  235. // unused
  236. (void)width;
  237. (void)height;
  238. #endif
  239. }
  240. };
  241. PluginHostWindow::PluginHostWindow(Window& parentWindow, Callbacks* const cbs)
  242. : pData(new PrivateData(parentWindow, cbs)) {}
  243. PluginHostWindow::~PluginHostWindow()
  244. {
  245. delete pData;
  246. }
  247. void* PluginHostWindow::attachAndGetWindowHandle()
  248. {
  249. return pData->attachAndGetWindowHandle();
  250. }
  251. void PluginHostWindow::hide()
  252. {
  253. pData->hide();
  254. }
  255. void PluginHostWindow::idle()
  256. {
  257. pData->idle();
  258. }
  259. void PluginHostWindow::setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  260. {
  261. pData->setPositionAndSize(x, y, width, height);
  262. }
  263. END_NAMESPACE_DGL