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.

373 lines
10KB

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