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.

252 lines
8.1KB

  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. extern XContext windowHandleXContext;
  20. //==============================================================================
  21. // Defined juce_linux_Windowing.cpp
  22. Rectangle<int> juce_LinuxScaledToPhysicalBounds (ComponentPeer*, Rectangle<int>);
  23. void juce_LinuxAddRepaintListener (ComponentPeer*, Component* dummy);
  24. void juce_LinuxRemoveRepaintListener (ComponentPeer*, Component* dummy);
  25. //==============================================================================
  26. class OpenGLContext::NativeContext
  27. {
  28. private:
  29. struct DummyComponent : public Component
  30. {
  31. DummyComponent (OpenGLContext::NativeContext& nativeParentContext)
  32. : native (nativeParentContext)
  33. {
  34. }
  35. void handleCommandMessage (int commandId) override
  36. {
  37. if (commandId == 0)
  38. native.triggerRepaint();
  39. }
  40. OpenGLContext::NativeContext& native;
  41. };
  42. public:
  43. NativeContext (Component& comp,
  44. const OpenGLPixelFormat& cPixelFormat,
  45. void* shareContext,
  46. bool /*useMultisampling*/,
  47. OpenGLVersion)
  48. : component (comp), contextToShareWith (shareContext), dummy (*this)
  49. {
  50. display = XWindowSystem::getInstance()->displayRef();
  51. ScopedXLock xlock (display);
  52. XSync (display, False);
  53. GLint attribs[] =
  54. {
  55. GLX_RGBA,
  56. GLX_DOUBLEBUFFER,
  57. GLX_RED_SIZE, cPixelFormat.redBits,
  58. GLX_GREEN_SIZE, cPixelFormat.greenBits,
  59. GLX_BLUE_SIZE, cPixelFormat.blueBits,
  60. GLX_ALPHA_SIZE, cPixelFormat.alphaBits,
  61. GLX_DEPTH_SIZE, cPixelFormat.depthBufferBits,
  62. GLX_STENCIL_SIZE, cPixelFormat.stencilBufferBits,
  63. GLX_ACCUM_RED_SIZE, cPixelFormat.accumulationBufferRedBits,
  64. GLX_ACCUM_GREEN_SIZE, cPixelFormat.accumulationBufferGreenBits,
  65. GLX_ACCUM_BLUE_SIZE, cPixelFormat.accumulationBufferBlueBits,
  66. GLX_ACCUM_ALPHA_SIZE, cPixelFormat.accumulationBufferAlphaBits,
  67. None
  68. };
  69. bestVisual = glXChooseVisual (display, DefaultScreen (display), attribs);
  70. if (bestVisual == nullptr)
  71. return;
  72. auto* peer = component.getPeer();
  73. jassert (peer != nullptr);
  74. auto windowH = (Window) peer->getNativeHandle();
  75. auto colourMap = XCreateColormap (display, windowH, bestVisual->visual, AllocNone);
  76. XSetWindowAttributes swa;
  77. swa.colormap = colourMap;
  78. swa.border_pixel = 0;
  79. swa.event_mask = ExposureMask | StructureNotifyMask;
  80. auto glBounds = component.getTopLevelComponent()
  81. ->getLocalArea (&component, component.getLocalBounds());
  82. glBounds = juce_LinuxScaledToPhysicalBounds (peer, glBounds);
  83. embeddedWindow = XCreateWindow (display, windowH,
  84. glBounds.getX(), glBounds.getY(),
  85. (unsigned int) jmax (1, glBounds.getWidth()),
  86. (unsigned int) jmax (1, glBounds.getHeight()),
  87. 0, bestVisual->depth,
  88. InputOutput,
  89. bestVisual->visual,
  90. CWBorderPixel | CWColormap | CWEventMask,
  91. &swa);
  92. XSaveContext (display, (XID) embeddedWindow, windowHandleXContext, (XPointer) peer);
  93. XMapWindow (display, embeddedWindow);
  94. XFreeColormap (display, colourMap);
  95. XSync (display, False);
  96. juce_LinuxAddRepaintListener (peer, &dummy);
  97. }
  98. ~NativeContext()
  99. {
  100. juce_LinuxRemoveRepaintListener (component.getPeer(), &dummy);
  101. if (embeddedWindow != 0)
  102. {
  103. ScopedXLock xlock (display);
  104. XUnmapWindow (display, embeddedWindow);
  105. XDestroyWindow (display, embeddedWindow);
  106. }
  107. if (bestVisual != nullptr)
  108. XFree (bestVisual);
  109. XWindowSystem::getInstance()->displayUnref();
  110. }
  111. void initialiseOnRenderThread (OpenGLContext& c)
  112. {
  113. ScopedXLock xlock (display);
  114. renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
  115. c.makeActive();
  116. context = &c;
  117. }
  118. void shutdownOnRenderThread()
  119. {
  120. context = nullptr;
  121. deactivateCurrentContext();
  122. glXDestroyContext (display, renderContext);
  123. renderContext = nullptr;
  124. }
  125. bool makeActive() const noexcept
  126. {
  127. return renderContext != 0
  128. && glXMakeCurrent (display, embeddedWindow, renderContext);
  129. }
  130. bool isActive() const noexcept
  131. {
  132. return glXGetCurrentContext() == renderContext && renderContext != 0;
  133. }
  134. static void deactivateCurrentContext()
  135. {
  136. ScopedXDisplay xDisplay;
  137. glXMakeCurrent (xDisplay.display, None, 0);
  138. }
  139. void swapBuffers()
  140. {
  141. glXSwapBuffers (display, embeddedWindow);
  142. }
  143. void updateWindowPosition (Rectangle<int> newBounds)
  144. {
  145. bounds = newBounds;
  146. auto physicalBounds = juce_LinuxScaledToPhysicalBounds (component.getPeer(), bounds);
  147. ScopedXLock xlock (display);
  148. XMoveResizeWindow (display, embeddedWindow,
  149. physicalBounds.getX(), physicalBounds.getY(),
  150. (unsigned int) jmax (1, physicalBounds.getWidth()),
  151. (unsigned int) jmax (1, physicalBounds.getHeight()));
  152. }
  153. bool setSwapInterval (int numFramesPerSwap)
  154. {
  155. if (numFramesPerSwap == swapFrames)
  156. return true;
  157. if (auto GLXSwapIntervalSGI
  158. = (PFNGLXSWAPINTERVALSGIPROC) OpenGLHelpers::getExtensionFunction ("glXSwapIntervalSGI"))
  159. {
  160. swapFrames = numFramesPerSwap;
  161. GLXSwapIntervalSGI (numFramesPerSwap);
  162. return true;
  163. }
  164. return false;
  165. }
  166. int getSwapInterval() const { return swapFrames; }
  167. bool createdOk() const noexcept { return true; }
  168. void* getRawContext() const noexcept { return renderContext; }
  169. GLuint getFrameBufferID() const noexcept { return 0; }
  170. void triggerRepaint()
  171. {
  172. if (context != nullptr)
  173. context->triggerRepaint();
  174. }
  175. struct Locker { Locker (NativeContext&) {} };
  176. private:
  177. Component& component;
  178. GLXContext renderContext = {};
  179. Window embeddedWindow = {};
  180. int swapFrames = 0;
  181. Rectangle<int> bounds;
  182. XVisualInfo* bestVisual = {};
  183. void* contextToShareWith;
  184. OpenGLContext* context = {};
  185. DummyComponent dummy;
  186. ::Display* display = {};
  187. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  188. };
  189. //==============================================================================
  190. bool OpenGLHelpers::isContextActive()
  191. {
  192. ScopedXDisplay xDisplay;
  193. if (xDisplay.display)
  194. {
  195. ScopedXLock xlock (xDisplay.display);
  196. return glXGetCurrentContext() != 0;
  197. }
  198. return false;
  199. }