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.

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