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.

347 lines
9.5KB

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