| @@ -1726,26 +1726,16 @@ const Result Result::fail (const String& errorMessage) noexcept | |||||
| return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage); | return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage); | ||||
| } | } | ||||
| bool Result::wasOk() const noexcept | |||||
| { | |||||
| return errorMessage.isEmpty(); | |||||
| } | |||||
| bool Result::failed() const noexcept | |||||
| { | |||||
| return errorMessage.isNotEmpty(); | |||||
| } | |||||
| Result::operator bool() const noexcept | |||||
| { | |||||
| return errorMessage.isEmpty(); | |||||
| } | |||||
| const String Result::getErrorMessage() const noexcept | const String Result::getErrorMessage() const noexcept | ||||
| { | { | ||||
| return errorMessage; | return errorMessage; | ||||
| } | } | ||||
| bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); } | |||||
| Result::operator bool() const noexcept { return errorMessage.isEmpty(); } | |||||
| bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); } | |||||
| bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| /*** End of inlined file: juce_Result.cpp ***/ | /*** End of inlined file: juce_Result.cpp ***/ | ||||
| @@ -48506,6 +48496,7 @@ void ComboBox::lookAndFeelChanged() | |||||
| } | } | ||||
| addAndMakeVisible (label); | addAndMakeVisible (label); | ||||
| setWantsKeyboardFocus (! label->isEditable()); | |||||
| label->addListener (this); | label->addListener (this); | ||||
| label->addMouseListener (this, false); | label->addMouseListener (this, false); | ||||
| @@ -76902,6 +76893,14 @@ public: | |||||
| while (owner.renderAndSwapBuffers() && ! threadShouldExit()) | while (owner.renderAndSwapBuffers() && ! threadShouldExit()) | ||||
| owner.waitAfterSwapping(); | owner.waitAfterSwapping(); | ||||
| owner.releaseOpenGLContext(); | |||||
| #if JUCE_LINUX | |||||
| owner.deleteContext(); | |||||
| #else | |||||
| owner.makeCurrentContextInactive(); | |||||
| #endif | |||||
| triggerAsyncUpdate(); | triggerAsyncUpdate(); | ||||
| } | } | ||||
| @@ -76933,17 +76932,13 @@ public: | |||||
| void componentPeerChanged() | void componentPeerChanged() | ||||
| { | { | ||||
| const ScopedLock sl (owner->getContextLock()); | |||||
| owner->stopRendering(); | owner->stopRendering(); | ||||
| } | } | ||||
| void componentVisibilityChanged() | void componentVisibilityChanged() | ||||
| { | { | ||||
| if (! owner->isShowing()) | if (! owner->isShowing()) | ||||
| { | |||||
| const ScopedLock sl (owner->getContextLock()); | |||||
| owner->stopRendering(); | owner->stopRendering(); | ||||
| } | |||||
| } | } | ||||
| private: | private: | ||||
| @@ -76955,7 +76950,8 @@ private: | |||||
| OpenGLComponent::OpenGLComponent (const OpenGLType type_) | OpenGLComponent::OpenGLComponent (const OpenGLType type_) | ||||
| : type (type_), | : type (type_), | ||||
| contextToShareListsWith (nullptr), | contextToShareListsWith (nullptr), | ||||
| needToUpdateViewport (true) | |||||
| needToUpdateViewport (true), | |||||
| useThread (false) | |||||
| { | { | ||||
| setOpaque (true); | setOpaque (true); | ||||
| componentWatcher = new OpenGLComponentWatcher (this); | componentWatcher = new OpenGLComponentWatcher (this); | ||||
| @@ -76963,7 +76959,8 @@ OpenGLComponent::OpenGLComponent (const OpenGLType type_) | |||||
| OpenGLComponent::~OpenGLComponent() | OpenGLComponent::~OpenGLComponent() | ||||
| { | { | ||||
| deleteContext(); | |||||
| stopRendering(); | |||||
| renderThread = nullptr; | |||||
| componentWatcher = nullptr; | componentWatcher = nullptr; | ||||
| } | } | ||||
| @@ -77079,14 +77076,29 @@ void OpenGLComponent::paint (Graphics&) | |||||
| renderThread = new OpenGLComponentRenderThread (*this); | renderThread = new OpenGLComponentRenderThread (*this); | ||||
| if (! renderThread->isThreadRunning()) | if (! renderThread->isThreadRunning()) | ||||
| { | |||||
| renderThread->handleUpdateNowIfNeeded(); // may still be shutting down as well | |||||
| #if ! JUCE_LINUX | |||||
| // Except for Linux, create the context etc. first | |||||
| const ScopedLock sl (contextLock); | |||||
| if (makeCurrentContextActive()) // Make active just to create | |||||
| makeCurrentContextInactive(); | |||||
| #endif | |||||
| renderThread->startThread (6); | renderThread->startThread (6); | ||||
| } | |||||
| // fall-through and update the masking region | // fall-through and update the masking region | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if (renderThread != nullptr && renderThread->isThreadRunning()) | |||||
| renderThread->stopThread (5000); | |||||
| if (renderThread != nullptr) | |||||
| { | |||||
| stopRendering(); | |||||
| renderThread = nullptr; | |||||
| } | |||||
| if (! renderAndSwapBuffers()) | if (! renderAndSwapBuffers()) | ||||
| return; | return; | ||||
| @@ -77127,26 +77139,19 @@ void OpenGLComponent::waitAfterSwapping() | |||||
| Thread::sleep (20); | Thread::sleep (20); | ||||
| } | } | ||||
| bool OpenGLComponent::stopRendering() | |||||
| void OpenGLComponent::stopRendering() | |||||
| { | { | ||||
| const ScopedLock sl (contextLock); | |||||
| if (renderThread != nullptr) | |||||
| renderThread->stopThread (5000); | |||||
| if (! makeCurrentContextActive()) | |||||
| return false; | |||||
| releaseOpenGLContext(); // callback to allow for shutdown | |||||
| if (renderThread != nullptr && Thread::getCurrentThread() == renderThread) | |||||
| if (context != nullptr && makeCurrentContextActive()) | |||||
| { | { | ||||
| // make the context inactive - if we're on a thread, this will release the context, | |||||
| // so the main thread can take it and do shutdown | |||||
| // On Linux, when threaded, context will have already been cleared | |||||
| const ScopedLock sl (contextLock); | |||||
| makeCurrentContextInactive(); | |||||
| releaseOpenGLContext(); | |||||
| deleteContext(); | |||||
| } | } | ||||
| else if (context != nullptr) | |||||
| context->deleteContext(); | |||||
| return true; | |||||
| } | } | ||||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | ||||
| @@ -73,7 +73,7 @@ namespace JuceDummyNamespace {} | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 77 | |||||
| #define JUCE_BUILDNUMBER 78 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -12059,6 +12059,11 @@ public: | |||||
| */ | */ | ||||
| operator bool() const noexcept; | operator bool() const noexcept; | ||||
| /** Returns true if this result indicates a failure. | |||||
| This is equivalent to calling failed(). | |||||
| */ | |||||
| bool operator!() const noexcept; | |||||
| /** Returns the error message that was set when this result was created. | /** Returns the error message that was set when this result was created. | ||||
| For a successful result, this will be an empty string; | For a successful result, this will be an empty string; | ||||
| */ | */ | ||||
| @@ -12074,6 +12079,10 @@ private: | |||||
| String errorMessage; | String errorMessage; | ||||
| explicit Result (const String& errorMessage) noexcept; | explicit Result (const String& errorMessage) noexcept; | ||||
| // These casts are private to prevent people trying to use the Result object in numeric contexts | |||||
| operator int() const; | |||||
| operator void*() const; | |||||
| }; | }; | ||||
| #endif // __JUCE_RESULT_JUCEHEADER__ | #endif // __JUCE_RESULT_JUCEHEADER__ | ||||
| @@ -63926,15 +63935,9 @@ public: | |||||
| Used when rendering is running on a thread. The default is 20 millseconds, giving | Used when rendering is running on a thread. The default is 20 millseconds, giving | ||||
| a nominal frame rate of just under 50 fps. | a nominal frame rate of just under 50 fps. | ||||
| */ | |||||
| */ | |||||
| virtual void waitAfterSwapping(); | virtual void waitAfterSwapping(); | ||||
| /** Stop Rendering. | |||||
| Use to shut down an openGLComponent properly, whether on a thread or not. | |||||
| */ | |||||
| virtual bool stopRendering(); | |||||
| /** This returns a critical section that can be used to lock the current context. | /** This returns a critical section that can be used to lock the current context. | ||||
| Because the context that is used by this component can change, e.g. when the | Because the context that is used by this component can change, e.g. when the | ||||
| @@ -63980,6 +63983,7 @@ private: | |||||
| OpenGLContext* createContext(); | OpenGLContext* createContext(); | ||||
| void updateContextPosition(); | void updateContextPosition(); | ||||
| void internalRepaint (int x, int y, int w, int h); | void internalRepaint (int x, int y, int w, int h); | ||||
| void stopRendering(); | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); | ||||
| }; | }; | ||||
| @@ -67,26 +67,15 @@ const Result Result::fail (const String& errorMessage) noexcept | |||||
| return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage); | return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage); | ||||
| } | } | ||||
| //============================================================================== | |||||
| bool Result::wasOk() const noexcept | |||||
| { | |||||
| return errorMessage.isEmpty(); | |||||
| } | |||||
| bool Result::failed() const noexcept | |||||
| { | |||||
| return errorMessage.isNotEmpty(); | |||||
| } | |||||
| Result::operator bool() const noexcept | |||||
| { | |||||
| return errorMessage.isEmpty(); | |||||
| } | |||||
| const String Result::getErrorMessage() const noexcept | const String Result::getErrorMessage() const noexcept | ||||
| { | { | ||||
| return errorMessage; | return errorMessage; | ||||
| } | } | ||||
| bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); } | |||||
| Result::operator bool() const noexcept { return errorMessage.isEmpty(); } | |||||
| bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); } | |||||
| bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); } | |||||
| END_JUCE_NAMESPACE | END_JUCE_NAMESPACE | ||||
| @@ -85,6 +85,11 @@ public: | |||||
| */ | */ | ||||
| operator bool() const noexcept; | operator bool() const noexcept; | ||||
| /** Returns true if this result indicates a failure. | |||||
| This is equivalent to calling failed(). | |||||
| */ | |||||
| bool operator!() const noexcept; | |||||
| /** Returns the error message that was set when this result was created. | /** Returns the error message that was set when this result was created. | ||||
| For a successful result, this will be an empty string; | For a successful result, this will be an empty string; | ||||
| */ | */ | ||||
| @@ -101,6 +106,10 @@ private: | |||||
| String errorMessage; | String errorMessage; | ||||
| explicit Result (const String& errorMessage) noexcept; | explicit Result (const String& errorMessage) noexcept; | ||||
| // These casts are private to prevent people trying to use the Result object in numeric contexts | |||||
| operator int() const; | |||||
| operator void*() const; | |||||
| }; | }; | ||||
| @@ -33,7 +33,7 @@ | |||||
| */ | */ | ||||
| #define JUCE_MAJOR_VERSION 1 | #define JUCE_MAJOR_VERSION 1 | ||||
| #define JUCE_MINOR_VERSION 53 | #define JUCE_MINOR_VERSION 53 | ||||
| #define JUCE_BUILDNUMBER 77 | |||||
| #define JUCE_BUILDNUMBER 78 | |||||
| /** Current Juce version number. | /** Current Juce version number. | ||||
| @@ -432,6 +432,7 @@ void ComboBox::lookAndFeelChanged() | |||||
| } | } | ||||
| addAndMakeVisible (label); | addAndMakeVisible (label); | ||||
| setWantsKeyboardFocus (! label->isEditable()); | |||||
| label->addListener (this); | label->addListener (this); | ||||
| label->addMouseListener (this, false); | label->addMouseListener (this, false); | ||||
| @@ -148,6 +148,14 @@ public: | |||||
| while (owner.renderAndSwapBuffers() && ! threadShouldExit()) | while (owner.renderAndSwapBuffers() && ! threadShouldExit()) | ||||
| owner.waitAfterSwapping(); | owner.waitAfterSwapping(); | ||||
| owner.releaseOpenGLContext(); | |||||
| #if JUCE_LINUX | |||||
| owner.deleteContext(); | |||||
| #else | |||||
| owner.makeCurrentContextInactive(); | |||||
| #endif | |||||
| triggerAsyncUpdate(); | triggerAsyncUpdate(); | ||||
| } | } | ||||
| @@ -184,17 +192,13 @@ public: | |||||
| void componentPeerChanged() | void componentPeerChanged() | ||||
| { | { | ||||
| const ScopedLock sl (owner->getContextLock()); | |||||
| owner->stopRendering(); | owner->stopRendering(); | ||||
| } | } | ||||
| void componentVisibilityChanged() | void componentVisibilityChanged() | ||||
| { | { | ||||
| if (! owner->isShowing()) | if (! owner->isShowing()) | ||||
| { | |||||
| const ScopedLock sl (owner->getContextLock()); | |||||
| owner->stopRendering(); | owner->stopRendering(); | ||||
| } | |||||
| } | } | ||||
| //============================================================================== | //============================================================================== | ||||
| @@ -208,7 +212,8 @@ private: | |||||
| OpenGLComponent::OpenGLComponent (const OpenGLType type_) | OpenGLComponent::OpenGLComponent (const OpenGLType type_) | ||||
| : type (type_), | : type (type_), | ||||
| contextToShareListsWith (nullptr), | contextToShareListsWith (nullptr), | ||||
| needToUpdateViewport (true) | |||||
| needToUpdateViewport (true), | |||||
| useThread (false) | |||||
| { | { | ||||
| setOpaque (true); | setOpaque (true); | ||||
| componentWatcher = new OpenGLComponentWatcher (this); | componentWatcher = new OpenGLComponentWatcher (this); | ||||
| @@ -216,7 +221,8 @@ OpenGLComponent::OpenGLComponent (const OpenGLType type_) | |||||
| OpenGLComponent::~OpenGLComponent() | OpenGLComponent::~OpenGLComponent() | ||||
| { | { | ||||
| deleteContext(); | |||||
| stopRendering(); | |||||
| renderThread = nullptr; | |||||
| componentWatcher = nullptr; | componentWatcher = nullptr; | ||||
| } | } | ||||
| @@ -332,14 +338,29 @@ void OpenGLComponent::paint (Graphics&) | |||||
| renderThread = new OpenGLComponentRenderThread (*this); | renderThread = new OpenGLComponentRenderThread (*this); | ||||
| if (! renderThread->isThreadRunning()) | if (! renderThread->isThreadRunning()) | ||||
| { | |||||
| renderThread->handleUpdateNowIfNeeded(); // may still be shutting down as well | |||||
| #if ! JUCE_LINUX | |||||
| // Except for Linux, create the context etc. first | |||||
| const ScopedLock sl (contextLock); | |||||
| if (makeCurrentContextActive()) // Make active just to create | |||||
| makeCurrentContextInactive(); | |||||
| #endif | |||||
| renderThread->startThread (6); | renderThread->startThread (6); | ||||
| } | |||||
| // fall-through and update the masking region | // fall-through and update the masking region | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| if (renderThread != nullptr && renderThread->isThreadRunning()) | |||||
| renderThread->stopThread (5000); | |||||
| if (renderThread != nullptr) | |||||
| { | |||||
| stopRendering(); | |||||
| renderThread = nullptr; | |||||
| } | |||||
| if (! renderAndSwapBuffers()) | if (! renderAndSwapBuffers()) | ||||
| return; | return; | ||||
| @@ -380,26 +401,19 @@ void OpenGLComponent::waitAfterSwapping() | |||||
| Thread::sleep (20); | Thread::sleep (20); | ||||
| } | } | ||||
| bool OpenGLComponent::stopRendering() | |||||
| void OpenGLComponent::stopRendering() | |||||
| { | { | ||||
| const ScopedLock sl (contextLock); | |||||
| if (! makeCurrentContextActive()) | |||||
| return false; | |||||
| if (renderThread != nullptr) | |||||
| renderThread->stopThread (5000); | |||||
| releaseOpenGLContext(); // callback to allow for shutdown | |||||
| if (renderThread != nullptr && Thread::getCurrentThread() == renderThread) | |||||
| if (context != nullptr && makeCurrentContextActive()) | |||||
| { | { | ||||
| // make the context inactive - if we're on a thread, this will release the context, | |||||
| // so the main thread can take it and do shutdown | |||||
| // On Linux, when threaded, context will have already been cleared | |||||
| const ScopedLock sl (contextLock); | |||||
| makeCurrentContextInactive(); | |||||
| releaseOpenGLContext(); | |||||
| deleteContext(); | |||||
| } | } | ||||
| else if (context != nullptr) | |||||
| context->deleteContext(); | |||||
| return true; | |||||
| } | } | ||||
| void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | void OpenGLComponent::internalRepaint (int x, int y, int w, int h) | ||||
| @@ -346,15 +346,9 @@ public: | |||||
| Used when rendering is running on a thread. The default is 20 millseconds, giving | Used when rendering is running on a thread. The default is 20 millseconds, giving | ||||
| a nominal frame rate of just under 50 fps. | a nominal frame rate of just under 50 fps. | ||||
| */ | |||||
| */ | |||||
| virtual void waitAfterSwapping(); | virtual void waitAfterSwapping(); | ||||
| /** Stop Rendering. | |||||
| Use to shut down an openGLComponent properly, whether on a thread or not. | |||||
| */ | |||||
| virtual bool stopRendering(); | |||||
| /** This returns a critical section that can be used to lock the current context. | /** This returns a critical section that can be used to lock the current context. | ||||
| Because the context that is used by this component can change, e.g. when the | Because the context that is used by this component can change, e.g. when the | ||||
| @@ -403,6 +397,7 @@ private: | |||||
| OpenGLContext* createContext(); | OpenGLContext* createContext(); | ||||
| void updateContextPosition(); | void updateContextPosition(); | ||||
| void internalRepaint (int x, int y, int w, int h); | void internalRepaint (int x, int y, int w, int h); | ||||
| void stopRendering(); | |||||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent); | ||||
| }; | }; | ||||