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.

421 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../juce_Config.h"
  24. #include "linuxincludes.h"
  25. #include <stdio.h>
  26. #include <signal.h>
  27. #include <X11/Xlib.h>
  28. #include <X11/Xatom.h>
  29. #include <X11/Xresource.h>
  30. #include <X11/Xutil.h>
  31. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  32. BEGIN_JUCE_NAMESPACE
  33. #include "../../../src/juce_appframework/events/juce_MessageManager.h"
  34. #include "../../../src/juce_core/threads/juce_WaitableEvent.h"
  35. #include "../../../src/juce_core/threads/juce_Process.h"
  36. #include "../../../src/juce_core/threads/juce_ScopedLock.h"
  37. #ifdef JUCE_DEBUG
  38. #define JUCE_DEBUG_XERRORS 1
  39. #endif
  40. Display* display = 0; // This is also referenced from WindowDriver.cpp
  41. static Window juce_messageWindowHandle = None;
  42. #define SpecialAtom "JUCESpecialAtom"
  43. #define BroadcastAtom "JUCEBroadcastAtom"
  44. #define SpecialCallbackAtom "JUCESpecialCallbackAtom"
  45. static Atom specialId;
  46. static Atom broadcastId;
  47. static Atom specialCallbackId;
  48. // This is referenced from WindowDriver.cpp
  49. XContext improbableNumber;
  50. // Defined in WindowDriver.cpp
  51. extern void juce_windowMessageReceive (XEvent* event);
  52. struct MessageThreadFuncCall
  53. {
  54. MessageCallbackFunction* func;
  55. void* parameter;
  56. void* result;
  57. CriticalSection lock;
  58. WaitableEvent event;
  59. };
  60. static bool errorCondition = false;
  61. static XErrorHandler oldErrorHandler = (XErrorHandler) 0;
  62. static XIOErrorHandler oldIOErrorHandler = (XIOErrorHandler) 0;
  63. // (defined in another file to avoid problems including certain headers in this one)
  64. extern bool juce_isRunningAsApplication();
  65. // Usually happens when client-server connection is broken
  66. static int ioErrorHandler (Display* display)
  67. {
  68. DBG (T("ERROR: connection to X server broken.. terminating."));
  69. errorCondition = true;
  70. if (juce_isRunningAsApplication())
  71. Process::terminate();
  72. return 0;
  73. }
  74. // A protocol error has occurred
  75. static int errorHandler (Display* display, XErrorEvent* event)
  76. {
  77. #ifdef JUCE_DEBUG_XERRORS
  78. char errorStr[64] = { 0 };
  79. char requestStr[64] = { 0 };
  80. XGetErrorText (display, event->error_code, errorStr, 64);
  81. XGetErrorDatabaseText (display,
  82. "XRequest",
  83. (const char*) String (event->request_code),
  84. "Unknown",
  85. requestStr,
  86. 64);
  87. DBG (T("ERROR: X returned ") + String (errorStr) + T(" for operation ") + String (requestStr));
  88. #endif
  89. return 0;
  90. }
  91. static bool breakIn = false;
  92. // Breakin from keyboard
  93. static void sig_handler (int sig)
  94. {
  95. if (sig == SIGINT)
  96. {
  97. breakIn = true;
  98. return;
  99. }
  100. static bool reentrant = false;
  101. if (reentrant == false)
  102. {
  103. reentrant = true;
  104. // Illegal instruction
  105. fflush (stdout);
  106. Logger::outputDebugString ("ERROR: Program executed illegal instruction.. terminating");
  107. errorCondition = true;
  108. if (juce_isRunningAsApplication())
  109. Process::terminate();
  110. }
  111. else
  112. {
  113. if (juce_isRunningAsApplication())
  114. exit(0);
  115. }
  116. }
  117. //==============================================================================
  118. void MessageManager::doPlatformSpecificInitialisation()
  119. {
  120. // Initialise xlib for multiple thread support
  121. static bool initThreadCalled = false;
  122. if (! initThreadCalled)
  123. {
  124. if (! XInitThreads())
  125. {
  126. // This is fatal! Print error and closedown
  127. Logger::outputDebugString ("Failed to initialise xlib thread support.");
  128. if (juce_isRunningAsApplication())
  129. Process::terminate();
  130. return;
  131. }
  132. initThreadCalled = true;
  133. }
  134. // This is called if the client/server connection is broken
  135. oldIOErrorHandler = XSetIOErrorHandler (ioErrorHandler);
  136. // This is called if a protocol error occurs
  137. oldErrorHandler = XSetErrorHandler (errorHandler);
  138. // Install signal handler for break-in
  139. struct sigaction saction;
  140. sigset_t maskSet;
  141. sigemptyset (&maskSet);
  142. saction.sa_handler = sig_handler;
  143. saction.sa_mask = maskSet;
  144. saction.sa_flags = 0;
  145. sigaction (SIGINT, &saction, NULL);
  146. #ifndef _DEBUG
  147. // Setup signal handlers for various fatal errors
  148. sigaction (SIGILL, &saction, NULL);
  149. sigaction (SIGBUS, &saction, NULL);
  150. sigaction (SIGFPE, &saction, NULL);
  151. sigaction (SIGSEGV, &saction, NULL);
  152. sigaction (SIGSYS, &saction, NULL);
  153. #endif
  154. String displayName (getenv ("DISPLAY"));
  155. if (displayName.isEmpty())
  156. displayName = T(":0.0");
  157. display = XOpenDisplay (displayName);
  158. if (display == 0)
  159. {
  160. // This is fatal! Print error and closedown
  161. Logger::outputDebugString ("Failed to open the X display.");
  162. if (juce_isRunningAsApplication())
  163. Process::terminate();
  164. return;
  165. }
  166. // Get defaults for various properties
  167. int screen = DefaultScreen (display);
  168. Window root = RootWindow (display, screen);
  169. Visual* visual = DefaultVisual (display, screen);
  170. // Create atoms for our ClientMessages (these cannot be deleted)
  171. specialId = XInternAtom (display, SpecialAtom, false);
  172. broadcastId = XInternAtom (display, BroadcastAtom, false);
  173. specialCallbackId = XInternAtom (display, SpecialCallbackAtom, false);
  174. // Create a context to store user data associated with Windows we
  175. // create in WindowDriver
  176. improbableNumber = XUniqueContext();
  177. // We're only interested in client messages for this window
  178. // which are always sent
  179. XSetWindowAttributes swa;
  180. swa.event_mask = NoEventMask;
  181. // Create our message window (this will never be mapped)
  182. juce_messageWindowHandle = XCreateWindow (display, root,
  183. 0, 0, 1, 1, 0, 0, InputOnly,
  184. visual, CWEventMask, &swa);
  185. }
  186. void MessageManager::doPlatformSpecificShutdown()
  187. {
  188. if (errorCondition == false)
  189. {
  190. XDestroyWindow (display, juce_messageWindowHandle);
  191. XCloseDisplay (display);
  192. // reset pointers
  193. juce_messageWindowHandle = 0;
  194. display = 0;
  195. // Restore original error handlers
  196. XSetIOErrorHandler (oldIOErrorHandler);
  197. oldIOErrorHandler = 0;
  198. XSetErrorHandler (oldErrorHandler);
  199. oldErrorHandler = 0;
  200. }
  201. }
  202. bool juce_postMessageToSystemQueue (void* message)
  203. {
  204. if (errorCondition)
  205. return false;
  206. XClientMessageEvent clientMsg;
  207. clientMsg.display = display;
  208. clientMsg.window = juce_messageWindowHandle;
  209. clientMsg.type = ClientMessage;
  210. clientMsg.format = 32;
  211. clientMsg.message_type = specialId;
  212. #if JUCE_64BIT
  213. clientMsg.data.l[0] = (long) (0x00000000ffffffff & (((uint64) message) >> 32));
  214. clientMsg.data.l[1] = (long) (0x00000000ffffffff & (long) message);
  215. #else
  216. clientMsg.data.l[0] = (long) message;
  217. #endif
  218. XSendEvent (display, juce_messageWindowHandle, false,
  219. NoEventMask, (XEvent*) &clientMsg);
  220. XFlush (display); // This is necessary to ensure the event is delivered
  221. return true;
  222. }
  223. void MessageManager::broadcastMessage (const String& value) throw()
  224. {
  225. }
  226. void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func,
  227. void* parameter)
  228. {
  229. void* retVal = 0;
  230. if (! errorCondition)
  231. {
  232. if (! isThisTheMessageThread())
  233. {
  234. static MessageThreadFuncCall messageFuncCallContext;
  235. const ScopedLock sl (messageFuncCallContext.lock);
  236. XClientMessageEvent clientMsg;
  237. clientMsg.display = display;
  238. clientMsg.window = juce_messageWindowHandle;
  239. clientMsg.type = ClientMessage;
  240. clientMsg.format = 32;
  241. clientMsg.message_type = specialCallbackId;
  242. #if JUCE_64BIT
  243. clientMsg.data.l[0] = (long) (0x00000000ffffffff & (((uint64) &messageFuncCallContext) >> 32));
  244. clientMsg.data.l[1] = (long) (0x00000000ffffffff & (uint64) &messageFuncCallContext);
  245. #else
  246. clientMsg.data.l[0] = (long) &messageFuncCallContext;
  247. #endif
  248. messageFuncCallContext.func = func;
  249. messageFuncCallContext.parameter = parameter;
  250. if (XSendEvent (display, juce_messageWindowHandle, false, NoEventMask, (XEvent*) &clientMsg) == 0)
  251. return 0;
  252. XFlush (display); // This is necessary to ensure the event is delivered
  253. // Wait for it to complete before continuing
  254. messageFuncCallContext.event.wait();
  255. retVal = messageFuncCallContext.result;
  256. }
  257. else
  258. {
  259. // Just call the function directly
  260. retVal = func (parameter);
  261. }
  262. }
  263. return retVal;
  264. }
  265. bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
  266. {
  267. if (errorCondition)
  268. return false;
  269. if (breakIn)
  270. {
  271. errorCondition = true;
  272. if (juce_isRunningAsApplication())
  273. Process::terminate();
  274. return false;
  275. }
  276. if (returnIfNoPendingMessages && ! XPending (display))
  277. return false;
  278. XEvent evt;
  279. XNextEvent (display, &evt);
  280. if (evt.type == ClientMessage && evt.xany.window == juce_messageWindowHandle)
  281. {
  282. XClientMessageEvent* const clientMsg = (XClientMessageEvent*) &evt;
  283. if (clientMsg->format != 32)
  284. {
  285. jassertfalse
  286. DBG ("Error: juce_dispatchNextMessageOnSystemQueue received malformed client message.");
  287. }
  288. else
  289. {
  290. JUCE_TRY
  291. {
  292. #if JUCE_64BIT
  293. void* const messagePtr
  294. = (void*) ((0xffffffff00000000 & (((uint64) clientMsg->data.l[0]) << 32))
  295. | (clientMsg->data.l[1] & 0x00000000ffffffff));
  296. #else
  297. void* const messagePtr = (void*) (clientMsg->data.l[0]);
  298. #endif
  299. if (clientMsg->message_type == specialId)
  300. {
  301. MessageManager::getInstance()->deliverMessage (messagePtr);
  302. }
  303. else if (clientMsg->message_type == specialCallbackId)
  304. {
  305. MessageThreadFuncCall* const call = (MessageThreadFuncCall*) messagePtr;
  306. MessageCallbackFunction* func = call->func;
  307. call->result = (*func) (call->parameter);
  308. call->event.signal();
  309. }
  310. else if (clientMsg->message_type == broadcastId)
  311. {
  312. #if 0
  313. TCHAR buffer[8192];
  314. zeromem (buffer, sizeof (buffer));
  315. if (GlobalGetAtomName ((ATOM) lParam, buffer, 8192) != 0)
  316. mq->deliverBroadcastMessage (String (buffer));
  317. #endif
  318. }
  319. else
  320. {
  321. DBG ("Error: juce_dispatchNextMessageOnSystemQueue received unknown client message.");
  322. }
  323. }
  324. JUCE_CATCH_ALL
  325. }
  326. }
  327. else if (evt.xany.window != juce_messageWindowHandle)
  328. {
  329. juce_windowMessageReceive (&evt);
  330. }
  331. return true;
  332. }
  333. END_JUCE_NAMESPACE