Audio plugin host https://kx.studio/carla
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.

juce_linux_Messaging.cpp 12KB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #if JUCE_DEBUG && ! defined (JUCE_DEBUG_XERRORS)
  18. #define JUCE_DEBUG_XERRORS 1
  19. #endif
  20. Display* display = nullptr;
  21. Window juce_messageWindowHandle = None;
  22. XContext windowHandleXContext; // This is referenced from Windowing.cpp
  23. typedef bool (*WindowMessageReceiveCallback) (XEvent&);
  24. WindowMessageReceiveCallback dispatchWindowMessage = nullptr;
  25. typedef void (*SelectionRequestCallback) (XSelectionRequestEvent&);
  26. SelectionRequestCallback handleSelectionRequest = nullptr;
  27. //==============================================================================
  28. ScopedXLock::ScopedXLock() { if (display != nullptr) XLockDisplay (display); }
  29. ScopedXLock::~ScopedXLock() { if (display != nullptr) XUnlockDisplay (display); }
  30. //==============================================================================
  31. class InternalMessageQueue
  32. {
  33. public:
  34. InternalMessageQueue()
  35. : bytesInSocket (0),
  36. totalEventCount (0)
  37. {
  38. int ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd);
  39. ignoreUnused (ret); jassert (ret == 0);
  40. }
  41. ~InternalMessageQueue()
  42. {
  43. close (fd[0]);
  44. close (fd[1]);
  45. clearSingletonInstance();
  46. }
  47. //==============================================================================
  48. void postMessage (MessageManager::MessageBase* const msg)
  49. {
  50. const int maxBytesInSocketQueue = 128;
  51. ScopedLock sl (lock);
  52. queue.add (msg);
  53. if (bytesInSocket < maxBytesInSocketQueue)
  54. {
  55. ++bytesInSocket;
  56. ScopedUnlock ul (lock);
  57. const unsigned char x = 0xff;
  58. ssize_t bytesWritten = write (fd[0], &x, 1);
  59. ignoreUnused (bytesWritten);
  60. }
  61. }
  62. bool isEmpty() const
  63. {
  64. ScopedLock sl (lock);
  65. return queue.size() == 0;
  66. }
  67. bool dispatchNextEvent()
  68. {
  69. // This alternates between giving priority to XEvents or internal messages,
  70. // to keep everything running smoothly..
  71. if ((++totalEventCount & 1) != 0)
  72. return dispatchNextXEvent() || dispatchNextInternalMessage();
  73. return dispatchNextInternalMessage() || dispatchNextXEvent();
  74. }
  75. // Wait for an event (either XEvent, or an internal Message)
  76. bool sleepUntilEvent (const int timeoutMs)
  77. {
  78. if (! isEmpty())
  79. return true;
  80. if (display != nullptr)
  81. {
  82. ScopedXLock xlock;
  83. if (XPending (display))
  84. return true;
  85. }
  86. struct timeval tv;
  87. tv.tv_sec = 0;
  88. tv.tv_usec = timeoutMs * 1000;
  89. int fd0 = getWaitHandle();
  90. int fdmax = fd0;
  91. fd_set readset;
  92. FD_ZERO (&readset);
  93. FD_SET (fd0, &readset);
  94. if (display != nullptr)
  95. {
  96. ScopedXLock xlock;
  97. int fd1 = XConnectionNumber (display);
  98. FD_SET (fd1, &readset);
  99. fdmax = jmax (fd0, fd1);
  100. }
  101. const int ret = select (fdmax + 1, &readset, 0, 0, &tv);
  102. return (ret > 0); // ret <= 0 if error or timeout
  103. }
  104. //==============================================================================
  105. juce_DeclareSingleton_SingleThreaded_Minimal (InternalMessageQueue)
  106. private:
  107. CriticalSection lock;
  108. ReferenceCountedArray <MessageManager::MessageBase> queue;
  109. int fd[2];
  110. int bytesInSocket;
  111. int totalEventCount;
  112. int getWaitHandle() const noexcept { return fd[1]; }
  113. static bool setNonBlocking (int handle)
  114. {
  115. int socketFlags = fcntl (handle, F_GETFL, 0);
  116. if (socketFlags == -1)
  117. return false;
  118. socketFlags |= O_NONBLOCK;
  119. return fcntl (handle, F_SETFL, socketFlags) == 0;
  120. }
  121. static bool dispatchNextXEvent()
  122. {
  123. if (display == nullptr)
  124. return false;
  125. XEvent evt;
  126. {
  127. ScopedXLock xlock;
  128. if (! XPending (display))
  129. return false;
  130. XNextEvent (display, &evt);
  131. }
  132. if (evt.type == SelectionRequest && evt.xany.window == juce_messageWindowHandle
  133. && handleSelectionRequest != nullptr)
  134. handleSelectionRequest (evt.xselectionrequest);
  135. else if (evt.xany.window != juce_messageWindowHandle && dispatchWindowMessage != nullptr)
  136. dispatchWindowMessage (evt);
  137. return true;
  138. }
  139. MessageManager::MessageBase::Ptr popNextMessage()
  140. {
  141. const ScopedLock sl (lock);
  142. if (bytesInSocket > 0)
  143. {
  144. --bytesInSocket;
  145. const ScopedUnlock ul (lock);
  146. unsigned char x;
  147. ssize_t numBytes = read (fd[1], &x, 1);
  148. ignoreUnused (numBytes);
  149. }
  150. return queue.removeAndReturn (0);
  151. }
  152. bool dispatchNextInternalMessage()
  153. {
  154. if (const MessageManager::MessageBase::Ptr msg = popNextMessage())
  155. {
  156. JUCE_TRY
  157. {
  158. msg->messageCallback();
  159. return true;
  160. }
  161. JUCE_CATCH_EXCEPTION
  162. }
  163. return false;
  164. }
  165. };
  166. juce_ImplementSingleton_SingleThreaded (InternalMessageQueue)
  167. //==============================================================================
  168. namespace LinuxErrorHandling
  169. {
  170. static bool errorOccurred = false;
  171. static bool keyboardBreakOccurred = false;
  172. static XErrorHandler oldErrorHandler = (XErrorHandler) 0;
  173. static XIOErrorHandler oldIOErrorHandler = (XIOErrorHandler) 0;
  174. //==============================================================================
  175. // Usually happens when client-server connection is broken
  176. int ioErrorHandler (Display*)
  177. {
  178. DBG ("ERROR: connection to X server broken.. terminating.");
  179. if (JUCEApplicationBase::isStandaloneApp())
  180. MessageManager::getInstance()->stopDispatchLoop();
  181. errorOccurred = true;
  182. return 0;
  183. }
  184. int errorHandler (Display* display, XErrorEvent* event)
  185. {
  186. ignoreUnused (display, event);
  187. #if JUCE_DEBUG_XERRORS
  188. char errorStr[64] = { 0 };
  189. char requestStr[64] = { 0 };
  190. XGetErrorText (display, event->error_code, errorStr, 64);
  191. XGetErrorDatabaseText (display, "XRequest", String (event->request_code).toUTF8(), "Unknown", requestStr, 64);
  192. DBG ("ERROR: X returned " << errorStr << " for operation " << requestStr);
  193. #endif
  194. return 0;
  195. }
  196. void installXErrorHandlers()
  197. {
  198. oldIOErrorHandler = XSetIOErrorHandler (ioErrorHandler);
  199. oldErrorHandler = XSetErrorHandler (errorHandler);
  200. }
  201. void removeXErrorHandlers()
  202. {
  203. if (JUCEApplicationBase::isStandaloneApp())
  204. {
  205. XSetIOErrorHandler (oldIOErrorHandler);
  206. oldIOErrorHandler = 0;
  207. XSetErrorHandler (oldErrorHandler);
  208. oldErrorHandler = 0;
  209. }
  210. }
  211. //==============================================================================
  212. void keyboardBreakSignalHandler (int sig)
  213. {
  214. if (sig == SIGINT)
  215. keyboardBreakOccurred = true;
  216. }
  217. void installKeyboardBreakHandler()
  218. {
  219. struct sigaction saction;
  220. sigset_t maskSet;
  221. sigemptyset (&maskSet);
  222. saction.sa_handler = keyboardBreakSignalHandler;
  223. saction.sa_mask = maskSet;
  224. saction.sa_flags = 0;
  225. sigaction (SIGINT, &saction, 0);
  226. }
  227. }
  228. //==============================================================================
  229. void MessageManager::doPlatformSpecificInitialisation()
  230. {
  231. if (JUCEApplicationBase::isStandaloneApp())
  232. {
  233. // Initialise xlib for multiple thread support
  234. static bool initThreadCalled = false;
  235. if (! initThreadCalled)
  236. {
  237. if (! XInitThreads())
  238. {
  239. // This is fatal! Print error and closedown
  240. Logger::outputDebugString ("Failed to initialise xlib thread support.");
  241. Process::terminate();
  242. return;
  243. }
  244. initThreadCalled = true;
  245. }
  246. LinuxErrorHandling::installXErrorHandlers();
  247. LinuxErrorHandling::installKeyboardBreakHandler();
  248. }
  249. // Create the internal message queue
  250. InternalMessageQueue::getInstance();
  251. // Try to connect to a display
  252. String displayName (getenv ("DISPLAY"));
  253. if (displayName.isEmpty())
  254. displayName = ":0.0";
  255. display = XOpenDisplay (displayName.toUTF8());
  256. if (display != nullptr) // This is not fatal! we can run headless.
  257. {
  258. // Create a context to store user data associated with Windows we create
  259. windowHandleXContext = XUniqueContext();
  260. // We're only interested in client messages for this window, which are always sent
  261. XSetWindowAttributes swa;
  262. swa.event_mask = NoEventMask;
  263. // Create our message window (this will never be mapped)
  264. const int screen = DefaultScreen (display);
  265. juce_messageWindowHandle = XCreateWindow (display, RootWindow (display, screen),
  266. 0, 0, 1, 1, 0, 0, InputOnly,
  267. DefaultVisual (display, screen),
  268. CWEventMask, &swa);
  269. }
  270. }
  271. void MessageManager::doPlatformSpecificShutdown()
  272. {
  273. InternalMessageQueue::deleteInstance();
  274. if (display != nullptr && ! LinuxErrorHandling::errorOccurred)
  275. {
  276. XDestroyWindow (display, juce_messageWindowHandle);
  277. XCloseDisplay (display);
  278. juce_messageWindowHandle = 0;
  279. display = nullptr;
  280. LinuxErrorHandling::removeXErrorHandlers();
  281. }
  282. }
  283. bool MessageManager::postMessageToSystemQueue (MessageManager::MessageBase* const message)
  284. {
  285. if (LinuxErrorHandling::errorOccurred)
  286. return false;
  287. if (InternalMessageQueue* const queue = InternalMessageQueue::getInstanceWithoutCreating())
  288. {
  289. queue->postMessage (message);
  290. return true;
  291. }
  292. return false;
  293. }
  294. void MessageManager::broadcastMessage (const String& /* value */)
  295. {
  296. /* TODO */
  297. }
  298. // this function expects that it will NEVER be called simultaneously for two concurrent threads
  299. bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
  300. {
  301. while (! LinuxErrorHandling::errorOccurred)
  302. {
  303. if (LinuxErrorHandling::keyboardBreakOccurred)
  304. {
  305. LinuxErrorHandling::errorOccurred = true;
  306. if (JUCEApplicationBase::isStandaloneApp())
  307. Process::terminate();
  308. break;
  309. }
  310. InternalMessageQueue* const queue = InternalMessageQueue::getInstanceWithoutCreating();
  311. jassert (queue != nullptr);
  312. if (queue->dispatchNextEvent())
  313. return true;
  314. if (returnIfNoPendingMessages)
  315. break;
  316. queue->sleepUntilEvent (2000);
  317. }
  318. return false;
  319. }