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.

587 lines
19KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2022 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. // --------------------------------------------------------------------------------------------------------------------
  18. // include base headers
  19. #ifdef DGL_CAIRO
  20. # include <cairo.h>
  21. #endif
  22. #ifdef DGL_OPENGL
  23. # include "../OpenGL-include.hpp"
  24. #endif
  25. #ifdef DGL_VULKAN
  26. # include <vulkan/vulkan_core.h>
  27. #endif
  28. /* we will include all header files used in pugl in their C++ friendly form, then pugl stuff in custom namespace */
  29. #include <cassert>
  30. #include <cmath>
  31. #include <cstdlib>
  32. #include <cstdio>
  33. #include <cstring>
  34. #include <ctime>
  35. #if defined(DISTRHO_OS_MAC)
  36. # import <Cocoa/Cocoa.h>
  37. # include <dlfcn.h>
  38. # include <mach/mach_time.h>
  39. # ifdef DGL_CAIRO
  40. # include <cairo-quartz.h>
  41. # endif
  42. # ifdef DGL_OPENGL
  43. # include <OpenGL/gl.h>
  44. # endif
  45. # ifdef DGL_VULKAN
  46. # import <QuartzCore/CAMetalLayer.h>
  47. # include <vulkan/vulkan_macos.h>
  48. # endif
  49. #elif defined(DISTRHO_OS_WINDOWS)
  50. # include <wctype.h>
  51. # include <winsock2.h>
  52. # include <windows.h>
  53. # include <windowsx.h>
  54. # ifdef DGL_CAIRO
  55. # include <cairo-win32.h>
  56. # endif
  57. # ifdef DGL_OPENGL
  58. # include <GL/gl.h>
  59. # endif
  60. # ifdef DGL_VULKAN
  61. # include <vulkan/vulkan.h>
  62. # include <vulkan/vulkan_win32.h>
  63. # endif
  64. #else
  65. # include <dlfcn.h>
  66. # include <limits.h>
  67. # include <unistd.h>
  68. # include <sys/select.h>
  69. // # include <sys/time.h>
  70. # include <X11/X.h>
  71. # include <X11/Xatom.h>
  72. # include <X11/Xlib.h>
  73. # include <X11/Xresource.h>
  74. # include <X11/Xutil.h>
  75. # include <X11/keysym.h>
  76. # ifdef HAVE_XCURSOR
  77. # include <X11/Xcursor/Xcursor.h>
  78. // # include <X11/cursorfont.h>
  79. # endif
  80. # ifdef HAVE_XRANDR
  81. # include <X11/extensions/Xrandr.h>
  82. # endif
  83. # ifdef HAVE_XSYNC
  84. # include <X11/extensions/sync.h>
  85. # include <X11/extensions/syncconst.h>
  86. # endif
  87. # ifdef DGL_CAIRO
  88. # include <cairo-xlib.h>
  89. # endif
  90. # ifdef DGL_OPENGL
  91. # include <GL/glx.h>
  92. # endif
  93. # ifdef DGL_VULKAN
  94. # include <vulkan/vulkan_xlib.h>
  95. # endif
  96. #endif
  97. #ifndef DGL_FILE_BROWSER_DISABLED
  98. # ifdef DISTRHO_OS_MAC
  99. # import "../../distrho/extra/FileBrowserDialog.cpp"
  100. # else
  101. # include "../../distrho/extra/FileBrowserDialog.cpp"
  102. # endif
  103. #endif
  104. #ifndef DISTRHO_OS_MAC
  105. START_NAMESPACE_DGL
  106. #endif
  107. // --------------------------------------------------------------------------------------------------------------------
  108. #if defined(DISTRHO_OS_MAC)
  109. # ifndef DISTRHO_MACOS_NAMESPACE_MACRO
  110. # define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, INTERFACE) NS ## SEP ## INTERFACE
  111. # define DISTRHO_MACOS_NAMESPACE_MACRO(NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, INTERFACE)
  112. # define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglStubView)
  113. # define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWrapperView)
  114. # define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindow)
  115. # endif
  116. # pragma clang diagnostic push
  117. # pragma clang diagnostic ignored "-Wdeprecated-declarations"
  118. # import "pugl-upstream/src/mac.m"
  119. # import "pugl-upstream/src/mac_stub.m"
  120. # ifdef DGL_CAIRO
  121. # import "pugl-upstream/src/mac_cairo.m"
  122. # endif
  123. # ifdef DGL_OPENGL
  124. # import "pugl-upstream/src/mac_gl.m"
  125. # endif
  126. # ifdef DGL_VULKAN
  127. # import "pugl-upstream/src/mac_vulkan.m"
  128. # endif
  129. # pragma clang diagnostic pop
  130. #elif defined(DISTRHO_OS_WINDOWS)
  131. # include "pugl-upstream/src/win.c"
  132. # include "pugl-upstream/src/win_stub.c"
  133. # ifdef DGL_CAIRO
  134. # include "pugl-upstream/src/win_cairo.c"
  135. # endif
  136. # ifdef DGL_OPENGL
  137. # include "pugl-upstream/src/win_gl.c"
  138. # endif
  139. # ifdef DGL_VULKAN
  140. # include "pugl-upstream/src/win_vulkan.c"
  141. # endif
  142. #else
  143. # include "pugl-upstream/src/x11.c"
  144. # include "pugl-upstream/src/x11_stub.c"
  145. # ifdef DGL_CAIRO
  146. # include "pugl-upstream/src/x11_cairo.c"
  147. # endif
  148. # ifdef DGL_OPENGL
  149. # include "pugl-upstream/src/x11_gl.c"
  150. # endif
  151. # ifdef DGL_VULKAN
  152. # include "pugl-upstream/src/x11_vulkan.c"
  153. # endif
  154. #endif
  155. #include "pugl-upstream/src/implementation.c"
  156. // --------------------------------------------------------------------------------------------------------------------
  157. // DGL specific, expose backend enter
  158. bool puglBackendEnter(PuglView* const view)
  159. {
  160. return view->backend->enter(view, nullptr) == PUGL_SUCCESS;
  161. }
  162. // --------------------------------------------------------------------------------------------------------------------
  163. // DGL specific, expose backend leave
  164. bool puglBackendLeave(PuglView* const view)
  165. {
  166. return view->backend->leave(view, nullptr) == PUGL_SUCCESS;
  167. }
  168. // --------------------------------------------------------------------------------------------------------------------
  169. // DGL specific, assigns backend that matches current DGL build
  170. void puglSetMatchingBackendForCurrentBuild(PuglView* const view)
  171. {
  172. #ifdef DGL_CAIRO
  173. puglSetBackend(view, puglCairoBackend());
  174. #endif
  175. #ifdef DGL_OPENGL
  176. puglSetBackend(view, puglGlBackend());
  177. #endif
  178. #ifdef DGL_VULKAN
  179. puglSetBackend(view, puglVulkanBackend());
  180. #endif
  181. if (view->backend == nullptr)
  182. puglSetBackend(view, puglStubBackend());
  183. }
  184. // --------------------------------------------------------------------------------------------------------------------
  185. // clear minimum size to 0
  186. // void puglClearMinSize(PuglView* const view)
  187. // {
  188. // view->sizeHints[PUGL_MIN_SIZE].width = 0;
  189. // view->sizeHints[PUGL_MIN_SIZE].height = 0;
  190. // }
  191. // --------------------------------------------------------------------------------------------------------------------
  192. // bring view window into the foreground, aka "raise" window
  193. void puglRaiseWindow(PuglView* const view)
  194. {
  195. #if defined(DISTRHO_OS_MAC)
  196. if (NSWindow* const window = view->impl->window ? view->impl->window
  197. : [view->impl->wrapperView window])
  198. [window orderFrontRegardless];
  199. #elif defined(DISTRHO_OS_WINDOWS)
  200. SetForegroundWindow(view->impl->hwnd);
  201. SetActiveWindow(view->impl->hwnd);
  202. #else
  203. XRaiseWindow(view->world->impl->display, view->impl->win);
  204. #endif
  205. }
  206. // --------------------------------------------------------------------------------------------------------------------
  207. // get scale factor from parent window if possible, fallback to puglGetScaleFactor
  208. double puglGetScaleFactorFromParent(const PuglView* const view)
  209. {
  210. const PuglNativeView parent = view->parent ? view->parent : view->transientParent ? view->transientParent : 0;
  211. #if defined(DISTRHO_OS_MAC)
  212. NSWindow* const window = parent != 0 ? [(NSView*)parent window]
  213. : view->impl->window ? view->impl->window : [view->impl->wrapperView window];
  214. NSScreen* const screen = window != nullptr ? [window screen] : [NSScreen mainScreen];
  215. return [screen backingScaleFactor];
  216. #elif defined(DISTRHO_OS_WINDOWS)
  217. const HWND hwnd = parent != 0 ? (HWND)parent : view->impl->hwnd;
  218. return puglWinGetViewScaleFactor(hwnd);
  219. #else
  220. return puglGetScaleFactor(view);
  221. // unused
  222. (void)parent;
  223. #endif
  224. }
  225. // --------------------------------------------------------------------------------------------------------------------
  226. // Combined puglSetSizeHint using PUGL_MIN_SIZE and PUGL_FIXED_ASPECT
  227. PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect)
  228. {
  229. view->sizeHints[PUGL_MIN_SIZE].width = width;
  230. view->sizeHints[PUGL_MIN_SIZE].height = height;
  231. if (aspect)
  232. {
  233. view->sizeHints[PUGL_FIXED_ASPECT].width = width;
  234. view->sizeHints[PUGL_FIXED_ASPECT].height = height;
  235. }
  236. #if defined(DISTRHO_OS_MAC)
  237. if (view->impl->window)
  238. {
  239. PuglStatus status;
  240. if ((status = updateSizeHint(view, PUGL_MIN_SIZE)) != PUGL_SUCCESS)
  241. return status;
  242. if (aspect && (status = updateSizeHint(view, PUGL_FIXED_ASPECT)) != PUGL_SUCCESS)
  243. return status;
  244. }
  245. #elif defined(DISTRHO_OS_WINDOWS)
  246. // nothing
  247. #else
  248. if (const PuglStatus status = updateSizeHints(view))
  249. return status;
  250. XFlush(view->world->impl->display);
  251. #endif
  252. return PUGL_SUCCESS;
  253. }
  254. // --------------------------------------------------------------------------------------------------------------------
  255. // set view as resizable (or not) during runtime
  256. void puglSetResizable(PuglView* const view, const bool resizable)
  257. {
  258. puglSetViewHint(view, PUGL_RESIZABLE, resizable ? PUGL_TRUE : PUGL_FALSE);
  259. #if defined(DISTRHO_OS_MAC)
  260. if (PuglWindow* const window = view->impl->window)
  261. {
  262. const uint style = (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask)
  263. | (resizable ? NSResizableWindowMask : 0x0);
  264. [window setStyleMask:style];
  265. }
  266. // FIXME use [view setAutoresizingMask:NSViewNotSizable] ?
  267. #elif defined(DISTRHO_OS_WINDOWS)
  268. if (const HWND hwnd = view->impl->hwnd)
  269. {
  270. const uint winFlags = resizable ? GetWindowLong(hwnd, GWL_STYLE) | (WS_SIZEBOX | WS_MAXIMIZEBOX)
  271. : GetWindowLong(hwnd, GWL_STYLE) & ~(WS_SIZEBOX | WS_MAXIMIZEBOX);
  272. SetWindowLong(hwnd, GWL_STYLE, winFlags);
  273. }
  274. #else
  275. updateSizeHints(view);
  276. #endif
  277. }
  278. // --------------------------------------------------------------------------------------------------------------------
  279. // set window size while also changing default
  280. PuglStatus puglSetSizeAndDefault(PuglView* view, uint width, uint height)
  281. {
  282. if (width > INT16_MAX || height > INT16_MAX)
  283. return PUGL_BAD_PARAMETER;
  284. view->sizeHints[PUGL_DEFAULT_SIZE].width = view->frame.width = static_cast<PuglSpan>(width);
  285. view->sizeHints[PUGL_DEFAULT_SIZE].height = view->frame.height = static_cast<PuglSpan>(height);
  286. #if defined(DISTRHO_OS_MAC)
  287. // mostly matches upstream pugl, simplified
  288. PuglInternals* const impl = view->impl;
  289. const PuglRect frame = view->frame;
  290. const NSRect framePx = rectToNsRect(frame);
  291. const NSRect framePt = nsRectToPoints(view, framePx);
  292. if (PuglWindow* const window = view->impl->window)
  293. {
  294. const NSRect screenPt = rectToScreen(viewScreen(view), framePt);
  295. const NSRect winFrame = [window frameRectForContentRect:screenPt];
  296. [window setFrame:winFrame display:NO];
  297. }
  298. const NSSize sizePx = NSMakeSize(frame.width, frame.height);
  299. const NSSize sizePt = [impl->drawView convertSizeFromBacking:sizePx];
  300. [impl->wrapperView setFrameSize:sizePt];
  301. [impl->drawView setFrameSize:sizePt];
  302. #elif defined(DISTRHO_OS_WINDOWS)
  303. // matches upstream pugl, except we re-enter context after resize
  304. if (const HWND hwnd = view->impl->hwnd)
  305. {
  306. const RECT rect = adjustedWindowRect(view, view->frame.x, view->frame.y,
  307. static_cast<long>(width), static_cast<long>(height));
  308. if (!SetWindowPos(hwnd, HWND_TOP, 0, 0, rect.right - rect.left, rect.bottom - rect.top,
  309. SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE))
  310. return PUGL_UNKNOWN_ERROR;
  311. // make sure to return context back to ourselves
  312. puglBackendEnter(view);
  313. }
  314. #else
  315. // matches upstream pugl, all in one
  316. if (const Window window = view->impl->win)
  317. {
  318. Display* const display = view->world->impl->display;
  319. if (! XResizeWindow(display, window, width, height))
  320. return PUGL_UNKNOWN_ERROR;
  321. if (const PuglStatus status = updateSizeHints(view))
  322. return status;
  323. XFlush(display);
  324. }
  325. #endif
  326. return PUGL_SUCCESS;
  327. }
  328. // --------------------------------------------------------------------------------------------------------------------
  329. // DGL specific, build-specific drawing prepare
  330. void puglOnDisplayPrepare(PuglView*)
  331. {
  332. #ifdef DGL_OPENGL
  333. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  334. glLoadIdentity();
  335. #endif
  336. }
  337. // --------------------------------------------------------------------------------------------------------------------
  338. // DGL specific, build-specific fallback resize
  339. void puglFallbackOnResize(PuglView* const view)
  340. {
  341. #ifdef DGL_OPENGL
  342. glEnable(GL_BLEND);
  343. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  344. glMatrixMode(GL_PROJECTION);
  345. glLoadIdentity();
  346. glOrtho(0.0, static_cast<GLdouble>(view->frame.width), static_cast<GLdouble>(view->frame.height), 0.0, 0.0, 1.0);
  347. glViewport(0, 0, static_cast<GLsizei>(view->frame.width), static_cast<GLsizei>(view->frame.height));
  348. glMatrixMode(GL_MODELVIEW);
  349. glLoadIdentity();
  350. #else
  351. return;
  352. // unused
  353. (void)view;
  354. #endif
  355. }
  356. #if defined(DISTRHO_OS_MAC)
  357. // --------------------------------------------------------------------------------------------------------------------
  358. // macOS specific, allow standalone window to gain focus
  359. void puglMacOSActivateApp()
  360. {
  361. [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
  362. [NSApp activateIgnoringOtherApps:YES];
  363. }
  364. // --------------------------------------------------------------------------------------------------------------------
  365. // macOS specific, add another view's window as child
  366. PuglStatus
  367. puglMacOSAddChildWindow(PuglView* const view, PuglView* const child)
  368. {
  369. if (NSWindow* const viewWindow = view->impl->window ? view->impl->window
  370. : [view->impl->wrapperView window])
  371. {
  372. if (NSWindow* const childWindow = child->impl->window ? child->impl->window
  373. : [child->impl->wrapperView window])
  374. {
  375. [viewWindow addChildWindow:childWindow ordered:NSWindowAbove];
  376. return PUGL_SUCCESS;
  377. }
  378. }
  379. return PUGL_FAILURE;
  380. }
  381. // --------------------------------------------------------------------------------------------------------------------
  382. // macOS specific, remove another view's window as child
  383. PuglStatus
  384. puglMacOSRemoveChildWindow(PuglView* const view, PuglView* const child)
  385. {
  386. if (NSWindow* const viewWindow = view->impl->window ? view->impl->window
  387. : [view->impl->wrapperView window])
  388. {
  389. if (NSWindow* const childWindow = child->impl->window ? child->impl->window
  390. : [child->impl->wrapperView window])
  391. {
  392. [viewWindow removeChildWindow:childWindow];
  393. return PUGL_SUCCESS;
  394. }
  395. }
  396. return PUGL_FAILURE;
  397. }
  398. // --------------------------------------------------------------------------------------------------------------------
  399. // macOS specific, center view based on parent coordinates (if there is one)
  400. void puglMacOSShowCentered(PuglView* const view)
  401. {
  402. if (puglShow(view) != PUGL_SUCCESS)
  403. return;
  404. if (view->transientParent != 0)
  405. {
  406. NSWindow* const transientWindow = [(NSView*)view->transientParent window];
  407. DISTRHO_SAFE_ASSERT_RETURN(transientWindow != nullptr,);
  408. const NSRect ourFrame = [view->impl->window frame];
  409. const NSRect transientFrame = [transientWindow frame];
  410. const int x = transientFrame.origin.x + (transientFrame.size.width - ourFrame.size.width) / 2;
  411. const int y = transientFrame.origin.y + (transientFrame.size.height - ourFrame.size.height) / 2;
  412. [view->impl->window setFrameTopLeftPoint:NSMakePoint(x, y)];
  413. }
  414. else
  415. {
  416. [view->impl->window center];
  417. }
  418. }
  419. // --------------------------------------------------------------------------------------------------------------------
  420. #elif defined(DISTRHO_OS_WINDOWS)
  421. // --------------------------------------------------------------------------------------------------------------------
  422. // win32 specific, call ShowWindow with SW_RESTORE
  423. void puglWin32RestoreWindow(PuglView* const view)
  424. {
  425. PuglInternals* impl = view->impl;
  426. DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,);
  427. ShowWindow(impl->hwnd, SW_RESTORE);
  428. SetFocus(impl->hwnd);
  429. }
  430. // --------------------------------------------------------------------------------------------------------------------
  431. // win32 specific, center view based on parent coordinates (if there is one)
  432. void puglWin32ShowCentered(PuglView* const view)
  433. {
  434. PuglInternals* impl = view->impl;
  435. DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,);
  436. RECT rectChild, rectParent;
  437. if (view->transientParent != 0 &&
  438. GetWindowRect(impl->hwnd, &rectChild) &&
  439. GetWindowRect((HWND)view->transientParent, &rectParent))
  440. {
  441. SetWindowPos(impl->hwnd, (HWND)view->transientParent,
  442. rectParent.left + (rectChild.right-rectChild.left)/2,
  443. rectParent.top + (rectChild.bottom-rectChild.top)/2,
  444. 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
  445. }
  446. else
  447. {
  448. #ifdef DGL_WINDOWS_ICON_ID
  449. WNDCLASSEX wClass;
  450. std::memset(&wClass, 0, sizeof(wClass));
  451. const HINSTANCE hInstance = GetModuleHandle(nullptr);
  452. if (GetClassInfoEx(hInstance, view->world->className, &wClass))
  453. wClass.hIcon = LoadIcon(nullptr, MAKEINTRESOURCE(DGL_WINDOWS_ICON_ID));
  454. SetClassLongPtr(impl->hwnd, GCLP_HICON, (LONG_PTR) LoadIcon(hInstance, MAKEINTRESOURCE(DGL_WINDOWS_ICON_ID)));
  455. #endif
  456. MONITORINFO mInfo;
  457. std::memset(&mInfo, 0, sizeof(mInfo));
  458. mInfo.cbSize = sizeof(mInfo);
  459. if (GetMonitorInfo(MonitorFromWindow(impl->hwnd, MONITOR_DEFAULTTOPRIMARY), &mInfo))
  460. SetWindowPos(impl->hwnd,
  461. HWND_TOP,
  462. mInfo.rcWork.left + (mInfo.rcWork.right - mInfo.rcWork.left - view->frame.width) / 2,
  463. mInfo.rcWork.top + (mInfo.rcWork.bottom - mInfo.rcWork.top - view->frame.height) / 2,
  464. 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
  465. else
  466. ShowWindow(impl->hwnd, SW_NORMAL);
  467. }
  468. SetFocus(impl->hwnd);
  469. }
  470. // --------------------------------------------------------------------------------------------------------------------
  471. #elif defined(HAVE_X11)
  472. // --------------------------------------------------------------------------------------------------------------------
  473. // X11 specific, set dialog window type and pid hints
  474. void puglX11SetWindowTypeAndPID(const PuglView* const view, const bool isStandalone)
  475. {
  476. const PuglInternals* const impl = view->impl;
  477. Display* const display = view->world->impl->display;
  478. const pid_t pid = getpid();
  479. const Atom _nwp = XInternAtom(display, "_NET_WM_PID", False);
  480. XChangeProperty(display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1);
  481. const Atom _wt = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
  482. Atom _wts[2];
  483. int numAtoms = 0;
  484. if (! isStandalone)
  485. _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
  486. _wts[numAtoms++] = XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", False);
  487. XChangeProperty(display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, numAtoms);
  488. }
  489. // --------------------------------------------------------------------------------------------------------------------
  490. #endif // HAVE_X11
  491. #ifndef DISTRHO_OS_MAC
  492. END_NAMESPACE_DGL
  493. #endif