The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

265 lines
8.5KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. extern XContext windowHandleXContext;
  22. //==============================================================================
  23. // Defined juce_linux_Windowing.cpp
  24. Rectangle<int> juce_LinuxScaledToPhysicalBounds (ComponentPeer*, Rectangle<int>);
  25. void juce_LinuxAddRepaintListener (ComponentPeer*, Component* dummy);
  26. void juce_LinuxRemoveRepaintListener (ComponentPeer*, Component* dummy);
  27. //==============================================================================
  28. class OpenGLContext::NativeContext
  29. {
  30. private:
  31. struct DummyComponent : public Component
  32. {
  33. DummyComponent (OpenGLContext::NativeContext& nativeParentContext)
  34. : native (nativeParentContext)
  35. {
  36. }
  37. void handleCommandMessage (int commandId) override
  38. {
  39. if (commandId == 0)
  40. native.triggerRepaint();
  41. }
  42. OpenGLContext::NativeContext& native;
  43. };
  44. public:
  45. NativeContext (Component& comp,
  46. const OpenGLPixelFormat& cPixelFormat,
  47. void* shareContext,
  48. bool /*useMultisampling*/,
  49. OpenGLVersion)
  50. : component (comp), contextToShareWith (shareContext), dummy (*this)
  51. {
  52. display = XWindowSystem::getInstance()->displayRef();
  53. ScopedXLock xlock (display);
  54. XSync (display, False);
  55. GLint attribs[] =
  56. {
  57. GLX_RGBA,
  58. GLX_DOUBLEBUFFER,
  59. GLX_RED_SIZE, cPixelFormat.redBits,
  60. GLX_GREEN_SIZE, cPixelFormat.greenBits,
  61. GLX_BLUE_SIZE, cPixelFormat.blueBits,
  62. GLX_ALPHA_SIZE, cPixelFormat.alphaBits,
  63. GLX_DEPTH_SIZE, cPixelFormat.depthBufferBits,
  64. GLX_STENCIL_SIZE, cPixelFormat.stencilBufferBits,
  65. GLX_ACCUM_RED_SIZE, cPixelFormat.accumulationBufferRedBits,
  66. GLX_ACCUM_GREEN_SIZE, cPixelFormat.accumulationBufferGreenBits,
  67. GLX_ACCUM_BLUE_SIZE, cPixelFormat.accumulationBufferBlueBits,
  68. GLX_ACCUM_ALPHA_SIZE, cPixelFormat.accumulationBufferAlphaBits,
  69. None
  70. };
  71. bestVisual = glXChooseVisual (display, DefaultScreen (display), attribs);
  72. if (bestVisual == nullptr)
  73. return;
  74. auto* peer = component.getPeer();
  75. jassert (peer != nullptr);
  76. auto windowH = (Window) peer->getNativeHandle();
  77. auto colourMap = XCreateColormap (display, windowH, bestVisual->visual, AllocNone);
  78. XSetWindowAttributes swa;
  79. swa.colormap = colourMap;
  80. swa.border_pixel = 0;
  81. swa.event_mask = ExposureMask | StructureNotifyMask;
  82. auto glBounds = component.getTopLevelComponent()
  83. ->getLocalArea (&component, component.getLocalBounds());
  84. glBounds = juce_LinuxScaledToPhysicalBounds (peer, glBounds);
  85. embeddedWindow = XCreateWindow (display, windowH,
  86. glBounds.getX(), glBounds.getY(),
  87. (unsigned int) jmax (1, glBounds.getWidth()),
  88. (unsigned int) jmax (1, glBounds.getHeight()),
  89. 0, bestVisual->depth,
  90. InputOutput,
  91. bestVisual->visual,
  92. CWBorderPixel | CWColormap | CWEventMask,
  93. &swa);
  94. XSaveContext (display, (XID) embeddedWindow, windowHandleXContext, (XPointer) peer);
  95. XMapWindow (display, embeddedWindow);
  96. XFreeColormap (display, colourMap);
  97. XSync (display, False);
  98. juce_LinuxAddRepaintListener (peer, &dummy);
  99. }
  100. ~NativeContext()
  101. {
  102. juce_LinuxRemoveRepaintListener (component.getPeer(), &dummy);
  103. if (embeddedWindow != 0)
  104. {
  105. ScopedXLock xlock (display);
  106. XUnmapWindow (display, embeddedWindow);
  107. XDestroyWindow (display, embeddedWindow);
  108. }
  109. if (bestVisual != nullptr)
  110. XFree (bestVisual);
  111. XWindowSystem::getInstance()->displayUnref();
  112. }
  113. bool initialiseOnRenderThread (OpenGLContext& c)
  114. {
  115. ScopedXLock xlock (display);
  116. renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
  117. c.makeActive();
  118. context = &c;
  119. return true;
  120. }
  121. void shutdownOnRenderThread()
  122. {
  123. ScopedXLock xlock (display);
  124. context = nullptr;
  125. deactivateCurrentContext();
  126. glXDestroyContext (display, renderContext);
  127. renderContext = nullptr;
  128. }
  129. bool makeActive() const noexcept
  130. {
  131. ScopedXLock xlock (display);
  132. return renderContext != 0
  133. && glXMakeCurrent (display, embeddedWindow, renderContext);
  134. }
  135. bool isActive() const noexcept
  136. {
  137. ScopedXLock xlock (display);
  138. return glXGetCurrentContext() == renderContext && renderContext != 0;
  139. }
  140. static void deactivateCurrentContext()
  141. {
  142. ScopedXDisplay xDisplay;
  143. ScopedXLock xlock (xDisplay.display);
  144. glXMakeCurrent (xDisplay.display, None, 0);
  145. }
  146. void swapBuffers()
  147. {
  148. ScopedXLock xlock (display);
  149. glXSwapBuffers (display, embeddedWindow);
  150. }
  151. void updateWindowPosition (Rectangle<int> newBounds)
  152. {
  153. bounds = newBounds;
  154. auto physicalBounds = juce_LinuxScaledToPhysicalBounds (component.getPeer(), bounds);
  155. ScopedXLock xlock (display);
  156. XMoveResizeWindow (display, embeddedWindow,
  157. physicalBounds.getX(), physicalBounds.getY(),
  158. (unsigned int) jmax (1, physicalBounds.getWidth()),
  159. (unsigned int) jmax (1, physicalBounds.getHeight()));
  160. }
  161. bool setSwapInterval (int numFramesPerSwap)
  162. {
  163. if (numFramesPerSwap == swapFrames)
  164. return true;
  165. if (auto GLXSwapIntervalSGI
  166. = (PFNGLXSWAPINTERVALSGIPROC) OpenGLHelpers::getExtensionFunction ("glXSwapIntervalSGI"))
  167. {
  168. ScopedXLock xlock (display);
  169. swapFrames = numFramesPerSwap;
  170. GLXSwapIntervalSGI (numFramesPerSwap);
  171. return true;
  172. }
  173. return false;
  174. }
  175. int getSwapInterval() const { return swapFrames; }
  176. bool createdOk() const noexcept { return true; }
  177. void* getRawContext() const noexcept { return renderContext; }
  178. GLuint getFrameBufferID() const noexcept { return 0; }
  179. void triggerRepaint()
  180. {
  181. if (context != nullptr)
  182. context->triggerRepaint();
  183. }
  184. struct Locker { Locker (NativeContext&) {} };
  185. private:
  186. Component& component;
  187. GLXContext renderContext = {};
  188. Window embeddedWindow = {};
  189. int swapFrames = 0;
  190. Rectangle<int> bounds;
  191. XVisualInfo* bestVisual = {};
  192. void* contextToShareWith;
  193. OpenGLContext* context = {};
  194. DummyComponent dummy;
  195. ::Display* display = {};
  196. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  197. };
  198. //==============================================================================
  199. bool OpenGLHelpers::isContextActive()
  200. {
  201. ScopedXDisplay xDisplay;
  202. if (xDisplay.display)
  203. {
  204. ScopedXLock xlock (xDisplay.display);
  205. return glXGetCurrentContext() != 0;
  206. }
  207. return false;
  208. }
  209. } // namespace juce