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.

408 lines
12KB

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