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.

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