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
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
50 InternalMessageQueue()
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()
66 clearSingletonInstance();
69 //==============================================================================
70 void postMessage (Message
* msg
)
72 const int maxBytesInSocketQueue
= 128;
77 if (bytesInSocket
< maxBytesInSocketQueue
)
81 ScopedUnlock
ul (lock
);
82 const unsigned char x
= 0xff;
83 size_t bytesWritten
= write (fd
[0], &x
, 1);
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();
101 return dispatchNextInternalMessage() || dispatchNextXEvent();
104 // Wait for an event (either XEvent, or an internal Message)
105 bool sleepUntilEvent (const int timeoutMs
)
113 if (XPending (display
))
119 tv
.tv_usec
= timeoutMs
* 1000;
120 int fd0
= getWaitHandle();
125 FD_SET (fd0
, &readset
);
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
;
147 CriticalSection lock
;
151 //==============================================================================
152 juce_DeclareSingleton_SingleThreaded_Minimal (InternalMessageQueue
);
155 CriticalSection lock
;
156 ReferenceCountedArray
<Message
> queue
;
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)
169 socketFlags
|= O_NONBLOCK
;
170 return fcntl (handle
, F_SETFL
, socketFlags
) == 0;
173 static bool dispatchNextXEvent()
182 if (! XPending (display
))
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
);
196 Message::Ptr
popNextMessage()
198 const ScopedLock
sl (lock
);
200 if (bytesInSocket
> 0)
204 const ScopedUnlock
ul (lock
);
206 size_t numBytes
= read (fd
[1], &x
, 1);
210 return queue
.removeAndReturn (0);
213 bool dispatchNextInternalMessage()
215 const Message::Ptr
msg (popNextMessage());
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();
230 // Handle "normal" messages
231 MessageManager::getInstance()->deliverMessage (msg
);
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;
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
));
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
);
296 //==============================================================================
297 static void keyboardBreakSignalHandler (int sig
)
300 keyboardBreakOccurred
= true;
303 static void installKeyboardBreakHandler()
305 struct sigaction saction
;
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();
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
),
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;
380 LinuxErrorHandling::removeXErrorHandlers();
384 bool MessageManager::postMessageToSystemQueue (Message
* message
)
386 if (LinuxErrorHandling::errorOccurred
)
389 InternalMessageQueue::getInstanceWithoutCreating()->postMessage (message
);
393 void MessageManager::broadcastMessage (const String
& value
)
399 //==============================================================================
400 class AsyncFunctionCaller
: public AsyncUpdater
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
);
421 WaitableEvent finished
;
422 MessageCallbackFunction
* func
;
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
)
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();
456 if (InternalMessageQueue::getInstanceWithoutCreating()->dispatchNextEvent())
459 if (returnIfNoPendingMessages
)
462 InternalMessageQueue::getInstanceWithoutCreating()->sleepUntilEvent (2000);