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.

340 lines
9.4KB

  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. # define WIN32_LEAN_AND_MEAN
  23. # include <windows.h>
  24. #else
  25. # define ILDAEIL_X11
  26. # include <X11/Xlib.h>
  27. # include <X11/Xutil.h>
  28. # include <pthread.h>
  29. #endif
  30. #include "PluginHostWindow.hpp"
  31. #ifdef DISTRHO_OS_MAC
  32. @interface IldaeilPluginView : NSView
  33. - (void)resizeWithOldSuperviewSize:(NSSize)oldSize;
  34. @end
  35. @implementation IldaeilPluginView
  36. - (void)resizeWithOldSuperviewSize:(NSSize)oldSize
  37. {
  38. [super resizeWithOldSuperviewSize:oldSize];
  39. }
  40. @end
  41. #endif
  42. START_NAMESPACE_DGL
  43. #if defined(DISTRHO_OS_HAIKU)
  44. #elif defined(DISTRHO_OS_MAC)
  45. #elif defined(DISTRHO_OS_WINDOWS)
  46. #else
  47. static pthread_mutex_t gErrorMutex = PTHREAD_MUTEX_INITIALIZER;
  48. static bool gErrorTriggered = false;
  49. static int ildaeilErrorHandler(Display*, XErrorEvent*)
  50. {
  51. gErrorTriggered = true;
  52. return 0;
  53. }
  54. #endif
  55. struct PluginHostWindow::PrivateData
  56. {
  57. Window& parentWindow;
  58. const uintptr_t parentWindowId;
  59. Callbacks* const pluginWindowCallbacks;
  60. #if defined(DISTRHO_OS_HAIKU)
  61. #elif defined(DISTRHO_OS_MAC)
  62. IldaeilPluginView* view;
  63. #elif defined(DISTRHO_OS_WINDOWS)
  64. ::HWND pluginWindow;
  65. #else
  66. ::Display* display;
  67. ::Window pluginWindow;
  68. #endif
  69. uint xOffset, yOffset;
  70. bool lookingForChildren;
  71. PrivateData(Window& pw, Callbacks* const cbs)
  72. : parentWindow(pw),
  73. parentWindowId(pw.getNativeWindowHandle()),
  74. pluginWindowCallbacks(cbs),
  75. #if defined(DISTRHO_OS_HAIKU)
  76. #elif defined(DISTRHO_OS_MAC)
  77. view(nullptr),
  78. #elif defined(DISTRHO_OS_WINDOWS)
  79. pluginWindow(nullptr),
  80. #else
  81. display(nullptr),
  82. pluginWindow(0),
  83. #endif
  84. xOffset(0),
  85. yOffset(0),
  86. lookingForChildren(false)
  87. {
  88. #if defined(DISTRHO_OS_HAIKU)
  89. #elif defined(DISTRHO_OS_MAC)
  90. view = [[IldaeilPluginView new]retain];
  91. DISTRHO_SAFE_ASSERT_RETURN(view != nullptr,)
  92. [view setAutoresizingMask:NSViewNotSizable];
  93. [view setAutoresizesSubviews:YES];
  94. [view setHidden:YES];
  95. [(NSView*)parentWindowId addSubview:view];
  96. #elif defined(DISTRHO_OS_WINDOWS)
  97. #else
  98. display = XOpenDisplay(nullptr);
  99. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr,)
  100. #endif
  101. }
  102. ~PrivateData()
  103. {
  104. #if defined(DISTRHO_OS_HAIKU)
  105. #elif defined(DISTRHO_OS_MAC)
  106. if (view != nullptr)
  107. [view release];
  108. #elif defined(DISTRHO_OS_WINDOWS)
  109. #else
  110. if (display != nullptr)
  111. XCloseDisplay(display);
  112. #endif
  113. }
  114. void* attachAndGetWindowHandle()
  115. {
  116. lookingForChildren = true;
  117. #if defined(DISTRHO_OS_HAIKU)
  118. return nullptr;
  119. #elif defined(DISTRHO_OS_MAC)
  120. return view;
  121. #elif defined(DISTRHO_OS_WINDOWS)
  122. pluginWindow = nullptr;
  123. return (void*)parentWindowId;
  124. #else
  125. pluginWindow = 0;
  126. return (void*)parentWindowId;
  127. #endif
  128. }
  129. void hide()
  130. {
  131. #if defined(DISTRHO_OS_HAIKU)
  132. #elif defined(DISTRHO_OS_MAC)
  133. if (view != nullptr)
  134. [view setHidden:YES];
  135. [NSOpenGLContext clearCurrentContext];
  136. #elif defined(DISTRHO_OS_WINDOWS)
  137. if (pluginWindow != nullptr)
  138. {
  139. ShowWindow(pluginWindow, SW_HIDE);
  140. pluginWindow = nullptr;
  141. }
  142. #else
  143. pluginWindow = 0;
  144. #endif
  145. }
  146. void idle()
  147. {
  148. if (lookingForChildren)
  149. {
  150. #if defined(DISTRHO_OS_HAIKU)
  151. #elif defined(DISTRHO_OS_MAC)
  152. if (view == nullptr)
  153. return;
  154. for (NSView* subview in [view subviews])
  155. {
  156. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  157. const NSSize size = [subview frame].size;
  158. const double width = size.width;
  159. const double height = size.height;
  160. if (width <= 1 || height <= 1)
  161. break;
  162. lookingForChildren = false;
  163. [view setFrameSize:size];
  164. [view setHidden:NO];
  165. [view setNeedsDisplay:YES];
  166. pluginWindowCallbacks->pluginWindowResized(width * scaleFactor, height * scaleFactor);
  167. break;
  168. }
  169. #elif defined(DISTRHO_OS_WINDOWS)
  170. if (pluginWindow == nullptr)
  171. pluginWindow = FindWindowExA((::HWND)parentWindowId, nullptr, nullptr, nullptr);
  172. if (pluginWindow != nullptr)
  173. {
  174. int width = 0;
  175. int height = 0;
  176. RECT rect;
  177. if (GetWindowRect(pluginWindow, &rect))
  178. {
  179. width = rect.right - rect.left;
  180. height = rect.bottom - rect.top;
  181. }
  182. d_stdout("child window bounds %u %u | offset %u %u", width, height, xOffset, yOffset);
  183. if (width > 1 && height > 1)
  184. {
  185. lookingForChildren = false;
  186. SetWindowPos(pluginWindow, 0, xOffset, yOffset, 0, 0,
  187. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  188. pluginWindowCallbacks->pluginWindowResized(width, height);
  189. }
  190. }
  191. #else
  192. if (pluginWindow == 0)
  193. {
  194. ::Window rootWindow, parentWindow;
  195. ::Window* childWindows = nullptr;
  196. uint numChildren = 0;
  197. XQueryTree(display, parentWindowId, &rootWindow, &parentWindow, &childWindows, &numChildren);
  198. if (numChildren > 0 && childWindows != nullptr)
  199. {
  200. pluginWindow = childWindows[0];
  201. XFree(childWindows);
  202. }
  203. }
  204. if (pluginWindow != 0)
  205. {
  206. int width = 0;
  207. int height = 0;
  208. XWindowAttributes attrs;
  209. memset(&attrs, 0, sizeof(attrs));
  210. pthread_mutex_lock(&gErrorMutex);
  211. const XErrorHandler oldErrorHandler = XSetErrorHandler(ildaeilErrorHandler);
  212. gErrorTriggered = false;
  213. if (XGetWindowAttributes(display, pluginWindow, &attrs) && ! gErrorTriggered)
  214. {
  215. width = attrs.width;
  216. height = attrs.height;
  217. }
  218. XSetErrorHandler(oldErrorHandler);
  219. pthread_mutex_unlock(&gErrorMutex);
  220. if (width == 0 && height == 0)
  221. {
  222. XSizeHints sizeHints;
  223. memset(&sizeHints, 0, sizeof(sizeHints));
  224. if (XGetNormalHints(display, pluginWindow, &sizeHints))
  225. {
  226. if (sizeHints.flags & PSize)
  227. {
  228. width = sizeHints.width;
  229. height = sizeHints.height;
  230. }
  231. else if (sizeHints.flags & PBaseSize)
  232. {
  233. width = sizeHints.base_width;
  234. height = sizeHints.base_height;
  235. }
  236. }
  237. }
  238. d_stdout("child window bounds %u %u | offset %u %u", width, height, xOffset, yOffset);
  239. if (width > 1 && height > 1)
  240. {
  241. lookingForChildren = false;
  242. XMoveWindow(display, pluginWindow, xOffset, yOffset);
  243. pluginWindowCallbacks->pluginWindowResized(width, height);
  244. }
  245. }
  246. #endif
  247. }
  248. #ifdef ILDAEIL_X11
  249. for (XEvent event; XPending(display) > 0;)
  250. XNextEvent(display, &event);
  251. #endif
  252. }
  253. void setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  254. {
  255. #if defined(DISTRHO_OS_HAIKU)
  256. #elif defined(DISTRHO_OS_MAC)
  257. if (view != nullptr)
  258. {
  259. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  260. [view setFrame:NSMakeRect(x / scaleFactor, y / scaleFactor, width / scaleFactor, height / scaleFactor)];
  261. }
  262. #elif defined(DISTRHO_OS_WINDOWS)
  263. // unused
  264. (void)width;
  265. (void)height;
  266. #else
  267. // unused
  268. (void)width;
  269. (void)height;
  270. #endif
  271. xOffset = x;
  272. yOffset = y;
  273. }
  274. };
  275. PluginHostWindow::PluginHostWindow(Window& parentWindow, Callbacks* const cbs)
  276. : pData(new PrivateData(parentWindow, cbs)) {}
  277. PluginHostWindow::~PluginHostWindow()
  278. {
  279. delete pData;
  280. }
  281. void* PluginHostWindow::attachAndGetWindowHandle()
  282. {
  283. return pData->attachAndGetWindowHandle();
  284. }
  285. void PluginHostWindow::hide()
  286. {
  287. pData->hide();
  288. }
  289. void PluginHostWindow::idle()
  290. {
  291. pData->idle();
  292. }
  293. void PluginHostWindow::setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  294. {
  295. pData->setPositionAndSize(x, y, width, height);
  296. }
  297. END_NAMESPACE_DGL