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.

359 lines
9.8KB

  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. 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_WASM)
  137. #elif defined(DISTRHO_OS_WINDOWS)
  138. if (pluginWindow != nullptr)
  139. {
  140. ShowWindow(pluginWindow, SW_HIDE);
  141. pluginWindow = nullptr;
  142. }
  143. #else
  144. pluginWindow = 0;
  145. #endif
  146. }
  147. void idle()
  148. {
  149. if (lookingForChildren)
  150. {
  151. #if defined(DISTRHO_OS_HAIKU)
  152. #elif defined(DISTRHO_OS_MAC)
  153. if (view == nullptr)
  154. return;
  155. if (subview == nullptr)
  156. {
  157. for (NSView* subview2 in [view subviews])
  158. {
  159. subview = subview2;
  160. break;
  161. }
  162. }
  163. #elif defined(DISTRHO_OS_WINDOWS)
  164. if (pluginWindow == nullptr)
  165. pluginWindow = FindWindowExA((::HWND)parentWindowId, nullptr, nullptr, nullptr);
  166. #elif defined(DISTRHO_OS_WASM)
  167. #else
  168. if (display == nullptr)
  169. return;
  170. if (pluginWindow == 0)
  171. {
  172. ::Window rootWindow, parentWindow;
  173. ::Window* childWindows = nullptr;
  174. uint numChildren = 0;
  175. XQueryTree(display, parentWindowId, &rootWindow, &parentWindow, &childWindows, &numChildren);
  176. if (numChildren > 0 && childWindows != nullptr)
  177. {
  178. pluginWindow = childWindows[0];
  179. XFree(childWindows);
  180. }
  181. }
  182. #endif
  183. }
  184. #if defined(DISTRHO_OS_HAIKU)
  185. #elif defined(DISTRHO_OS_MAC)
  186. if (subview != nullptr)
  187. {
  188. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  189. const NSSize size = [subview frame].size;
  190. const double width = size.width;
  191. const double height = size.height;
  192. if (lookingForChildren)
  193. d_stdout("child window bounds %f %f | offset %u %u", width, height, xOffset, yOffset);
  194. if (width > 1.0 && height > 1.0)
  195. {
  196. lookingForChildren = false;
  197. [view setFrameSize:size];
  198. [view setHidden:NO];
  199. [view setNeedsDisplay:YES];
  200. pluginWindowCallbacks->pluginWindowResized(width * scaleFactor, height * scaleFactor);
  201. }
  202. }
  203. #elif defined(DISTRHO_OS_WASM)
  204. #elif defined(DISTRHO_OS_WINDOWS)
  205. if (pluginWindow != nullptr)
  206. {
  207. int width = 0;
  208. int height = 0;
  209. RECT rect;
  210. if (GetWindowRect(pluginWindow, &rect))
  211. {
  212. width = rect.right - rect.left;
  213. height = rect.bottom - rect.top;
  214. }
  215. if (lookingForChildren)
  216. d_stdout("child window bounds %i %i | offset %u %u", width, height, xOffset, yOffset);
  217. if (width > 1 && height > 1)
  218. {
  219. lookingForChildren = false;
  220. SetWindowPos(pluginWindow, 0, xOffset, yOffset, 0, 0,
  221. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  222. pluginWindowCallbacks->pluginWindowResized(width, height);
  223. }
  224. }
  225. #else
  226. if (pluginWindow != 0)
  227. {
  228. int width = 0;
  229. int height = 0;
  230. XWindowAttributes attrs;
  231. memset(&attrs, 0, sizeof(attrs));
  232. pthread_mutex_lock(&gErrorMutex);
  233. const XErrorHandler oldErrorHandler = XSetErrorHandler(ildaeilErrorHandler);
  234. gErrorTriggered = false;
  235. if (XGetWindowAttributes(display, pluginWindow, &attrs) && ! gErrorTriggered)
  236. {
  237. width = attrs.width;
  238. height = attrs.height;
  239. }
  240. XSetErrorHandler(oldErrorHandler);
  241. pthread_mutex_unlock(&gErrorMutex);
  242. if (width == 0 && height == 0)
  243. {
  244. XSizeHints sizeHints;
  245. memset(&sizeHints, 0, sizeof(sizeHints));
  246. if (XGetNormalHints(display, pluginWindow, &sizeHints))
  247. {
  248. if (sizeHints.flags & PSize)
  249. {
  250. width = sizeHints.width;
  251. height = sizeHints.height;
  252. }
  253. else if (sizeHints.flags & PBaseSize)
  254. {
  255. width = sizeHints.base_width;
  256. height = sizeHints.base_height;
  257. }
  258. }
  259. }
  260. if (lookingForChildren)
  261. d_stdout("child window bounds %i %i | offset %u %u", width, height, xOffset, yOffset);
  262. if (width > 1 && height > 1)
  263. {
  264. lookingForChildren = false;
  265. XMoveWindow(display, pluginWindow, xOffset, yOffset);
  266. pluginWindowCallbacks->pluginWindowResized(width, height);
  267. }
  268. }
  269. for (XEvent event; XPending(display) > 0;)
  270. XNextEvent(display, &event);
  271. #endif
  272. }
  273. void setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  274. {
  275. #if defined(DISTRHO_OS_HAIKU)
  276. #elif defined(DISTRHO_OS_MAC)
  277. if (view != nullptr)
  278. {
  279. const double scaleFactor = [[[view window] screen] backingScaleFactor];
  280. [view setFrame:NSMakeRect(x / scaleFactor, y / scaleFactor, width / scaleFactor, height / scaleFactor)];
  281. }
  282. #elif defined(DISTRHO_OS_WASM)
  283. #elif defined(DISTRHO_OS_WINDOWS)
  284. // unused
  285. (void)width;
  286. (void)height;
  287. #else
  288. // unused
  289. (void)width;
  290. (void)height;
  291. #endif
  292. xOffset = x;
  293. yOffset = y;
  294. }
  295. };
  296. PluginHostWindow::PluginHostWindow(Window& parentWindow, Callbacks* const cbs)
  297. : pData(new PrivateData(parentWindow, cbs)) {}
  298. PluginHostWindow::~PluginHostWindow()
  299. {
  300. delete pData;
  301. }
  302. void* PluginHostWindow::attachAndGetWindowHandle()
  303. {
  304. return pData->attachAndGetWindowHandle();
  305. }
  306. void PluginHostWindow::hide()
  307. {
  308. pData->hide();
  309. }
  310. void PluginHostWindow::idle()
  311. {
  312. pData->idle();
  313. }
  314. void PluginHostWindow::setPositionAndSize(const uint x, const uint y, const uint width, const uint height)
  315. {
  316. pData->setPositionAndSize(x, y, width, height);
  317. }
  318. END_NAMESPACE_DGL