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.

435 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #if JUCE_DEBUG && ! defined (JUCE_DEBUG_XERRORS)
  19. #define JUCE_DEBUG_XERRORS 1
  20. #endif
  21. Display* display = nullptr;
  22. Window juce_messageWindowHandle = None;
  23. XContext windowHandleXContext; // This is referenced from Windowing.cpp
  24. extern void juce_windowMessageReceive (XEvent* event); // Defined in Windowing.cpp
  25. extern void juce_handleSelectionRequest (XSelectionRequestEvent &evt); // Defined in Clipboard.cpp
  26. //==============================================================================
  27. ScopedXLock::ScopedXLock() { XLockDisplay (display); }
  28. ScopedXLock::~ScopedXLock() { XUnlockDisplay (display); }
  29. //==============================================================================
  30. class InternalMessageQueue
  31. {
  32. public:
  33. InternalMessageQueue()
  34. : bytesInSocket (0),
  35. totalEventCount (0)
  36. {
  37. int ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd);
  38. (void) ret; jassert (ret == 0);
  39. }
  40. ~InternalMessageQueue()
  41. {
  42. close (fd[0]);
  43. close (fd[1]);
  44. clearSingletonInstance();
  45. }
  46. //==============================================================================
  47. void postMessage (Message* msg)
  48. {
  49. const int maxBytesInSocketQueue = 128;
  50. ScopedLock sl (lock);
  51. queue.add (msg);
  52. if (bytesInSocket < maxBytesInSocketQueue)
  53. {
  54. ++bytesInSocket;
  55. ScopedUnlock ul (lock);
  56. const unsigned char x = 0xff;
  57. size_t bytesWritten = write (fd[0], &x, 1);
  58. (void) bytesWritten;
  59. }
  60. }
  61. bool isEmpty() const
  62. {
  63. ScopedLock sl (lock);
  64. return queue.size() == 0;
  65. }
  66. bool dispatchNextEvent()
  67. {
  68. // This alternates between giving priority to XEvents or internal messages,
  69. // to keep everything running smoothly..
  70. if ((++totalEventCount & 1) != 0)
  71. return dispatchNextXEvent() || dispatchNextInternalMessage();
  72. else
  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 != 0)
  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 != 0)
  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 <Message> 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 == 0)
  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. juce_handleSelectionRequest (evt.xselectionrequest);
  134. else if (evt.xany.window != juce_messageWindowHandle)
  135. juce_windowMessageReceive (&evt);
  136. return true;
  137. }
  138. Message::Ptr popNextMessage()
  139. {
  140. const ScopedLock sl (lock);
  141. if (bytesInSocket > 0)
  142. {
  143. --bytesInSocket;
  144. const ScopedUnlock ul (lock);
  145. unsigned char x;
  146. size_t numBytes = read (fd[1], &x, 1);
  147. (void) numBytes;
  148. }
  149. return queue.removeAndReturn (0);
  150. }
  151. bool dispatchNextInternalMessage()
  152. {
  153. const Message::Ptr msg (popNextMessage());
  154. if (msg == nullptr)
  155. return false;
  156. MessageManager::getInstance()->deliverMessage (msg);
  157. return true;
  158. }
  159. };
  160. juce_ImplementSingleton_SingleThreaded (InternalMessageQueue);
  161. //==============================================================================
  162. namespace LinuxErrorHandling
  163. {
  164. static bool errorOccurred = false;
  165. static bool keyboardBreakOccurred = false;
  166. static XErrorHandler oldErrorHandler = (XErrorHandler) 0;
  167. static XIOErrorHandler oldIOErrorHandler = (XIOErrorHandler) 0;
  168. //==============================================================================
  169. // Usually happens when client-server connection is broken
  170. int ioErrorHandler (Display* display)
  171. {
  172. DBG ("ERROR: connection to X server broken.. terminating.");
  173. if (JUCEApplicationBase::isStandaloneApp())
  174. MessageManager::getInstance()->stopDispatchLoop();
  175. errorOccurred = true;
  176. return 0;
  177. }
  178. int errorHandler (Display* display, XErrorEvent* event)
  179. {
  180. #if JUCE_DEBUG_XERRORS
  181. char errorStr[64] = { 0 };
  182. char requestStr[64] = { 0 };
  183. XGetErrorText (display, event->error_code, errorStr, 64);
  184. XGetErrorDatabaseText (display, "XRequest", String (event->request_code).toUTF8(), "Unknown", requestStr, 64);
  185. DBG ("ERROR: X returned " + String (errorStr) + " for operation " + String (requestStr));
  186. #endif
  187. return 0;
  188. }
  189. void installXErrorHandlers()
  190. {
  191. oldIOErrorHandler = XSetIOErrorHandler (ioErrorHandler);
  192. oldErrorHandler = XSetErrorHandler (errorHandler);
  193. }
  194. void removeXErrorHandlers()
  195. {
  196. if (JUCEApplicationBase::isStandaloneApp())
  197. {
  198. XSetIOErrorHandler (oldIOErrorHandler);
  199. oldIOErrorHandler = 0;
  200. XSetErrorHandler (oldErrorHandler);
  201. oldErrorHandler = 0;
  202. }
  203. }
  204. //==============================================================================
  205. void keyboardBreakSignalHandler (int sig)
  206. {
  207. if (sig == SIGINT)
  208. keyboardBreakOccurred = true;
  209. }
  210. void installKeyboardBreakHandler()
  211. {
  212. struct sigaction saction;
  213. sigset_t maskSet;
  214. sigemptyset (&maskSet);
  215. saction.sa_handler = keyboardBreakSignalHandler;
  216. saction.sa_mask = maskSet;
  217. saction.sa_flags = 0;
  218. sigaction (SIGINT, &saction, 0);
  219. }
  220. }
  221. //==============================================================================
  222. void MessageManager::doPlatformSpecificInitialisation()
  223. {
  224. if (JUCEApplicationBase::isStandaloneApp())
  225. {
  226. // Initialise xlib for multiple thread support
  227. static bool initThreadCalled = false;
  228. if (! initThreadCalled)
  229. {
  230. if (! XInitThreads())
  231. {
  232. // This is fatal! Print error and closedown
  233. Logger::outputDebugString ("Failed to initialise xlib thread support.");
  234. Process::terminate();
  235. return;
  236. }
  237. initThreadCalled = true;
  238. }
  239. LinuxErrorHandling::installXErrorHandlers();
  240. LinuxErrorHandling::installKeyboardBreakHandler();
  241. }
  242. // Create the internal message queue
  243. InternalMessageQueue::getInstance();
  244. // Try to connect to a display
  245. String displayName (getenv ("DISPLAY"));
  246. if (displayName.isEmpty())
  247. displayName = ":0.0";
  248. display = XOpenDisplay (displayName.toUTF8());
  249. if (display != 0) // This is not fatal! we can run headless.
  250. {
  251. // Create a context to store user data associated with Windows we create in WindowDriver
  252. windowHandleXContext = XUniqueContext();
  253. // We're only interested in client messages for this window, which are always sent
  254. XSetWindowAttributes swa;
  255. swa.event_mask = NoEventMask;
  256. // Create our message window (this will never be mapped)
  257. const int screen = DefaultScreen (display);
  258. juce_messageWindowHandle = XCreateWindow (display, RootWindow (display, screen),
  259. 0, 0, 1, 1, 0, 0, InputOnly,
  260. DefaultVisual (display, screen),
  261. CWEventMask, &swa);
  262. }
  263. }
  264. void MessageManager::doPlatformSpecificShutdown()
  265. {
  266. InternalMessageQueue::deleteInstance();
  267. if (display != 0 && ! LinuxErrorHandling::errorOccurred)
  268. {
  269. XDestroyWindow (display, juce_messageWindowHandle);
  270. XCloseDisplay (display);
  271. juce_messageWindowHandle = 0;
  272. display = nullptr;
  273. LinuxErrorHandling::removeXErrorHandlers();
  274. }
  275. }
  276. bool MessageManager::postMessageToSystemQueue (Message* message)
  277. {
  278. if (LinuxErrorHandling::errorOccurred)
  279. return false;
  280. InternalMessageQueue::getInstanceWithoutCreating()->postMessage (message);
  281. return true;
  282. }
  283. void MessageManager::broadcastMessage (const String& value)
  284. {
  285. /* TODO */
  286. }
  287. //==============================================================================
  288. class AsyncFunctionCaller : public AsyncUpdater
  289. {
  290. public:
  291. static void* call (MessageCallbackFunction* func_, void* parameter_)
  292. {
  293. if (MessageManager::getInstance()->isThisTheMessageThread())
  294. return func_ (parameter_);
  295. AsyncFunctionCaller caller (func_, parameter_);
  296. caller.triggerAsyncUpdate();
  297. caller.finished.wait();
  298. return caller.result;
  299. }
  300. void handleAsyncUpdate()
  301. {
  302. result = (*func) (parameter);
  303. finished.signal();
  304. }
  305. private:
  306. WaitableEvent finished;
  307. MessageCallbackFunction* func;
  308. void* parameter;
  309. void* volatile result;
  310. AsyncFunctionCaller (MessageCallbackFunction* func_, void* parameter_)
  311. : result (nullptr), func (func_), parameter (parameter_)
  312. {}
  313. JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCaller);
  314. };
  315. void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
  316. {
  317. if (LinuxErrorHandling::errorOccurred)
  318. return nullptr;
  319. return AsyncFunctionCaller::call (func, parameter);
  320. }
  321. // this function expects that it will NEVER be called simultaneously for two concurrent threads
  322. bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
  323. {
  324. while (! LinuxErrorHandling::errorOccurred)
  325. {
  326. if (LinuxErrorHandling::keyboardBreakOccurred)
  327. {
  328. LinuxErrorHandling::errorOccurred = true;
  329. if (JUCEApplicationBase::isStandaloneApp())
  330. Process::terminate();
  331. break;
  332. }
  333. InternalMessageQueue* const queue = InternalMessageQueue::getInstanceWithoutCreating();
  334. jassert (queue != nullptr);
  335. if (queue->dispatchNextEvent())
  336. return true;
  337. if (returnIfNoPendingMessages)
  338. break;
  339. queue->sleepUntilEvent (2000);
  340. }
  341. return false;
  342. }