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.

445 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-10 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. // (This file gets included by juce_linux_NativeCode.cpp, rather than being
  19. // compiled on its own).
  20. #if JUCE_INCLUDED_FILE
  21. //==============================================================================
  22. #if JUCE_DEBUG && ! defined (JUCE_DEBUG_XERRORS)
  23. #define JUCE_DEBUG_XERRORS 1
  24. #endif
  25. Display* display = 0;
  26. Window juce_messageWindowHandle = None;
  27. XContext windowHandleXContext; // This is referenced from Windowing.cpp
  28. extern void juce_windowMessageReceive (XEvent* event); // Defined in Windowing.cpp
  29. extern void juce_handleSelectionRequest (XSelectionRequestEvent &evt); // Defined in Clipboard.cpp
  30. //==============================================================================
  31. ScopedXLock::ScopedXLock() { XLockDisplay (display); }
  32. ScopedXLock::~ScopedXLock() { XUnlockDisplay (display); }
  33. //==============================================================================
  34. class InternalMessageQueue
  35. {
  36. public:
  37. InternalMessageQueue()
  38. : bytesInSocket (0),
  39. totalEventCount (0)
  40. {
  41. int ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd);
  42. (void) ret; jassert (ret == 0);
  43. //setNonBlocking (fd[0]);
  44. //setNonBlocking (fd[1]);
  45. }
  46. ~InternalMessageQueue()
  47. {
  48. close (fd[0]);
  49. close (fd[1]);
  50. clearSingletonInstance();
  51. }
  52. //==============================================================================
  53. void postMessage (Message* msg)
  54. {
  55. const int maxBytesInSocketQueue = 128;
  56. ScopedLock sl (lock);
  57. queue.add (msg);
  58. if (bytesInSocket < maxBytesInSocketQueue)
  59. {
  60. ++bytesInSocket;
  61. ScopedUnlock ul (lock);
  62. const unsigned char x = 0xff;
  63. size_t bytesWritten = write (fd[0], &x, 1);
  64. (void) bytesWritten;
  65. }
  66. }
  67. bool isEmpty() const
  68. {
  69. ScopedLock sl (lock);
  70. return queue.size() == 0;
  71. }
  72. bool dispatchNextEvent()
  73. {
  74. // This alternates between giving priority to XEvents or internal messages,
  75. // to keep everything running smoothly..
  76. if ((++totalEventCount & 1) != 0)
  77. return dispatchNextXEvent() || dispatchNextInternalMessage();
  78. else
  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 != 0)
  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 != 0)
  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. struct MessageThreadFuncCall
  112. {
  113. enum { uniqueID = 0x73774623 };
  114. MessageCallbackFunction* func;
  115. void* parameter;
  116. void* result;
  117. CriticalSection lock;
  118. WaitableEvent event;
  119. };
  120. //==============================================================================
  121. juce_DeclareSingleton_SingleThreaded_Minimal (InternalMessageQueue);
  122. private:
  123. CriticalSection lock;
  124. OwnedArray <Message> queue;
  125. int fd[2];
  126. int bytesInSocket;
  127. int totalEventCount;
  128. int getWaitHandle() const throw() { return fd[1]; }
  129. static bool setNonBlocking (int handle)
  130. {
  131. int socketFlags = fcntl (handle, F_GETFL, 0);
  132. if (socketFlags == -1)
  133. return false;
  134. socketFlags |= O_NONBLOCK;
  135. return fcntl (handle, F_SETFL, socketFlags) == 0;
  136. }
  137. static bool dispatchNextXEvent()
  138. {
  139. if (display == 0)
  140. return false;
  141. XEvent evt;
  142. {
  143. ScopedXLock xlock;
  144. if (! XPending (display))
  145. return false;
  146. XNextEvent (display, &evt);
  147. }
  148. if (evt.type == SelectionRequest && evt.xany.window == juce_messageWindowHandle)
  149. juce_handleSelectionRequest (evt.xselectionrequest);
  150. else if (evt.xany.window != juce_messageWindowHandle)
  151. juce_windowMessageReceive (&evt);
  152. return true;
  153. }
  154. Message* popNextMessage()
  155. {
  156. ScopedLock sl (lock);
  157. if (bytesInSocket > 0)
  158. {
  159. --bytesInSocket;
  160. ScopedUnlock ul (lock);
  161. unsigned char x;
  162. size_t numBytes = read (fd[1], &x, 1);
  163. (void) numBytes;
  164. }
  165. return queue.removeAndReturn (0);
  166. }
  167. bool dispatchNextInternalMessage()
  168. {
  169. ScopedPointer <Message> msg (popNextMessage());
  170. if (msg == 0)
  171. return false;
  172. if (msg->intParameter1 == MessageThreadFuncCall::uniqueID)
  173. {
  174. // Handle callback message
  175. MessageThreadFuncCall* const call = (MessageThreadFuncCall*) msg->pointerParameter;
  176. call->result = (*(call->func)) (call->parameter);
  177. call->event.signal();
  178. }
  179. else
  180. {
  181. // Handle "normal" messages
  182. MessageManager::getInstance()->deliverMessage (msg.release());
  183. }
  184. return true;
  185. }
  186. };
  187. juce_ImplementSingleton_SingleThreaded (InternalMessageQueue);
  188. //==============================================================================
  189. namespace LinuxErrorHandling
  190. {
  191. //==============================================================================
  192. static bool errorOccurred = false;
  193. static bool keyboardBreakOccurred = false;
  194. static XErrorHandler oldErrorHandler = (XErrorHandler) 0;
  195. static XIOErrorHandler oldIOErrorHandler = (XIOErrorHandler) 0;
  196. //==============================================================================
  197. // Usually happens when client-server connection is broken
  198. static int ioErrorHandler (Display* display)
  199. {
  200. DBG ("ERROR: connection to X server broken.. terminating.");
  201. if (JUCEApplication::isStandaloneApp())
  202. MessageManager::getInstance()->stopDispatchLoop();
  203. errorOccurred = true;
  204. return 0;
  205. }
  206. // A protocol error has occurred
  207. static int juce_XErrorHandler (Display* display, XErrorEvent* event)
  208. {
  209. #if JUCE_DEBUG_XERRORS
  210. char errorStr[64] = { 0 };
  211. char requestStr[64] = { 0 };
  212. XGetErrorText (display, event->error_code, errorStr, 64);
  213. XGetErrorDatabaseText (display, "XRequest", String (event->request_code).toCString(), "Unknown", requestStr, 64);
  214. DBG ("ERROR: X returned " + String (errorStr) + " for operation " + String (requestStr));
  215. #endif
  216. return 0;
  217. }
  218. static void installXErrorHandlers()
  219. {
  220. oldIOErrorHandler = XSetIOErrorHandler (ioErrorHandler);
  221. oldErrorHandler = XSetErrorHandler (juce_XErrorHandler);
  222. }
  223. static void removeXErrorHandlers()
  224. {
  225. XSetIOErrorHandler (oldIOErrorHandler);
  226. oldIOErrorHandler = 0;
  227. XSetErrorHandler (oldErrorHandler);
  228. oldErrorHandler = 0;
  229. }
  230. //==============================================================================
  231. static void keyboardBreakSignalHandler (int sig)
  232. {
  233. if (sig == SIGINT)
  234. keyboardBreakOccurred = true;
  235. }
  236. static void installKeyboardBreakHandler()
  237. {
  238. struct sigaction saction;
  239. sigset_t maskSet;
  240. sigemptyset (&maskSet);
  241. saction.sa_handler = keyboardBreakSignalHandler;
  242. saction.sa_mask = maskSet;
  243. saction.sa_flags = 0;
  244. sigaction (SIGINT, &saction, 0);
  245. }
  246. }
  247. //==============================================================================
  248. void MessageManager::doPlatformSpecificInitialisation()
  249. {
  250. // Initialise xlib for multiple thread support
  251. static bool initThreadCalled = false;
  252. if (! initThreadCalled)
  253. {
  254. if (! XInitThreads())
  255. {
  256. // This is fatal! Print error and closedown
  257. Logger::outputDebugString ("Failed to initialise xlib thread support.");
  258. if (JUCEApplication::isStandaloneApp())
  259. Process::terminate();
  260. return;
  261. }
  262. initThreadCalled = true;
  263. }
  264. LinuxErrorHandling::installXErrorHandlers();
  265. LinuxErrorHandling::installKeyboardBreakHandler();
  266. // Create the internal message queue
  267. InternalMessageQueue::getInstance();
  268. // Try to connect to a display
  269. String displayName (getenv ("DISPLAY"));
  270. if (displayName.isEmpty())
  271. displayName = ":0.0";
  272. display = XOpenDisplay (displayName.toCString());
  273. if (display != 0) // This is not fatal! we can run headless.
  274. {
  275. // Create a context to store user data associated with Windows we create in WindowDriver
  276. windowHandleXContext = XUniqueContext();
  277. // We're only interested in client messages for this window, which are always sent
  278. XSetWindowAttributes swa;
  279. swa.event_mask = NoEventMask;
  280. // Create our message window (this will never be mapped)
  281. const int screen = DefaultScreen (display);
  282. juce_messageWindowHandle = XCreateWindow (display, RootWindow (display, screen),
  283. 0, 0, 1, 1, 0, 0, InputOnly,
  284. DefaultVisual (display, screen),
  285. CWEventMask, &swa);
  286. }
  287. }
  288. void MessageManager::doPlatformSpecificShutdown()
  289. {
  290. InternalMessageQueue::deleteInstance();
  291. if (display != 0 && ! LinuxErrorHandling::errorOccurred)
  292. {
  293. XDestroyWindow (display, juce_messageWindowHandle);
  294. XCloseDisplay (display);
  295. juce_messageWindowHandle = 0;
  296. display = 0;
  297. LinuxErrorHandling::removeXErrorHandlers();
  298. }
  299. }
  300. bool juce_postMessageToSystemQueue (Message* message)
  301. {
  302. if (LinuxErrorHandling::errorOccurred)
  303. return false;
  304. InternalMessageQueue::getInstanceWithoutCreating()->postMessage (message);
  305. return true;
  306. }
  307. void MessageManager::broadcastMessage (const String& value)
  308. {
  309. /* TODO */
  310. }
  311. void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
  312. {
  313. if (LinuxErrorHandling::errorOccurred)
  314. return 0;
  315. if (isThisTheMessageThread())
  316. return func (parameter);
  317. InternalMessageQueue::MessageThreadFuncCall messageCallContext;
  318. messageCallContext.func = func;
  319. messageCallContext.parameter = parameter;
  320. InternalMessageQueue::getInstanceWithoutCreating()
  321. ->postMessage (new Message (InternalMessageQueue::MessageThreadFuncCall::uniqueID,
  322. 0, 0, &messageCallContext));
  323. // Wait for it to complete before continuing
  324. messageCallContext.event.wait();
  325. return messageCallContext.result;
  326. }
  327. // this function expects that it will NEVER be called simultaneously for two concurrent threads
  328. bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
  329. {
  330. while (! LinuxErrorHandling::errorOccurred)
  331. {
  332. if (LinuxErrorHandling::keyboardBreakOccurred)
  333. {
  334. LinuxErrorHandling::errorOccurred = true;
  335. if (JUCEApplication::isStandaloneApp())
  336. Process::terminate();
  337. break;
  338. }
  339. if (InternalMessageQueue::getInstanceWithoutCreating()->dispatchNextEvent())
  340. return true;
  341. if (returnIfNoPendingMessages)
  342. break;
  343. InternalMessageQueue::getInstanceWithoutCreating()->sleepUntilEvent (2000);
  344. }
  345. return false;
  346. }
  347. #endif