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