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.

402 lines
12KB

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