DISTRHO Plugin Framework
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.

498 lines
15KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "pugl.hpp"
  17. /* we will include all header files used in pugl in their C++ friendly form, then pugl stuff in custom namespace */
  18. #include <cassert>
  19. #include <cmath>
  20. #include <cstdlib>
  21. #include <cstring>
  22. #include <ctime>
  23. #if defined(DISTRHO_OS_HAIKU)
  24. #elif defined(DISTRHO_OS_MAC)
  25. # import <Cocoa/Cocoa.h>
  26. # include <dlfcn.h>
  27. # include <mach/mach_time.h>
  28. # ifdef DGL_CAIRO
  29. # include <cairo.h>
  30. # include <cairo-quartz.h>
  31. # endif
  32. # ifdef DGL_OPENGL
  33. # include <OpenGL/gl.h>
  34. # endif
  35. # ifdef DGL_VULKAN
  36. # import <QuartzCore/CAMetalLayer.h>
  37. # include <vulkan/vulkan_core.h>
  38. # include <vulkan/vulkan_macos.h>
  39. # endif
  40. #elif defined(DISTRHO_OS_WINDOWS)
  41. # include <wctype.h>
  42. # include <windows.h>
  43. # include <windowsx.h>
  44. # ifdef DGL_CAIRO
  45. # include <cairo.h>
  46. # include <cairo-win32.h>
  47. # endif
  48. # ifdef DGL_OPENGL
  49. # include <GL/gl.h>
  50. # endif
  51. # ifdef DGL_VULKAN
  52. # include <vulkan/vulkan.h>
  53. # include <vulkan/vulkan_win32.h>
  54. # endif
  55. #else
  56. # include <dlfcn.h>
  57. # include <sys/select.h>
  58. # include <sys/time.h>
  59. # include <X11/X.h>
  60. # include <X11/Xatom.h>
  61. # include <X11/Xlib.h>
  62. # include <X11/Xutil.h>
  63. # include <X11/keysym.h>
  64. # ifdef HAVE_XCURSOR
  65. # include <X11/Xcursor/Xcursor.h>
  66. # include <X11/cursorfont.h>
  67. # endif
  68. # ifdef HAVE_XRANDR
  69. # include <X11/extensions/Xrandr.h>
  70. # endif
  71. # ifdef HAVE_XSYNC
  72. # include <X11/extensions/sync.h>
  73. # include <X11/extensions/syncconst.h>
  74. # endif
  75. # ifdef DGL_CAIRO
  76. # include <cairo.h>
  77. # include <cairo-xlib.h>
  78. # endif
  79. # ifdef DGL_OPENGL
  80. # include <GL/gl.h>
  81. # include <GL/glx.h>
  82. # endif
  83. # ifdef DGL_VULKAN
  84. # include <vulkan/vulkan_core.h>
  85. # include <vulkan/vulkan_xlib.h>
  86. # endif
  87. #endif
  88. #ifdef HAVE_X11
  89. # define DBLCLKTME 400
  90. # include "sofd/libsofd.h"
  91. # include "sofd/libsofd.c"
  92. #endif
  93. #ifndef DISTRHO_OS_MAC
  94. START_NAMESPACE_DGL
  95. #endif
  96. // --------------------------------------------------------------------------------------------------------------------
  97. #if defined(DISTRHO_OS_HAIKU)
  98. #elif defined(DISTRHO_OS_MAC)
  99. # ifndef DISTRHO_MACOS_NAMESPACE_MACRO
  100. # define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, INTERFACE) NS ## SEP ## INTERFACE
  101. # define DISTRHO_MACOS_NAMESPACE_MACRO(NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, INTERFACE)
  102. # define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglStubView)
  103. # define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWrapperView)
  104. # define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindow)
  105. # endif
  106. # import "pugl-upstream/src/mac.m"
  107. # import "pugl-upstream/src/mac_stub.m"
  108. # ifdef DGL_CAIRO
  109. # import "pugl-upstream/src/mac_cairo.m"
  110. # endif
  111. # ifdef DGL_OPENGL
  112. # import "pugl-upstream/src/mac_gl.m"
  113. # endif
  114. # ifdef DGL_VULKAN
  115. # import "pugl-upstream/src/mac_vulkan.m"
  116. # endif
  117. #elif defined(DISTRHO_OS_WINDOWS)
  118. # include "pugl-upstream/src/win.c"
  119. # include "pugl-upstream/src/win_stub.c"
  120. # ifdef DGL_CAIRO
  121. # include "pugl-upstream/src/win_cairo.c"
  122. # endif
  123. # ifdef DGL_OPENGL
  124. # include "pugl-upstream/src/win_gl.c"
  125. # endif
  126. # ifdef DGL_VULKAN
  127. # include "pugl-upstream/src/win_vulkan.c"
  128. # endif
  129. #else
  130. # include "pugl-upstream/src/x11.c"
  131. # include "pugl-upstream/src/x11_stub.c"
  132. # ifdef DGL_CAIRO
  133. # include "pugl-upstream/src/x11_cairo.c"
  134. # endif
  135. # ifdef DGL_OPENGL
  136. # include "pugl-upstream/src/x11_gl.c"
  137. # endif
  138. # ifdef DGL_VULKAN
  139. # include "pugl-upstream/src/x11_vulkan.c"
  140. # endif
  141. #endif
  142. #include "pugl-upstream/src/implementation.c"
  143. // --------------------------------------------------------------------------------------------------------------------
  144. // expose backend enter
  145. void puglBackendEnter(PuglView* const view)
  146. {
  147. view->backend->enter(view, NULL);
  148. }
  149. // --------------------------------------------------------------------------------------------------------------------
  150. // clear minimum size to 0
  151. void puglClearMinSize(PuglView* const view)
  152. {
  153. view->minWidth = 0;
  154. view->minHeight = 0;
  155. }
  156. // --------------------------------------------------------------------------------------------------------------------
  157. // missing in pugl, directly returns title char* pointer
  158. const char* puglGetWindowTitle(const PuglView* view)
  159. {
  160. return view->title;
  161. }
  162. // --------------------------------------------------------------------------------------------------------------------
  163. // bring view window into the foreground, aka "raise" window
  164. void puglRaiseWindow(PuglView* view)
  165. {
  166. #if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC)
  167. // nothing here yet
  168. #elif defined(DISTRHO_OS_WINDOWS)
  169. SetForegroundWindow(view->impl->hwnd);
  170. SetActiveWindow(view->impl->hwnd);
  171. #else
  172. XRaiseWindow(view->impl->display, view->impl->win);
  173. #endif
  174. }
  175. // --------------------------------------------------------------------------------------------------------------------
  176. // set backend that matches current build
  177. void puglSetMatchingBackendForCurrentBuild(PuglView* const view)
  178. {
  179. #ifdef DGL_CAIRO
  180. puglSetBackend(view, puglCairoBackend());
  181. #endif
  182. #ifdef DGL_OPENGL
  183. puglSetBackend(view, puglGlBackend());
  184. #endif
  185. #ifdef DGL_VULKAN
  186. puglSetBackend(view, puglVulkanBackend());
  187. #endif
  188. if (view->backend == nullptr)
  189. puglSetBackend(view, puglStubBackend());
  190. }
  191. // --------------------------------------------------------------------------------------------------------------------
  192. // Combine puglSetMinSize and puglSetAspectRatio
  193. PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect)
  194. {
  195. view->minWidth = (int)width;
  196. view->minHeight = (int)height;
  197. if (aspect) {
  198. view->minAspectX = (int)width;
  199. view->minAspectY = (int)height;
  200. view->maxAspectX = (int)width;
  201. view->maxAspectY = (int)height;
  202. }
  203. #if defined(DISTRHO_OS_HAIKU)
  204. // nothing?
  205. #elif defined(DISTRHO_OS_MAC)
  206. /*
  207. if (view->impl->window)
  208. {
  209. [view->impl->window setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)];
  210. if (aspect)
  211. [view->impl->window setContentAspectRatio:sizePoints(view, view->minAspectX, view->minAspectY)];
  212. }
  213. */
  214. puglSetMinSize(view, width, height);
  215. puglSetAspectRatio(view, width, height, width, height);
  216. #elif defined(DISTRHO_OS_WINDOWS)
  217. // nothing
  218. #else
  219. if (const PuglStatus status = updateSizeHints(view))
  220. return status;
  221. XFlush(view->impl->display);
  222. #endif
  223. return PUGL_SUCCESS;
  224. }
  225. // --------------------------------------------------------------------------------------------------------------------
  226. // set window size with default size and without changing frame x/y position
  227. PuglStatus puglSetWindowSize(PuglView* const view, const uint width, const uint height)
  228. {
  229. view->defaultWidth = width;
  230. view->defaultHeight = height;
  231. #if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC)
  232. // keep upstream behaviour
  233. const PuglRect frame = { view->frame.x, view->frame.y, (double)width, (double)height };
  234. return puglSetFrame(view, frame);
  235. #elif defined(DISTRHO_OS_WINDOWS)
  236. // matches upstream pugl, except we add SWP_NOMOVE flag
  237. if (view->impl->hwnd)
  238. {
  239. const PuglRect frame = view->frame;
  240. RECT rect = { (long)frame.x,
  241. (long)frame.y,
  242. (long)frame.x + (long)frame.width,
  243. (long)frame.y + (long)frame.height };
  244. AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view));
  245. if (! SetWindowPos(view->impl->hwnd,
  246. HWND_TOP,
  247. rect.left,
  248. rect.top,
  249. rect.right - rect.left,
  250. rect.bottom - rect.top,
  251. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER))
  252. return PUGL_UNKNOWN_ERROR;
  253. }
  254. #else
  255. // matches upstream pugl, except we use XResizeWindow instead of XMoveResizeWindow
  256. if (view->impl->win)
  257. {
  258. Display* const display = view->impl->display;
  259. if (! XResizeWindow(display, view->impl->win, width, height))
  260. return PUGL_UNKNOWN_ERROR;
  261. #if 0
  262. // custom handling for embed non-resizable windows
  263. if (view->parent != 0 && ! view->hints[PUGL_RESIZABLE])
  264. {
  265. XSizeHints sizeHints = {};
  266. sizeHints.flags = PSize | PBaseSize | PMinSize | PMaxSize;
  267. sizeHints.width = static_cast<int>(width);
  268. sizeHints.height = static_cast<int>(height);
  269. sizeHints.base_width = width;
  270. sizeHints.base_height = height;
  271. sizeHints.min_width = width;
  272. sizeHints.min_height = height;
  273. sizeHints.max_width = width;
  274. sizeHints.max_height = height;
  275. XSetNormalHints(display, view->impl->win, &sizeHints);
  276. }
  277. #endif
  278. if (const PuglStatus status = updateSizeHints(view))
  279. return status;
  280. XFlush(display);
  281. }
  282. #endif
  283. view->frame.width = width;
  284. view->frame.height = height;
  285. return PUGL_SUCCESS;
  286. }
  287. // --------------------------------------------------------------------------------------------------------------------
  288. // DGL specific, build-specific drawing prepare
  289. void puglOnDisplayPrepare(PuglView*)
  290. {
  291. #ifdef DGL_OPENGL
  292. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  293. glLoadIdentity();
  294. #endif
  295. }
  296. // --------------------------------------------------------------------------------------------------------------------
  297. // DGL specific, build-specific fallback resize
  298. void puglFallbackOnResize(PuglView* const view)
  299. {
  300. #ifdef DGL_OPENGL
  301. glEnable(GL_BLEND);
  302. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  303. glMatrixMode(GL_PROJECTION);
  304. glLoadIdentity();
  305. glOrtho(0.0, static_cast<GLdouble>(view->frame.width), static_cast<GLdouble>(view->frame.height), 0.0, 0.0, 1.0);
  306. glViewport(0, 0, static_cast<GLsizei>(view->frame.width), static_cast<GLsizei>(view->frame.height));
  307. glMatrixMode(GL_MODELVIEW);
  308. glLoadIdentity();
  309. #endif
  310. }
  311. #ifdef DISTRHO_OS_WINDOWS
  312. // --------------------------------------------------------------------------------------------------------------------
  313. // win32 specific, call ShowWindow with SW_RESTORE
  314. void puglWin32RestoreWindow(PuglView* const view)
  315. {
  316. PuglInternals* impl = view->impl;
  317. DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,);
  318. ShowWindow(impl->hwnd, SW_RESTORE);
  319. SetFocus(impl->hwnd);
  320. }
  321. // --------------------------------------------------------------------------------------------------------------------
  322. // win32 specific, center view based on parent coordinates (if there is one)
  323. void puglWin32ShowWindowCentered(PuglView* const view)
  324. {
  325. PuglInternals* impl = view->impl;
  326. DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,);
  327. RECT rectChild, rectParent;
  328. if (view->transientParent != 0 &&
  329. GetWindowRect(impl->hwnd, &rectChild) &&
  330. GetWindowRect((HWND)view->transientParent, &rectParent))
  331. {
  332. SetWindowPos(impl->hwnd, (HWND)view->transientParent,
  333. rectParent.left + (rectChild.right-rectChild.left)/2,
  334. rectParent.top + (rectChild.bottom-rectChild.top)/2,
  335. 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
  336. }
  337. else
  338. {
  339. ShowWindow(impl->hwnd, SW_SHOWNORMAL);
  340. }
  341. SetFocus(impl->hwnd);
  342. }
  343. // --------------------------------------------------------------------------------------------------------------------
  344. // win32 specific, set or unset WS_SIZEBOX style flag
  345. void puglWin32SetWindowResizable(PuglView* const view, const bool resizable)
  346. {
  347. PuglInternals* impl = view->impl;
  348. DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,);
  349. const int winFlags = resizable ? GetWindowLong(impl->hwnd, GWL_STYLE) | WS_SIZEBOX
  350. : GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX;
  351. SetWindowLong(impl->hwnd, GWL_STYLE, winFlags);
  352. }
  353. // --------------------------------------------------------------------------------------------------------------------
  354. #endif
  355. #ifdef HAVE_X11
  356. // --------------------------------------------------------------------------------------------------------------------
  357. // X11 specific, setup event loop filter for sofd file dialog
  358. static bool sofd_has_action;
  359. static char* sofd_filename;
  360. static bool sofd_event_filter(Display* const display, XEvent* const xevent)
  361. {
  362. if (x_fib_handle_events(display, xevent) == 0)
  363. return false;
  364. if (sofd_filename != nullptr)
  365. std::free(sofd_filename);
  366. if (x_fib_status() > 0)
  367. sofd_filename = x_fib_filename();
  368. else
  369. sofd_filename = nullptr;
  370. x_fib_close(display);
  371. sofd_has_action = true;
  372. return true;
  373. }
  374. void sofdFileDialogSetup(PuglWorld* const world)
  375. {
  376. puglX11SetEventFilter(world, sofd_event_filter);
  377. }
  378. // --------------------------------------------------------------------------------------------------------------------
  379. // X11 specific, show file dialog via sofd
  380. bool sofdFileDialogShow(PuglView* const view,
  381. const char* const startDir, const char* const title,
  382. const uint flags, const uint width, const uint height)
  383. {
  384. DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false);
  385. DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false);
  386. /*
  387. x_fib_cfg_buttons(3, options.buttons.listAllFiles-1);
  388. x_fib_cfg_buttons(1, options.buttons.showHidden-1);
  389. x_fib_cfg_buttons(2, options.buttons.showPlaces-1);
  390. */
  391. PuglInternals* const impl = view->impl;
  392. return (x_fib_show(impl->display, impl->win, width, height) == 0);
  393. }
  394. // --------------------------------------------------------------------------------------------------------------------
  395. // X11 specific, close sofd file dialog
  396. void sofdFileDialogClose(PuglView* const view)
  397. {
  398. PuglInternals* const impl = view->impl;
  399. x_fib_close(impl->display);
  400. }
  401. // --------------------------------------------------------------------------------------------------------------------
  402. // X11 specific, get path chosen via sofd file dialog
  403. bool sofdFileDialogGetPath(char** path)
  404. {
  405. if (! sofd_has_action)
  406. return false;
  407. sofd_has_action = false;
  408. *path = sofd_filename;
  409. return true;
  410. }
  411. // --------------------------------------------------------------------------------------------------------------------
  412. // X11 specific, free path of sofd file dialog, no longer needed
  413. void sofdFileDialogFree(char* const path)
  414. {
  415. DISTRHO_SAFE_ASSERT_RETURN(path == nullptr || path == sofd_filename,);
  416. std::free(sofd_filename);
  417. sofd_filename = nullptr;
  418. }
  419. // --------------------------------------------------------------------------------------------------------------------
  420. #endif
  421. // --------------------------------------------------------------------------------------------------------------------
  422. #ifndef DISTRHO_OS_MAC
  423. END_NAMESPACE_DGL
  424. #endif