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.

371 lines
10KB

  1. /*
  2. * DISTRHO Ildaeil Plugin
  3. * Copyright (C) 2021-2024 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* pluginView;
  54. #elif defined(DISTRHO_OS_WASM)
  55. #elif defined(DISTRHO_OS_WINDOWS)
  56. ::HWND pluginWindow;
  57. #else
  58. ::Display* display;
  59. ::Window pluginWindow;
  60. #endif
  61. uint xOffset, yOffset;
  62. bool lookingForChildren;
  63. PrivateData(Window& pw, Callbacks* const cbs)
  64. : parentWindow(pw),
  65. parentWindowId(pw.getNativeWindowHandle()),
  66. pluginWindowCallbacks(cbs),
  67. #if defined(DISTRHO_OS_HAIKU)
  68. #elif defined(DISTRHO_OS_MAC)
  69. pluginView(nullptr),
  70. #elif defined(DISTRHO_OS_WASM)
  71. #elif defined(DISTRHO_OS_WINDOWS)
  72. pluginWindow(nullptr),
  73. #else
  74. display(nullptr),
  75. pluginWindow(0),
  76. #endif
  77. xOffset(0),
  78. yOffset(0),
  79. lookingForChildren(false)
  80. {
  81. #if defined(DISTRHO_OS_HAIKU)
  82. #elif defined(DISTRHO_OS_MAC)
  83. #elif defined(DISTRHO_OS_WASM)
  84. #elif defined(DISTRHO_OS_WINDOWS)
  85. #else
  86. display = XOpenDisplay(nullptr);
  87. DISTRHO_SAFE_ASSERT_RETURN(display != nullptr,)
  88. #endif
  89. }
  90. ~PrivateData()
  91. {
  92. #if defined(DISTRHO_OS_HAIKU)
  93. #elif defined(DISTRHO_OS_MAC)
  94. #elif defined(DISTRHO_OS_WASM)
  95. #elif defined(DISTRHO_OS_WINDOWS)
  96. #else
  97. if (display != nullptr)
  98. XCloseDisplay(display);
  99. #endif
  100. }
  101. void* attachAndGetWindowHandle()
  102. {
  103. lookingForChildren = true;
  104. #if defined(DISTRHO_OS_HAIKU)
  105. return nullptr;
  106. #elif defined(DISTRHO_OS_MAC)
  107. pluginView = nullptr;
  108. return (void*)parentWindowId;
  109. #elif defined(DISTRHO_OS_WASM)
  110. return nullptr;
  111. #elif defined(DISTRHO_OS_WINDOWS)
  112. pluginWindow = nullptr;
  113. return (void*)parentWindowId;
  114. #else
  115. pluginWindow = 0;
  116. return (void*)parentWindowId;
  117. #endif
  118. }
  119. bool hide()
  120. {
  121. #if defined(DISTRHO_OS_HAIKU)
  122. #elif defined(DISTRHO_OS_MAC)
  123. if (pluginView != nullptr)
  124. {
  125. [pluginView setHidden:YES];
  126. pluginView = nullptr;
  127. [NSOpenGLContext clearCurrentContext];
  128. return true;
  129. }
  130. #elif defined(DISTRHO_OS_WASM)
  131. #elif defined(DISTRHO_OS_WINDOWS)
  132. if (pluginWindow != nullptr)
  133. {
  134. ShowWindow(pluginWindow, SW_HIDE);
  135. pluginWindow = nullptr;
  136. return true;
  137. }
  138. #else
  139. if (pluginWindow != 0)
  140. {
  141. XUnmapWindow(display, pluginWindow);
  142. XSync(display, True);
  143. pluginWindow = 0;
  144. return true;
  145. }
  146. #endif
  147. return false;
  148. }
  149. void idle()
  150. {
  151. if (lookingForChildren)
  152. {
  153. #if defined(DISTRHO_OS_HAIKU)
  154. #elif defined(DISTRHO_OS_MAC)
  155. if (pluginView == nullptr)
  156. {
  157. bool first = true;
  158. for (NSView* view in [(NSView*)parentWindowId subviews])
  159. {
  160. if (first)
  161. {
  162. first = false;
  163. continue;
  164. }
  165. pluginView = view;
  166. break;
  167. }
  168. }
  169. #elif defined(DISTRHO_OS_WASM)
  170. #elif defined(DISTRHO_OS_WINDOWS)
  171. if (pluginWindow == nullptr)
  172. pluginWindow = FindWindowExA((::HWND)parentWindowId, nullptr, nullptr, nullptr);
  173. #else
  174. if (display == nullptr)
  175. return;
  176. if (pluginWindow == 0)
  177. {
  178. ::Window rootWindow, parentWindow;
  179. ::Window* childWindows = nullptr;
  180. uint numChildren = 0;
  181. XQueryTree(display, parentWindowId, &rootWindow, &parentWindow, &childWindows, &numChildren);
  182. if (numChildren > 0 && childWindows != nullptr)
  183. {
  184. // pick last child, needed for NTK based UIs which do not delete/remove previous windows.
  185. //sadly this breaks ildaeil-within-ildaeil recursion.. :(
  186. pluginWindow = childWindows[numChildren - 1];
  187. XFree(childWindows);
  188. }
  189. }
  190. #endif
  191. }
  192. #if defined(DISTRHO_OS_HAIKU)
  193. #elif defined(DISTRHO_OS_MAC)
  194. if (pluginView != nullptr)
  195. {
  196. const double scaleFactor = [[[pluginView window] screen] backingScaleFactor];
  197. const NSSize size = [pluginView frame].size;
  198. const double width = size.width;
  199. const double height = size.height;
  200. if (lookingForChildren)
  201. d_stdout("child window bounds %f %f | offset %u %u", width, height, xOffset, yOffset);
  202. if (width > 1.0 && height > 1.0)
  203. {
  204. lookingForChildren = false;
  205. [pluginView setFrameOrigin:NSMakePoint(xOffset / scaleFactor, yOffset / scaleFactor)];
  206. [pluginView setNeedsDisplay:YES];
  207. pluginWindowCallbacks->pluginWindowResized(width * scaleFactor, height * scaleFactor);
  208. }
  209. }
  210. #elif defined(DISTRHO_OS_WASM)
  211. #elif defined(DISTRHO_OS_WINDOWS)
  212. if (pluginWindow != nullptr)
  213. {
  214. int width = 0;
  215. int height = 0;
  216. RECT rect;
  217. if (GetWindowRect(pluginWindow, &rect))
  218. {
  219. width = rect.right - rect.left;
  220. height = rect.bottom - rect.top;
  221. }
  222. if (lookingForChildren)
  223. d_stdout("child window bounds %i %i | offset %u %u", width, height, xOffset, yOffset);
  224. if (width > 1 && height > 1)
  225. {
  226. lookingForChildren = false;
  227. SetWindowPos(pluginWindow, 0, xOffset, yOffset, 0, 0,
  228. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  229. pluginWindowCallbacks->pluginWindowResized(width, height);
  230. }
  231. }
  232. #else
  233. for (XEvent event; XPending(display) > 0;)
  234. XNextEvent(display, &event);
  235. if (pluginWindow != 0)
  236. {
  237. int width = 0;
  238. int height = 0;
  239. XWindowAttributes attrs;
  240. memset(&attrs, 0, sizeof(attrs));
  241. pthread_mutex_lock(&gErrorMutex);
  242. const XErrorHandler oldErrorHandler = XSetErrorHandler(ildaeilErrorHandler);
  243. gErrorTriggered = false;
  244. if (XGetWindowAttributes(display, pluginWindow, &attrs) && ! gErrorTriggered)
  245. {
  246. width = attrs.width;
  247. height = attrs.height;
  248. }
  249. XSetErrorHandler(oldErrorHandler);
  250. pthread_mutex_unlock(&gErrorMutex);
  251. if (width == 0 && height == 0)
  252. {
  253. XSizeHints sizeHints;
  254. memset(&sizeHints, 0, sizeof(sizeHints));
  255. if (XGetNormalHints(display, pluginWindow, &sizeHints))
  256. {
  257. if (sizeHints.flags & PSize)
  258. {
  259. width = sizeHints.width;
  260. height = sizeHints.height;
  261. }
  262. else if (sizeHints.flags & PBaseSize)
  263. {
  264. width = sizeHints.base_width;
  265. height = sizeHints.base_height;
  266. }
  267. }
  268. }
  269. if (lookingForChildren)
  270. d_stdout("child window bounds %i %i | offset %u %u", width, height, xOffset, yOffset);
  271. if (width > 1 && height > 1)
  272. {
  273. lookingForChildren = false;
  274. XMoveWindow(display, pluginWindow, xOffset, yOffset);
  275. XSync(display, True);
  276. pluginWindowCallbacks->pluginWindowResized(width, height);
  277. }
  278. }
  279. #endif
  280. }
  281. void setOffset(const uint x, const uint y)
  282. {
  283. xOffset = x;
  284. yOffset = y;
  285. }
  286. void setSize(const uint width, const uint height)
  287. {
  288. #if defined(DISTRHO_OS_HAIKU)
  289. #elif defined(DISTRHO_OS_MAC)
  290. if (pluginView != nullptr)
  291. [pluginView setFrameSize:NSMakeSize(width, height)];
  292. #elif defined(DISTRHO_OS_WASM)
  293. #elif defined(DISTRHO_OS_WINDOWS)
  294. if (pluginWindow != nullptr)
  295. SetWindowPos(pluginWindow, 0, 0, 0, width, height,
  296. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  297. #else
  298. if (pluginWindow != 0)
  299. XResizeWindow(display, pluginWindow, width, height);
  300. #endif
  301. }
  302. };
  303. PluginHostWindow::PluginHostWindow(Window& parentWindow, Callbacks* const cbs)
  304. : pData(new PrivateData(parentWindow, cbs)) {}
  305. PluginHostWindow::~PluginHostWindow()
  306. {
  307. delete pData;
  308. }
  309. void* PluginHostWindow::attachAndGetWindowHandle()
  310. {
  311. return pData->attachAndGetWindowHandle();
  312. }
  313. bool PluginHostWindow::hide()
  314. {
  315. return pData->hide();
  316. }
  317. void PluginHostWindow::idle()
  318. {
  319. pData->idle();
  320. }
  321. void PluginHostWindow::setOffset(const uint x, const uint y)
  322. {
  323. pData->setOffset(x, y);
  324. }
  325. void PluginHostWindow::setSize(const uint width, const uint height)
  326. {
  327. pData->setSize(width, height);
  328. }
  329. END_NAMESPACE_DGL