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.

253 lines
8.4KB

  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* peer, const Rectangle<int>& bounds);
  23. void juce_LinuxAddRepaintListener (ComponentPeer* peer, Component* dummy);
  24. void juce_LinuxRemoveRepaintListener (ComponentPeer* peer, Component* dummy);
  25. //==============================================================================
  26. class OpenGLContext::NativeContext
  27. {
  28. private:
  29. class DummyComponent : public Component
  30. {
  31. public:
  32. DummyComponent (OpenGLContext::NativeContext& nativeParentContext)
  33. : native (nativeParentContext)
  34. {
  35. }
  36. void handleCommandMessage (int commandId) override
  37. {
  38. if (commandId == 0)
  39. native.triggerRepaint();
  40. }
  41. private:
  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), renderContext (0), embeddedWindow (0), swapFrames (0), bestVisual (0),
  51. contextToShareWith (shareContext), context (nullptr), dummy (*this)
  52. {
  53. display = XWindowSystem::getInstance()->displayRef();
  54. ScopedXLock xlock (display);
  55. XSync (display, False);
  56. GLint attribs[] =
  57. {
  58. GLX_RGBA,
  59. GLX_DOUBLEBUFFER,
  60. GLX_RED_SIZE, cPixelFormat.redBits,
  61. GLX_GREEN_SIZE, cPixelFormat.greenBits,
  62. GLX_BLUE_SIZE, cPixelFormat.blueBits,
  63. GLX_ALPHA_SIZE, cPixelFormat.alphaBits,
  64. GLX_DEPTH_SIZE, cPixelFormat.depthBufferBits,
  65. GLX_STENCIL_SIZE, cPixelFormat.stencilBufferBits,
  66. GLX_ACCUM_RED_SIZE, cPixelFormat.accumulationBufferRedBits,
  67. GLX_ACCUM_GREEN_SIZE, cPixelFormat.accumulationBufferGreenBits,
  68. GLX_ACCUM_BLUE_SIZE, cPixelFormat.accumulationBufferBlueBits,
  69. GLX_ACCUM_ALPHA_SIZE, cPixelFormat.accumulationBufferAlphaBits,
  70. None
  71. };
  72. bestVisual = glXChooseVisual (display, DefaultScreen (display), attribs);
  73. if (bestVisual == nullptr)
  74. return;
  75. ComponentPeer* const peer = component.getPeer();
  76. Window windowH = (Window) peer->getNativeHandle();
  77. Colormap 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. Rectangle<int> 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. void initialiseOnRenderThread (OpenGLContext& c)
  114. {
  115. ScopedXLock xlock (display);
  116. renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
  117. c.makeActive();
  118. context = &c;
  119. }
  120. void shutdownOnRenderThread()
  121. {
  122. context = nullptr;
  123. deactivateCurrentContext();
  124. glXDestroyContext (display, renderContext);
  125. renderContext = nullptr;
  126. }
  127. bool makeActive() const noexcept
  128. {
  129. return renderContext != 0
  130. && glXMakeCurrent (display, embeddedWindow, renderContext);
  131. }
  132. bool isActive() const noexcept
  133. {
  134. return glXGetCurrentContext() == renderContext && renderContext != 0;
  135. }
  136. static void deactivateCurrentContext()
  137. {
  138. ScopedXDisplay xDisplay;
  139. ::Display* display = xDisplay.get();
  140. glXMakeCurrent (display, None, 0);
  141. }
  142. void swapBuffers()
  143. {
  144. glXSwapBuffers (display, embeddedWindow);
  145. }
  146. void updateWindowPosition (const Rectangle<int>& newBounds)
  147. {
  148. bounds = newBounds;
  149. const Rectangle<int> physicalBounds =
  150. juce_LinuxScaledToPhysicalBounds (component.getPeer(), bounds);
  151. ScopedXLock xlock (display);
  152. XMoveResizeWindow (display, embeddedWindow,
  153. physicalBounds.getX(), physicalBounds.getY(),
  154. (unsigned int) jmax (1, physicalBounds.getWidth()),
  155. (unsigned int) jmax (1, physicalBounds.getHeight()));
  156. }
  157. bool setSwapInterval (int numFramesPerSwap)
  158. {
  159. if (numFramesPerSwap == swapFrames)
  160. return true;
  161. PFNGLXSWAPINTERVALSGIPROC GLXSwapIntervalSGI
  162. = (PFNGLXSWAPINTERVALSGIPROC) OpenGLHelpers::getExtensionFunction ("glXSwapIntervalSGI");
  163. if (GLXSwapIntervalSGI != nullptr)
  164. {
  165. swapFrames = numFramesPerSwap;
  166. GLXSwapIntervalSGI (numFramesPerSwap);
  167. return true;
  168. }
  169. return false;
  170. }
  171. int getSwapInterval() const { return swapFrames; }
  172. bool createdOk() const noexcept { return true; }
  173. void* getRawContext() const noexcept { return renderContext; }
  174. GLuint getFrameBufferID() const noexcept { return 0; }
  175. void triggerRepaint()
  176. {
  177. if (context != nullptr)
  178. context->triggerRepaint();
  179. }
  180. struct Locker { Locker (NativeContext&) {} };
  181. private:
  182. Component& component;
  183. GLXContext renderContext;
  184. Window embeddedWindow;
  185. int swapFrames;
  186. Rectangle<int> bounds;
  187. XVisualInfo* bestVisual;
  188. void* contextToShareWith;
  189. OpenGLContext* context;
  190. DummyComponent dummy;
  191. ::Display* display;
  192. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  193. };
  194. //==============================================================================
  195. bool OpenGLHelpers::isContextActive()
  196. {
  197. ScopedXDisplay xDisplay;
  198. ::Display* display = xDisplay.get();
  199. ScopedXLock xlock (display);
  200. return glXGetCurrentContext() != 0;
  201. }