Add remaining files
[juce-lv2.git] / juce / source / src / native / linux / juce_linux_Messaging.cpp
blobc857ff6b2701ba9ae035987d91750c2f79c9b6ca
1 /*
2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 // (This file gets included by juce_linux_NativeCode.cpp, rather than being
27 // compiled on its own).
28 #if JUCE_INCLUDED_FILE
30 //==============================================================================
31 #if JUCE_DEBUG && ! defined (JUCE_DEBUG_XERRORS)
32 #define JUCE_DEBUG_XERRORS 1
33 #endif
35 Display* display = nullptr;
36 Window juce_messageWindowHandle = None;
37 XContext windowHandleXContext; // This is referenced from Windowing.cpp
39 extern void juce_windowMessageReceive (XEvent* event); // Defined in Windowing.cpp
40 extern void juce_handleSelectionRequest (XSelectionRequestEvent &evt); // Defined in Clipboard.cpp
42 //==============================================================================
43 ScopedXLock::ScopedXLock() { XLockDisplay (display); }
44 ScopedXLock::~ScopedXLock() { XUnlockDisplay (display); }
46 //==============================================================================
47 class InternalMessageQueue
49 public:
50 InternalMessageQueue()
51 : bytesInSocket (0),
52 totalEventCount (0)
54 int ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd);
55 (void) ret; jassert (ret == 0);
57 //setNonBlocking (fd[0]);
58 //setNonBlocking (fd[1]);
61 ~InternalMessageQueue()
63 close (fd[0]);
64 close (fd[1]);
66 clearSingletonInstance();
69 //==============================================================================
70 void postMessage (Message* msg)
72 const int maxBytesInSocketQueue = 128;
74 ScopedLock sl (lock);
75 queue.add (msg);
77 if (bytesInSocket < maxBytesInSocketQueue)
79 ++bytesInSocket;
81 ScopedUnlock ul (lock);
82 const unsigned char x = 0xff;
83 size_t bytesWritten = write (fd[0], &x, 1);
84 (void) bytesWritten;
88 bool isEmpty() const
90 ScopedLock sl (lock);
91 return queue.size() == 0;
94 bool dispatchNextEvent()
96 // This alternates between giving priority to XEvents or internal messages,
97 // to keep everything running smoothly..
98 if ((++totalEventCount & 1) != 0)
99 return dispatchNextXEvent() || dispatchNextInternalMessage();
100 else
101 return dispatchNextInternalMessage() || dispatchNextXEvent();
104 // Wait for an event (either XEvent, or an internal Message)
105 bool sleepUntilEvent (const int timeoutMs)
107 if (! isEmpty())
108 return true;
110 if (display != 0)
112 ScopedXLock xlock;
113 if (XPending (display))
114 return true;
117 struct timeval tv;
118 tv.tv_sec = 0;
119 tv.tv_usec = timeoutMs * 1000;
120 int fd0 = getWaitHandle();
121 int fdmax = fd0;
123 fd_set readset;
124 FD_ZERO (&readset);
125 FD_SET (fd0, &readset);
127 if (display != 0)
129 ScopedXLock xlock;
130 int fd1 = XConnectionNumber (display);
131 FD_SET (fd1, &readset);
132 fdmax = jmax (fd0, fd1);
135 const int ret = select (fdmax + 1, &readset, 0, 0, &tv);
136 return (ret > 0); // ret <= 0 if error or timeout
139 //==============================================================================
140 struct MessageThreadFuncCall
142 enum { uniqueID = 0x73774623 };
144 MessageCallbackFunction* func;
145 void* parameter;
146 void* result;
147 CriticalSection lock;
148 WaitableEvent event;
151 //==============================================================================
152 juce_DeclareSingleton_SingleThreaded_Minimal (InternalMessageQueue);
154 private:
155 CriticalSection lock;
156 ReferenceCountedArray <Message> queue;
157 int fd[2];
158 int bytesInSocket;
159 int totalEventCount;
161 int getWaitHandle() const noexcept { return fd[1]; }
163 static bool setNonBlocking (int handle)
165 int socketFlags = fcntl (handle, F_GETFL, 0);
166 if (socketFlags == -1)
167 return false;
169 socketFlags |= O_NONBLOCK;
170 return fcntl (handle, F_SETFL, socketFlags) == 0;
173 static bool dispatchNextXEvent()
175 if (display == 0)
176 return false;
178 XEvent evt;
181 ScopedXLock xlock;
182 if (! XPending (display))
183 return false;
185 XNextEvent (display, &evt);
188 if (evt.type == SelectionRequest && evt.xany.window == juce_messageWindowHandle)
189 juce_handleSelectionRequest (evt.xselectionrequest);
190 else if (evt.xany.window != juce_messageWindowHandle)
191 juce_windowMessageReceive (&evt);
193 return true;
196 Message::Ptr popNextMessage()
198 const ScopedLock sl (lock);
200 if (bytesInSocket > 0)
202 --bytesInSocket;
204 const ScopedUnlock ul (lock);
205 unsigned char x;
206 size_t numBytes = read (fd[1], &x, 1);
207 (void) numBytes;
210 return queue.removeAndReturn (0);
213 bool dispatchNextInternalMessage()
215 const Message::Ptr msg (popNextMessage());
217 if (msg == nullptr)
218 return false;
220 if (msg->intParameter1 == MessageThreadFuncCall::uniqueID)
222 // Handle callback message
223 MessageThreadFuncCall* const call = (MessageThreadFuncCall*) msg->pointerParameter;
225 call->result = (*(call->func)) (call->parameter);
226 call->event.signal();
228 else
230 // Handle "normal" messages
231 MessageManager::getInstance()->deliverMessage (msg);
234 return true;
238 juce_ImplementSingleton_SingleThreaded (InternalMessageQueue);
241 //==============================================================================
242 namespace LinuxErrorHandling
244 //==============================================================================
245 static bool errorOccurred = false;
246 static bool keyboardBreakOccurred = false;
247 static XErrorHandler oldErrorHandler = (XErrorHandler) 0;
248 static XIOErrorHandler oldIOErrorHandler = (XIOErrorHandler) 0;
250 //==============================================================================
251 // Usually happens when client-server connection is broken
252 static int ioErrorHandler (Display* display)
254 DBG ("ERROR: connection to X server broken.. terminating.");
256 if (JUCEApplication::isStandaloneApp())
257 MessageManager::getInstance()->stopDispatchLoop();
259 errorOccurred = true;
260 return 0;
263 // A protocol error has occurred
264 static int juce_XErrorHandler (Display* display, XErrorEvent* event)
266 #if JUCE_DEBUG_XERRORS
267 char errorStr[64] = { 0 };
268 char requestStr[64] = { 0 };
270 XGetErrorText (display, event->error_code, errorStr, 64);
271 XGetErrorDatabaseText (display, "XRequest", String (event->request_code).toUTF8(), "Unknown", requestStr, 64);
272 DBG ("ERROR: X returned " + String (errorStr) + " for operation " + String (requestStr));
273 #endif
275 return 0;
278 static void installXErrorHandlers()
280 oldIOErrorHandler = XSetIOErrorHandler (ioErrorHandler);
281 oldErrorHandler = XSetErrorHandler (juce_XErrorHandler);
284 static void removeXErrorHandlers()
286 if (JUCEApplication::isStandaloneApp())
288 XSetIOErrorHandler (oldIOErrorHandler);
289 oldIOErrorHandler = 0;
291 XSetErrorHandler (oldErrorHandler);
292 oldErrorHandler = 0;
296 //==============================================================================
297 static void keyboardBreakSignalHandler (int sig)
299 if (sig == SIGINT)
300 keyboardBreakOccurred = true;
303 static void installKeyboardBreakHandler()
305 struct sigaction saction;
306 sigset_t maskSet;
307 sigemptyset (&maskSet);
308 saction.sa_handler = keyboardBreakSignalHandler;
309 saction.sa_mask = maskSet;
310 saction.sa_flags = 0;
311 sigaction (SIGINT, &saction, 0);
315 //==============================================================================
316 void MessageManager::doPlatformSpecificInitialisation()
318 if (JUCEApplication::isStandaloneApp())
320 // Initialise xlib for multiple thread support
321 static bool initThreadCalled = false;
323 if (! initThreadCalled)
325 if (! XInitThreads())
327 // This is fatal! Print error and closedown
328 Logger::outputDebugString ("Failed to initialise xlib thread support.");
329 Process::terminate();
330 return;
333 initThreadCalled = true;
336 LinuxErrorHandling::installXErrorHandlers();
337 LinuxErrorHandling::installKeyboardBreakHandler();
340 // Create the internal message queue
341 InternalMessageQueue::getInstance();
343 // Try to connect to a display
344 String displayName (getenv ("DISPLAY"));
345 if (displayName.isEmpty())
346 displayName = ":0.0";
348 display = XOpenDisplay (displayName.toUTF8());
350 if (display != 0) // This is not fatal! we can run headless.
352 // Create a context to store user data associated with Windows we create in WindowDriver
353 windowHandleXContext = XUniqueContext();
355 // We're only interested in client messages for this window, which are always sent
356 XSetWindowAttributes swa;
357 swa.event_mask = NoEventMask;
359 // Create our message window (this will never be mapped)
360 const int screen = DefaultScreen (display);
361 juce_messageWindowHandle = XCreateWindow (display, RootWindow (display, screen),
362 0, 0, 1, 1, 0, 0, InputOnly,
363 DefaultVisual (display, screen),
364 CWEventMask, &swa);
368 void MessageManager::doPlatformSpecificShutdown()
370 InternalMessageQueue::deleteInstance();
372 if (display != 0 && ! LinuxErrorHandling::errorOccurred)
374 XDestroyWindow (display, juce_messageWindowHandle);
375 XCloseDisplay (display);
377 juce_messageWindowHandle = 0;
378 display = nullptr;
380 LinuxErrorHandling::removeXErrorHandlers();
384 bool MessageManager::postMessageToSystemQueue (Message* message)
386 if (LinuxErrorHandling::errorOccurred)
387 return false;
389 InternalMessageQueue::getInstanceWithoutCreating()->postMessage (message);
390 return true;
393 void MessageManager::broadcastMessage (const String& value)
395 /* TODO */
399 //==============================================================================
400 class AsyncFunctionCaller : public AsyncUpdater
402 public:
403 static void* call (MessageCallbackFunction* func_, void* parameter_)
405 if (MessageManager::getInstance()->isThisTheMessageThread())
406 return func_ (parameter_);
408 AsyncFunctionCaller caller (func_, parameter_);
409 caller.triggerAsyncUpdate();
410 caller.finished.wait();
411 return caller.result;
414 void handleAsyncUpdate()
416 result = (*func) (parameter);
417 finished.signal();
420 private:
421 WaitableEvent finished;
422 MessageCallbackFunction* func;
423 void* parameter;
424 void* volatile result;
426 AsyncFunctionCaller (MessageCallbackFunction* func_, void* parameter_)
427 : result (0), func (func_), parameter (parameter_)
430 JUCE_DECLARE_NON_COPYABLE (AsyncFunctionCaller);
433 void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func, void* parameter)
435 if (LinuxErrorHandling::errorOccurred)
436 return nullptr;
438 return AsyncFunctionCaller::call (func, parameter);
441 // this function expects that it will NEVER be called simultaneously for two concurrent threads
442 bool MessageManager::dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
444 while (! LinuxErrorHandling::errorOccurred)
446 if (LinuxErrorHandling::keyboardBreakOccurred)
448 LinuxErrorHandling::errorOccurred = true;
450 if (JUCEApplication::isStandaloneApp())
451 Process::terminate();
453 break;
456 if (InternalMessageQueue::getInstanceWithoutCreating()->dispatchNextEvent())
457 return true;
459 if (returnIfNoPendingMessages)
460 break;
462 InternalMessageQueue::getInstanceWithoutCreating()->sleepUntilEvent (2000);
465 return false;
468 #endif