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.

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