| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2017 - ROLI Ltd.
 - 
 -    JUCE is an open source library subject to commercial or open-source
 -    licensing.
 - 
 -    The code included in this file is provided under the terms of the ISC license
 -    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
 -    To use, copy, modify, and/or distribute this software for any purpose with or
 -    without fee is hereby granted provided that the above copyright notice and
 -    this permission notice appear in all copies.
 - 
 -    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 -    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 -    DISCLAIMED.
 - 
 -   ==============================================================================
 - */
 - 
 - #include <poll.h>
 - 
 - enum FdType
 - {
 -     INTERNAL_QUEUE_FD,
 -     WINDOW_SYSTEM_FD,
 -     FD_COUNT,
 - };
 - 
 - namespace juce
 - {
 - 
 - //==============================================================================
 - class InternalMessageQueue
 - {
 - public:
 -     InternalMessageQueue()
 -     {
 -         auto ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd);
 -         ignoreUnused (ret); jassert (ret == 0);
 - 
 -         auto internalQueueCb = [this] (int _fd)
 -         {
 -             if (const MessageManager::MessageBase::Ptr msg = this->popNextMessage (_fd))
 -             {
 -                 JUCE_TRY
 -                 {
 -                     msg->messageCallback();
 -                     return true;
 -                 }
 -                 JUCE_CATCH_EXCEPTION
 -             }
 -             return false;
 -         };
 - 
 -         pfds[INTERNAL_QUEUE_FD].fd = getReadHandle();
 -         pfds[INTERNAL_QUEUE_FD].events = POLLIN;
 -         readCallback[INTERNAL_QUEUE_FD] = new LinuxEventLoop::CallbackFunction<decltype(internalQueueCb)> (internalQueueCb);
 -     }
 - 
 -     ~InternalMessageQueue()
 -     {
 -         close (getReadHandle());
 -         close (getWriteHandle());
 - 
 -         clearSingletonInstance();
 -     }
 - 
 -     //==============================================================================
 -     void postMessage (MessageManager::MessageBase* const msg) noexcept
 -     {
 -         ScopedLock sl (lock);
 -         queue.add (msg);
 - 
 -         const int maxBytesInSocketQueue = 128;
 - 
 -         if (bytesInSocket < maxBytesInSocketQueue)
 -         {
 -             bytesInSocket++;
 - 
 -             ScopedUnlock ul (lock);
 -             const unsigned char x = 0xff;
 -             ssize_t bytesWritten = write (getWriteHandle(), &x, 1);
 -             ignoreUnused (bytesWritten);
 -         }
 -     }
 - 
 -     void setWindowSystemFd (int _fd, LinuxEventLoop::CallbackFunctionBase* _readCallback)
 -     {
 -         jassert (fdCount == 1);
 - 
 -         ScopedLock sl (lock);
 - 
 -         fdCount = 2;
 -         pfds[WINDOW_SYSTEM_FD].fd = _fd;
 -         pfds[WINDOW_SYSTEM_FD].events = POLLIN;
 -         readCallback[WINDOW_SYSTEM_FD] = _readCallback;
 -         readCallback[WINDOW_SYSTEM_FD]->active = true;
 -     }
 - 
 -     void removeWindowSystemFd()
 -     {
 -         jassert (fdCount == FD_COUNT);
 - 
 -         ScopedLock sl (lock);
 - 
 -         fdCount = 1;
 -         readCallback[WINDOW_SYSTEM_FD]->active = false;
 -     }
 - 
 -     bool dispatchNextEvent() noexcept
 -     {
 -         for (int counter = 0; counter < fdCount; counter++)
 -         {
 -             const int i = loopCount++;
 -             loopCount %= fdCount;
 - 
 -             if (readCallback[i] != nullptr && readCallback[i]->active)
 -                 if ((*readCallback[i]) (pfds[i].fd))
 -                     return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     bool sleepUntilEvent (const int timeoutMs)
 -     {
 -         const int pnum = poll (pfds, static_cast<nfds_t> (fdCount), timeoutMs);
 -         return (pnum > 0);
 -     }
 - 
 -     //==============================================================================
 -     juce_DeclareSingleton_SingleThreaded_Minimal (InternalMessageQueue)
 - 
 - private:
 -     CriticalSection lock;
 -     ReferenceCountedArray <MessageManager::MessageBase> queue;
 -     int fd[2];
 -     pollfd pfds[FD_COUNT];
 -     ScopedPointer<LinuxEventLoop::CallbackFunctionBase> readCallback[FD_COUNT];
 -     int fdCount = 1;
 -     int loopCount = 0;
 -     int bytesInSocket = 0;
 - 
 -     int getWriteHandle() const noexcept     { return fd[0]; }
 -     int getReadHandle() const noexcept      { return fd[1]; }
 - 
 -     MessageManager::MessageBase::Ptr popNextMessage (int _fd) noexcept
 -     {
 -         const ScopedLock sl (lock);
 - 
 -         if (bytesInSocket > 0)
 -         {
 -             --bytesInSocket;
 - 
 -             const ScopedUnlock ul (lock);
 -             unsigned char x;
 -             ssize_t numBytes = read (_fd, &x, 1);
 -             ignoreUnused (numBytes);
 -         }
 - 
 -         return queue.removeAndReturn (0);
 -     }
 - };
 - 
 - juce_ImplementSingleton_SingleThreaded (InternalMessageQueue)
 - 
 - 
 - //==============================================================================
 - namespace LinuxErrorHandling
 - {
 -     static bool keyboardBreakOccurred = false;
 - 
 -     //==============================================================================
 -     void keyboardBreakSignalHandler (int sig)
 -     {
 -         if (sig == SIGINT)
 -             keyboardBreakOccurred = true;
 -     }
 - 
 -     void installKeyboardBreakHandler()
 -     {
 -         struct sigaction saction;
 -         sigset_t maskSet;
 -         sigemptyset (&maskSet);
 -         saction.sa_handler = keyboardBreakSignalHandler;
 -         saction.sa_mask = maskSet;
 -         saction.sa_flags = 0;
 -         sigaction (SIGINT, &saction, 0);
 -     }
 - }
 - 
 - //==============================================================================
 - void MessageManager::doPlatformSpecificInitialisation()
 - {
 -     if (JUCEApplicationBase::isStandaloneApp())
 -         LinuxErrorHandling::installKeyboardBreakHandler();
 - 
 -     // Create the internal message queue
 -     auto* queue = InternalMessageQueue::getInstance();
 -     ignoreUnused (queue);
 - }
 - 
 - void MessageManager::doPlatformSpecificShutdown()
 - {
 -     InternalMessageQueue::deleteInstance();
 - }
 - 
 - bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
 - {
 -     if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
 -     {
 -         queue->postMessage (message);
 -         return true;
 -     }
 - 
 -     return false;
 - }
 - 
 - void MessageManager::broadcastMessage (const String&)
 - {
 -     // TODO
 - }
 - 
 - // this function expects that it will NEVER be called simultaneously for two concurrent threads
 - bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
 - {
 -     for (;;)
 -     {
 -         if (LinuxErrorHandling::keyboardBreakOccurred)
 -             JUCEApplicationBase::getInstance()->quit();
 - 
 -         if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
 -         {
 -             if (queue->dispatchNextEvent())
 -                 break;
 - 
 -             if (returnIfNoPendingMessages)
 -                 return false;
 - 
 -             // wait for 2000ms for next events if necessary
 -             queue->sleepUntilEvent (2000);
 -         }
 -     }
 - 
 -     return true;
 - }
 - 
 - //==============================================================================
 - void LinuxEventLoop::setWindowSystemFdInternal (int fd, LinuxEventLoop::CallbackFunctionBase* readCallback) noexcept
 - {
 -     if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
 -         queue->setWindowSystemFd (fd, readCallback);
 - }
 - 
 - void LinuxEventLoop::removeWindowSystemFd() noexcept
 - {
 -     if (auto* queue = InternalMessageQueue::getInstanceWithoutCreating())
 -         queue->removeWindowSystemFd();
 - }
 - 
 - 
 - } // namespace juce
 
 
  |