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.

378 lines
11KB

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