1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-18 00:54:19 +00:00

Added Linux contributions for headless messaging, clipboard and better shm support.

This commit is contained in:
Julian Storer 2010-01-11 22:25:43 +00:00
parent d7cbfe93c5
commit 2343dcdcee
8 changed files with 1344 additions and 670 deletions

File diff suppressed because it is too large Load diff

View file

@ -252666,7 +252666,7 @@ void* PlatformUtilities::getProcedureEntryPoint (void* libraryHandle, const Stri
#if ! JUCE_ONLY_BUILD_CORE_LIBRARY
/********* Start of inlined file: juce_linux_Messaging.cpp *********/
/********* Start of inlined file: juce_linux_Clipboard.cpp *********/
// (This file gets included by juce_linux_NativeCode.cpp, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE
@ -252675,8 +252675,246 @@ void* PlatformUtilities::getProcedureEntryPoint (void* libraryHandle, const Stri
#define JUCE_DEBUG_XERRORS 1
#endif
extern Display* display;
extern Window juce_messageWindowHandle;
static String localClipboardContent;
static Atom atom_UTF8_STRING;
static Atom atom_CLIPBOARD;
static Atom atom_TARGETS;
static void initSelectionAtoms()
{
static bool isInitialised = false;
if (! isInitialised)
{
atom_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
atom_CLIPBOARD = XInternAtom (display, "CLIPBOARD", False);
atom_TARGETS = XInternAtom (display, "TARGETS", False);
}
}
// Read the content of a window property as either a locale-dependent string or an utf8 string
// works only for strings shorter than 1000000 bytes
static String juce_readWindowProperty (Window window, Atom prop,
Atom fmt, // XA_STRING or UTF8_STRING
bool deleteAfterReading)
{
String returnData;
uint8 *clipData;
Atom actualType;
int actualFormat;
unsigned long numItems, bytesLeft;
if (XGetWindowProperty (display, window, prop,
0L /* offset */, 1000000 /* length (max) */, False,
AnyPropertyType /* format */,
&actualType, &actualFormat, &numItems, &bytesLeft,
&clipData) == Success)
{
if (actualType == atom_UTF8_STRING && actualFormat == 8)
{
returnData = String::fromUTF8 (clipData, numItems);
}
else if (actualType == XA_STRING && actualFormat == 8)
{
returnData = String ((const char*) clipData, numItems);
}
if (clipData != 0)
XFree (clipData);
jassert (bytesLeft == 0 || numItems == 1000000);
}
if (deleteAfterReading)
XDeleteProperty (display, window, prop);
return returnData;
}
// Send a SelectionRequest to the window owning the selection and waits for its answer (with a timeout) */
static bool juce_requestSelectionContent (String &selection_content, Atom selection, Atom requested_format)
{
Atom property_name = XInternAtom (display, "JUCE_SEL", false);
// The selection owner will be asked to set the JUCE_SEL property on the
// juce_messageWindowHandle with the selection content
XConvertSelection (display, selection, requested_format, property_name,
juce_messageWindowHandle, CurrentTime);
int timeoutMs = 200; // will wait at most for 200 ms
do
{
XEvent event;
if (XCheckTypedWindowEvent (display, juce_messageWindowHandle, SelectionNotify, &event))
{
if (event.xselection.property == property_name)
{
jassert (event.xselection.requestor == juce_messageWindowHandle);
selection_content = juce_readWindowProperty (event.xselection.requestor,
event.xselection.property,
requested_format, true);
return true;
}
else
{
return false; // the format we asked for was denied.. (event.xselection.property == None)
}
}
// not very elegant.. we could do a select() or something like that...
// however clipboard content requesting is inherently slow on x11, it
// often takes 50ms or more so...
Thread::sleep (4);
timeoutMs -= 4;
}
while (timeoutMs > 0);
DBG("timeout for juce_requestSelectionContent");
return false;
}
// Called from the event loop in juce_linux_Messaging in response to SelectionRequest events
void juce_handleSelectionRequest (XSelectionRequestEvent &evt)
{
initSelectionAtoms();
// the selection content is sent to the target window as a window property
XSelectionEvent reply;
reply.type = SelectionNotify;
reply.display = evt.display;
reply.requestor = evt.requestor;
reply.selection = evt.selection;
reply.target = evt.target;
reply.property = None; // == "fail"
reply.time = evt.time;
HeapBlock <char> data;
int propertyFormat = 0, numDataItems = 0;
if (evt.selection == XA_PRIMARY || evt.selection == atom_CLIPBOARD)
{
if (evt.target == XA_STRING)
{
// format data according to system locale
numDataItems = localClipboardContent.length();
data.calloc (numDataItems + 2);
localClipboardContent.copyToBuffer ((char*) data, numDataItems + 1);
propertyFormat = 8; // bits/item
}
else if (evt.target == atom_UTF8_STRING)
{
// translate to utf8
numDataItems = localClipboardContent.copyToUTF8 (0);
data.calloc (numDataItems + 2);
localClipboardContent.copyToUTF8 (data, numDataItems + 1);
propertyFormat = 8; // bits/item
}
else if (evt.target == atom_TARGETS)
{
// another application wants to know what we are able to send
numDataItems = 2;
propertyFormat = 32; // atoms are 32-bit
data.calloc (numDataItems * 4);
((Atom*) data)[0] = atom_UTF8_STRING;
((Atom*) data)[1] = XA_STRING;
}
}
else
{
DBG ("requested unsupported clipboard");
}
if (data != 0)
{
const int maxReasonableSelectionSize = 1000000;
// for very big chunks of data, we should use the "INCR" protocol , which is a pain in the *ss
if (evt.property != None && numDataItems < maxReasonableSelectionSize)
{
XChangeProperty (evt.display, evt.requestor,
evt.property, evt.target,
propertyFormat /* 8 or 32 */, PropModeReplace,
(const unsigned char*) data, numDataItems);
reply.property = evt.property; // " == success"
}
}
XSendEvent (evt.display, evt.requestor, 0, NoEventMask, (XEvent*) &reply);
}
void SystemClipboard::copyTextToClipboard (const String& clipText) throw()
{
initSelectionAtoms();
localClipboardContent = clipText;
XSetSelectionOwner (display, XA_PRIMARY, juce_messageWindowHandle, CurrentTime);
XSetSelectionOwner (display, atom_CLIPBOARD, juce_messageWindowHandle, CurrentTime);
}
const String SystemClipboard::getTextFromClipboard() throw()
{
initSelectionAtoms();
/* 1) try to read from the "CLIPBOARD" selection first (the "high
level" clipboard that is supposed to be filled by ctrl-C
etc). When a clipboard manager is running, the content of this
selection is preserved even when the original selection owner
exits.
2) and then try to read from "PRIMARY" selection (the "legacy" selection
filled by good old x11 apps such as xterm)
*/
String content;
Atom selection = XA_PRIMARY;
Window selectionOwner = None;
if ((selectionOwner = XGetSelectionOwner (display, selection)) == None)
{
selection = atom_CLIPBOARD;
selectionOwner = XGetSelectionOwner (display, selection);
}
if (selectionOwner != None)
{
if (selectionOwner == juce_messageWindowHandle)
{
content = localClipboardContent;
}
else
{
// first try: we want an utf8 string
bool ok = juce_requestSelectionContent (content, selection, atom_UTF8_STRING);
if (! ok)
{
// second chance, ask for a good old locale-dependent string ..
ok = juce_requestSelectionContent (content, selection, XA_STRING);
}
}
}
return content;
}
#endif
/********* End of inlined file: juce_linux_Clipboard.cpp *********/
/********* Start of inlined file: juce_linux_Messaging.cpp *********/
// (This file gets included by juce_linux_NativeCode.cpp, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE
#ifdef JUCE_DEBUG
#define JUCE_DEBUG_XERRORS 1
#endif
Display* display = 0; // This is also referenced from WindowDriver.cpp
static Window juce_messageWindowHandle = None;
Window juce_messageWindowHandle = None;
#define SpecialAtom "JUCESpecialAtom"
#define BroadcastAtom "JUCEBroadcastAtom"
@ -252692,8 +252930,68 @@ XContext improbableNumber;
// Defined in WindowDriver.cpp
extern void juce_windowMessageReceive (XEvent* event);
// Defined in ClipboardDriver.cpp
extern void juce_handleSelectionRequest (XSelectionRequestEvent &evt);
class InternalMessageQueue
{
public:
InternalMessageQueue()
{
int ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd);
(void) ret; jassert (ret == 0);
}
~InternalMessageQueue()
{
close (fd[0]);
close (fd[1]);
}
void postMessage (Message* msg)
{
ScopedLock sl (lock);
queue.add (msg);
const unsigned char x = 0xff;
write (fd[0], &x, 1);
}
bool isEmpty() const
{
ScopedLock sl (lock);
return queue.size() == 0;
}
Message* popMessage()
{
Message* m = 0;
ScopedLock sl (lock);
if (queue.size() != 0)
{
unsigned char x;
read (fd[1], &x, 1);
m = queue.getUnchecked(0);
queue.remove (0, false /* deleteObject */);
}
return m;
}
int getWaitHandle() const { return fd[1]; }
private:
CriticalSection lock;
OwnedArray <Message> queue;
int fd[2];
};
struct MessageThreadFuncCall
{
enum { uniqueID = 0x73774623 };
MessageCallbackFunction* func;
void* parameter;
void* result;
@ -252701,21 +252999,22 @@ struct MessageThreadFuncCall
WaitableEvent event;
};
static bool errorCondition = false;
static InternalMessageQueue* juce_internalMessageQueue = 0;
// error handling in X11
static bool errorOccurred = false;
static bool keyboardBreakOccurred = false;
static XErrorHandler oldErrorHandler = (XErrorHandler) 0;
static XIOErrorHandler oldIOErrorHandler = (XIOErrorHandler) 0;
// (defined in another file to avoid problems including certain headers in this one)
extern bool juce_isRunningAsApplication();
// Usually happens when client-server connection is broken
static int ioErrorHandler (Display* display)
{
DBG (T("ERROR: connection to X server broken.. terminating."));
errorCondition = true;
errorOccurred = true;
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
Process::terminate();
return 0;
@ -252743,20 +253042,18 @@ static int errorHandler (Display* display, XErrorEvent* event)
return 0;
}
static bool breakIn = false;
// Breakin from keyboard
static void sig_handler (int sig)
static void signalHandler (int sig)
{
if (sig == SIGINT)
{
breakIn = true;
keyboardBreakOccurred = true;
return;
}
static bool reentrant = false;
if (reentrant == false)
if (! reentrant)
{
reentrant = true;
@ -252764,14 +253061,14 @@ static void sig_handler (int sig)
fflush (stdout);
Logger::outputDebugString ("ERROR: Program executed illegal instruction.. terminating");
errorCondition = true;
errorOccurred = true;
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
Process::terminate();
}
else
{
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
exit(0);
}
}
@ -252788,7 +253085,7 @@ void MessageManager::doPlatformSpecificInitialisation()
// This is fatal! Print error and closedown
Logger::outputDebugString ("Failed to initialise xlib thread support.");
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
Process::terminate();
return;
@ -252807,7 +253104,7 @@ void MessageManager::doPlatformSpecificInitialisation()
struct sigaction saction;
sigset_t maskSet;
sigemptyset (&maskSet);
saction.sa_handler = sig_handler;
saction.sa_handler = signalHandler;
saction.sa_mask = maskSet;
saction.sa_flags = 0;
sigaction (SIGINT, &saction, NULL);
@ -252821,6 +253118,10 @@ void MessageManager::doPlatformSpecificInitialisation()
sigaction (SIGSYS, &saction, NULL);
#endif
// Create the internal message queue
juce_internalMessageQueue = new InternalMessageQueue();
// Try to connect to a display
String displayName (getenv ("DISPLAY"));
if (displayName.isEmpty())
displayName = T(":0.0");
@ -252829,12 +253130,7 @@ void MessageManager::doPlatformSpecificInitialisation()
if (display == 0)
{
// This is fatal! Print error and closedown
Logger::outputDebugString ("Failed to open the X display.");
if (juce_isRunningAsApplication())
Process::terminate();
// This is not fatal! we can run headless.
return;
}
@ -252865,7 +253161,9 @@ void MessageManager::doPlatformSpecificInitialisation()
void MessageManager::doPlatformSpecificShutdown()
{
if (errorCondition == false)
deleteAndZero (juce_internalMessageQueue);
if (display != 0 && ! errorOccurred)
{
XDestroyWindow (display, juce_messageWindowHandle);
XCloseDisplay (display);
@ -252884,9 +253182,15 @@ void MessageManager::doPlatformSpecificShutdown()
bool juce_postMessageToSystemQueue (void* message)
{
if (errorCondition)
if (errorOccurred)
return false;
juce_internalMessageQueue->postMessage ((Message*) message);
return true;
}
/*bool juce_postMessageToX11Queue (void *message)
{
XClientMessageEvent clientMsg;
clientMsg.display = display;
clientMsg.window = juce_messageWindowHandle;
@ -252906,131 +253210,79 @@ bool juce_postMessageToSystemQueue (void* message)
XFlush (display); // This is necessary to ensure the event is delivered
return true;
}
}*/
void MessageManager::broadcastMessage (const String& value) throw()
{
/* TODO */
}
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func,
void* parameter)
{
void* retVal = 0;
if (errorOccurred)
return 0;
if (! errorCondition)
if (! isThisTheMessageThread())
{
if (! isThisTheMessageThread())
{
static MessageThreadFuncCall messageFuncCallContext;
MessageThreadFuncCall messageCallContext;
messageCallContext.func = func;
messageCallContext.parameter = parameter;
const ScopedLock sl (messageFuncCallContext.lock);
juce_internalMessageQueue->postMessage (new Message (MessageThreadFuncCall::uniqueID,
0, 0, &messageCallContext));
XClientMessageEvent clientMsg;
clientMsg.display = display;
clientMsg.window = juce_messageWindowHandle;
clientMsg.type = ClientMessage;
clientMsg.format = 32;
clientMsg.message_type = specialCallbackId;
#if JUCE_64BIT
clientMsg.data.l[0] = (long) (0x00000000ffffffff & (((uint64) &messageFuncCallContext) >> 32));
clientMsg.data.l[1] = (long) (0x00000000ffffffff & (uint64) &messageFuncCallContext);
#else
clientMsg.data.l[0] = (long) &messageFuncCallContext;
#endif
// Wait for it to complete before continuing
messageCallContext.event.wait();
messageFuncCallContext.func = func;
messageFuncCallContext.parameter = parameter;
if (XSendEvent (display, juce_messageWindowHandle, false, NoEventMask, (XEvent*) &clientMsg) == 0)
return 0;
XFlush (display); // This is necessary to ensure the event is delivered
// Wait for it to complete before continuing
messageFuncCallContext.event.wait();
retVal = messageFuncCallContext.result;
}
else
{
// Just call the function directly
retVal = func (parameter);
}
return messageCallContext.result;
}
else
{
// Just call the function directly
return func (parameter);
}
return retVal;
}
bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
// Wait for an event (either XEvent, or an internal Message)
static bool juce_sleepUntilEvent (const int timeoutMs)
{
if (errorCondition)
return false;
if ((display != 0 && XPending (display)) || ! juce_internalMessageQueue->isEmpty())
return true;
if (breakIn)
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = timeoutMs * 1000;
int fd0 = juce_internalMessageQueue->getWaitHandle();
int fdmax = fd0;
fd_set readset;
FD_ZERO (&readset);
FD_SET (fd0, &readset);
if (display != 0)
{
errorCondition = true;
if (juce_isRunningAsApplication())
Process::terminate();
return false;
int fd1 = XConnectionNumber (display);
FD_SET (fd1, &readset);
fdmax = jmax (fd0, fd1);
}
if (returnIfNoPendingMessages && ! XPending (display))
int ret = select (fdmax + 1, &readset, 0, 0, &tv);
return (ret > 0); // ret <= 0 if error or timeout
}
// Handle next XEvent (if any)
static bool juce_dispatchNextXEvent()
{
if (display == 0 || ! XPending (display))
return false;
XEvent evt;
XNextEvent (display, &evt);
if (evt.type == ClientMessage && evt.xany.window == juce_messageWindowHandle)
if (evt.type == SelectionRequest && evt.xany.window == juce_messageWindowHandle)
{
XClientMessageEvent* const clientMsg = (XClientMessageEvent*) &evt;
if (clientMsg->format != 32)
{
jassertfalse
DBG ("Error: juce_dispatchNextMessageOnSystemQueue received malformed client message.");
}
else
{
JUCE_TRY
{
#if JUCE_64BIT
void* const messagePtr
= (void*) ((0xffffffff00000000 & (((uint64) clientMsg->data.l[0]) << 32))
| (clientMsg->data.l[1] & 0x00000000ffffffff));
#else
void* const messagePtr = (void*) (clientMsg->data.l[0]);
#endif
if (clientMsg->message_type == specialId)
{
MessageManager::getInstance()->deliverMessage (messagePtr);
}
else if (clientMsg->message_type == specialCallbackId)
{
MessageThreadFuncCall* const call = (MessageThreadFuncCall*) messagePtr;
MessageCallbackFunction* func = call->func;
call->result = (*func) (call->parameter);
call->event.signal();
}
else if (clientMsg->message_type == broadcastId)
{
#if 0
TCHAR buffer[8192];
zeromem (buffer, sizeof (buffer));
if (GlobalGetAtomName ((ATOM) lParam, buffer, 8192) != 0)
mq->deliverBroadcastMessage (String (buffer));
#endif
}
else
{
DBG ("Error: juce_dispatchNextMessageOnSystemQueue received unknown client message.");
}
}
JUCE_CATCH_ALL
}
juce_handleSelectionRequest (evt.xselectionrequest);
}
else if (evt.xany.window != juce_messageWindowHandle)
{
@ -253040,6 +253292,76 @@ bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
return true;
}
// Handle next internal Message (if any)
static bool juce_dispatchNextInternalMessage()
{
if (juce_internalMessageQueue->isEmpty())
return false;
ScopedPointer <Message> msg (juce_internalMessageQueue->popMessage());
if (msg->intParameter1 == MessageThreadFuncCall::uniqueID)
{
// Handle callback message
MessageThreadFuncCall* const call = (MessageThreadFuncCall*) msg->pointerParameter;
call->result = (*(call->func)) (call->parameter);
call->event.signal();
}
else
{
// Handle "normal" messages
MessageManager::getInstance()->deliverMessage (msg.release());
}
return true;
}
// this function expects that it will NEVER be called simultaneously for two concurrent threads
bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
{
for (;;)
{
if (errorOccurred)
break;
if (keyboardBreakOccurred)
{
errorOccurred = true;
if (JUCEApplication::getInstance() != 0)
Process::terminate();
break;
}
static int totalEventCount = 0;
++totalEventCount;
// The purpose here is to give either priority to XEvents or
// to internal messages This is necessary to keep a "good"
// behaviour when the cpu is overloaded
if (totalEventCount & 1)
{
if (juce_dispatchNextXEvent() || juce_dispatchNextInternalMessage())
return true;
}
else
{
if (juce_dispatchNextInternalMessage() || juce_dispatchNextXEvent())
return true;
}
if (returnIfNoPendingMessages) // early exit
break;
// the timeout is to be on the safe side, but it does not seem to be useful
juce_sleepUntilEvent (2000);
}
return false;
}
#endif
/********* End of inlined file: juce_linux_Messaging.cpp *********/
@ -253667,12 +253989,6 @@ bool Process::isForegroundProcess()
return isActiveApplication;
}
// (used in the messaging code, declared here for build reasons)
bool juce_isRunningAsApplication()
{
return JUCEApplication::getInstance() != 0;
}
// These are defined in juce_linux_Messaging.cpp
extern Display* display;
extern XContext improbableNumber;
@ -254170,7 +254486,7 @@ public:
// blit results to screen.
#if JUCE_USE_XSHM
if (usingXShm)
XShmPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh, False);
XShmPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh, True);
else
#endif
XPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh);
@ -255182,6 +255498,10 @@ public:
break;
default:
#if JUCE_USE_XSHM
if (event->xany.type == XShmGetEventBase (display))
repainter->notifyPaintCompleted();
#endif
break;
}
}
@ -255269,6 +255589,8 @@ private:
lastTimeImageUsed (0)
{
#if JUCE_USE_XSHM
shmCompletedDrawing = true;
useARGBImagesForRendering = isShmAvailable();
if (useARGBImagesForRendering)
@ -255291,7 +255613,7 @@ private:
void timerCallback()
{
if (! regionsNeedingRepaint.isEmpty())
if (! regionsNeedingRepaint.isEmpty() && shmCompletedDrawing)
{
stopTimer();
performAnyPendingRepaintsNow();
@ -255319,6 +255641,8 @@ private:
if (! totalArea.isEmpty())
{
shmCompletedDrawing = false;
if (image == 0 || image->getWidth() < totalArea.getWidth()
|| image->getHeight() < totalArea.getHeight())
{
@ -255362,6 +255686,13 @@ private:
startTimer (repaintTimerPeriod);
}
#if JUCE_USE_XSHM
void notifyPaintCompleted()
{
shmCompletedDrawing = true;
}
#endif
private:
LinuxComponentPeer* const peer;
ScopedPointer <XBitmapImage> image;
@ -255370,6 +255701,7 @@ private:
#if JUCE_USE_XSHM
bool useARGBImagesForRendering;
bool shmCompletedDrawing;
#endif
LinuxRepaintManager (const LinuxRepaintManager&);
const LinuxRepaintManager& operator= (const LinuxRepaintManager&);
@ -256101,6 +256433,9 @@ void juce_windowMessageReceive (XEvent* event)
void juce_updateMultiMonitorInfo (Array <Rectangle>& monitorCoords, const bool /*clipToWorkArea*/) throw()
{
if (display == 0)
return;
#if JUCE_USE_XINERAMA
int major_opcode, first_event, first_error;
@ -256629,84 +256964,6 @@ void OpenGLPixelFormat::getAvailablePixelFormats (Component* component,
#endif
static void initClipboard (Window root, Atom* cutBuffers) throw()
{
static bool init = false;
if (! init)
{
init = true;
// Make sure all cut buffers exist before use
for (int i = 0; i < 8; i++)
{
XChangeProperty (display, root, cutBuffers[i],
XA_STRING, 8, PropModeAppend, NULL, 0);
}
}
}
// Clipboard implemented currently using cut buffers
// rather than the more powerful selection method
void SystemClipboard::copyTextToClipboard (const String& clipText) throw()
{
Window root = RootWindow (display, DefaultScreen (display));
Atom cutBuffers[8] = { XA_CUT_BUFFER0, XA_CUT_BUFFER1, XA_CUT_BUFFER2, XA_CUT_BUFFER3,
XA_CUT_BUFFER4, XA_CUT_BUFFER5, XA_CUT_BUFFER6, XA_CUT_BUFFER7 };
initClipboard (root, cutBuffers);
XRotateWindowProperties (display, root, cutBuffers, 8, 1);
XChangeProperty (display, root, cutBuffers[0],
XA_STRING, 8, PropModeReplace, (const unsigned char*) (const char*) clipText,
clipText.length());
}
const String SystemClipboard::getTextFromClipboard() throw()
{
const int bufSize = 64; // in words
String returnData;
int byteOffset = 0;
Window root = RootWindow (display, DefaultScreen (display));
Atom cutBuffers[8] = { XA_CUT_BUFFER0, XA_CUT_BUFFER1, XA_CUT_BUFFER2, XA_CUT_BUFFER3,
XA_CUT_BUFFER4, XA_CUT_BUFFER5, XA_CUT_BUFFER6, XA_CUT_BUFFER7 };
initClipboard (root, cutBuffers);
for (;;)
{
unsigned long bytesLeft = 0, nitems = 0;
unsigned char* clipData = 0;
int actualFormat = 0;
Atom actualType;
if (XGetWindowProperty (display, root, cutBuffers[0], byteOffset >> 2, bufSize,
False, XA_STRING, &actualType, &actualFormat, &nitems, &bytesLeft,
&clipData) == Success)
{
if (actualType == XA_STRING && actualFormat == 8)
{
byteOffset += nitems;
returnData += String ((const char*) clipData, nitems);
}
else
{
bytesLeft = 0;
}
if (clipData != 0)
XFree (clipData);
}
if (bytesLeft == 0)
break;
}
return returnData;
}
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMoveFiles)
{
jassertfalse // not implemented!
@ -258888,6 +259145,62 @@ void FileChooser::showPlatformDialog (OwnedArray<File>& results,
bool selectMultipleFiles,
FilePreviewComponent* previewComponent)
{
const tchar* const separator = T(":");
String command ("zenity --file-selection");
if (title.isNotEmpty())
command << " --title=\"" << title << "\"";
if (file != File::nonexistent)
command << " --filename=\"" << file.getFullPathName () << "\"";
if (isDirectory)
command << " --directory";
if (isSave)
command << " --save";
if (selectMultipleFiles)
command << " --multiple --separator=\"" << separator << "\"";
command << " 2>&1";
MemoryOutputStream result;
int status = -1;
FILE* stream = popen ((const char*) command.toUTF8(), "r");
if (stream != 0)
{
for (;;)
{
char buffer [1024];
const int bytesRead = fread (buffer, 1, sizeof (buffer), stream);
if (bytesRead <= 0)
break;
result.write (buffer, bytesRead);
}
status = pclose (stream);
}
if (status == 0)
{
String resultString (String::fromUTF8 ((const uint8*) result.getData(), result.getDataSize()));
StringArray tokens;
if (selectMultipleFiles)
tokens.addTokens (resultString, separator, 0);
else
tokens.add (resultString);
for (int i = 0; i < tokens.size(); i++)
results.add (new File (tokens[i]));
return;
}
//xxx ain't got one!
jassertfalse
}
@ -273681,7 +273994,6 @@ END_JUCE_NAMESPACE
- (void) captureOutput: (QTCaptureFileOutput*) captureOutput
didOutputSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection;
@end
BEGIN_JUCE_NAMESPACE
@ -273747,6 +274059,7 @@ public:
void resetFile()
{
[fileOutput recordToOutputFileURL: nil];
[session removeOutput: fileOutput];
[fileOutput release];
fileOutput = [[QTCaptureMovieFileOutput alloc] init];
@ -273826,11 +274139,14 @@ END_JUCE_NAMESPACE
withSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection
{
const ScopedAutoReleasePool pool;
if (internal->listeners.size() > 0)
{
const ScopedAutoReleasePool pool;
internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame],
CVPixelBufferGetWidth (videoFrame),
CVPixelBufferGetHeight (videoFrame));
internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame],
CVPixelBufferGetWidth (videoFrame),
CVPixelBufferGetHeight (videoFrame));
}
}
- (void) captureOutput: (QTCaptureFileOutput*) captureOutput
@ -273962,12 +274278,11 @@ CameraDevice* CameraDevice::openDevice (int index,
int minWidth, int minHeight,
int maxWidth, int maxHeight)
{
CameraDevice* d = new CameraDevice (getAvailableDevices() [index], index);
ScopedPointer <CameraDevice> d (new CameraDevice (getAvailableDevices() [index], index));
if (((QTCameraDeviceInteral*) (d->internal))->openingError.isEmpty())
return d;
return d.release();
delete d;
return 0;
}

View file

@ -41,6 +41,7 @@ BEGIN_JUCE_NAMESPACE
#include "../core/juce_Random.h"
#include "../io/network/juce_URL.h"
#include "../io/files/juce_NamedPipe.h"
#include "../io/streams/juce_MemoryOutputStream.h"
#include "../threads/juce_InterProcessLock.h"
#include "../audio/devices/juce_AudioIODeviceType.h"
#include "../threads/juce_Thread.h"
@ -100,6 +101,7 @@ BEGIN_JUCE_NAMESPACE
#include "linux/juce_linux_Threads.cpp"
#if ! JUCE_ONLY_BUILD_CORE_LIBRARY
#include "linux/juce_linux_Clipboard.cpp"
#include "linux/juce_linux_Messaging.cpp"
#include "linux/juce_linux_Fonts.cpp"
#include "linux/juce_linux_Windowing.cpp"

View file

@ -0,0 +1,266 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-9 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
// (This file gets included by juce_linux_NativeCode.cpp, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE
//==============================================================================
#ifdef JUCE_DEBUG
#define JUCE_DEBUG_XERRORS 1
#endif
extern Display* display;
extern Window juce_messageWindowHandle;
static String localClipboardContent;
static Atom atom_UTF8_STRING;
static Atom atom_CLIPBOARD;
static Atom atom_TARGETS;
//==============================================================================
static void initSelectionAtoms()
{
static bool isInitialised = false;
if (! isInitialised)
{
atom_UTF8_STRING = XInternAtom (display, "UTF8_STRING", False);
atom_CLIPBOARD = XInternAtom (display, "CLIPBOARD", False);
atom_TARGETS = XInternAtom (display, "TARGETS", False);
}
}
//==============================================================================
// Read the content of a window property as either a locale-dependent string or an utf8 string
// works only for strings shorter than 1000000 bytes
static String juce_readWindowProperty (Window window, Atom prop,
Atom fmt, // XA_STRING or UTF8_STRING
bool deleteAfterReading)
{
String returnData;
uint8 *clipData;
Atom actualType;
int actualFormat;
unsigned long numItems, bytesLeft;
if (XGetWindowProperty (display, window, prop,
0L /* offset */, 1000000 /* length (max) */, False,
AnyPropertyType /* format */,
&actualType, &actualFormat, &numItems, &bytesLeft,
&clipData) == Success)
{
if (actualType == atom_UTF8_STRING && actualFormat == 8)
{
returnData = String::fromUTF8 (clipData, numItems);
}
else if (actualType == XA_STRING && actualFormat == 8)
{
returnData = String ((const char*) clipData, numItems);
}
if (clipData != 0)
XFree (clipData);
jassert (bytesLeft == 0 || numItems == 1000000);
}
if (deleteAfterReading)
XDeleteProperty (display, window, prop);
return returnData;
}
//==============================================================================
// Send a SelectionRequest to the window owning the selection and waits for its answer (with a timeout) */
static bool juce_requestSelectionContent (String &selection_content, Atom selection, Atom requested_format)
{
Atom property_name = XInternAtom (display, "JUCE_SEL", false);
// The selection owner will be asked to set the JUCE_SEL property on the
// juce_messageWindowHandle with the selection content
XConvertSelection (display, selection, requested_format, property_name,
juce_messageWindowHandle, CurrentTime);
int timeoutMs = 200; // will wait at most for 200 ms
do
{
XEvent event;
if (XCheckTypedWindowEvent (display, juce_messageWindowHandle, SelectionNotify, &event))
{
if (event.xselection.property == property_name)
{
jassert (event.xselection.requestor == juce_messageWindowHandle);
selection_content = juce_readWindowProperty (event.xselection.requestor,
event.xselection.property,
requested_format, true);
return true;
}
else
{
return false; // the format we asked for was denied.. (event.xselection.property == None)
}
}
// not very elegant.. we could do a select() or something like that...
// however clipboard content requesting is inherently slow on x11, it
// often takes 50ms or more so...
Thread::sleep (4);
timeoutMs -= 4;
}
while (timeoutMs > 0);
DBG("timeout for juce_requestSelectionContent");
return false;
}
//==============================================================================
// Called from the event loop in juce_linux_Messaging in response to SelectionRequest events
void juce_handleSelectionRequest (XSelectionRequestEvent &evt)
{
initSelectionAtoms();
// the selection content is sent to the target window as a window property
XSelectionEvent reply;
reply.type = SelectionNotify;
reply.display = evt.display;
reply.requestor = evt.requestor;
reply.selection = evt.selection;
reply.target = evt.target;
reply.property = None; // == "fail"
reply.time = evt.time;
HeapBlock <char> data;
int propertyFormat = 0, numDataItems = 0;
if (evt.selection == XA_PRIMARY || evt.selection == atom_CLIPBOARD)
{
if (evt.target == XA_STRING)
{
// format data according to system locale
numDataItems = localClipboardContent.length();
data.calloc (numDataItems + 2);
localClipboardContent.copyToBuffer ((char*) data, numDataItems + 1);
propertyFormat = 8; // bits/item
}
else if (evt.target == atom_UTF8_STRING)
{
// translate to utf8
numDataItems = localClipboardContent.copyToUTF8 (0);
data.calloc (numDataItems + 2);
localClipboardContent.copyToUTF8 (data, numDataItems + 1);
propertyFormat = 8; // bits/item
}
else if (evt.target == atom_TARGETS)
{
// another application wants to know what we are able to send
numDataItems = 2;
propertyFormat = 32; // atoms are 32-bit
data.calloc (numDataItems * 4);
((Atom*) data)[0] = atom_UTF8_STRING;
((Atom*) data)[1] = XA_STRING;
}
}
else
{
DBG ("requested unsupported clipboard");
}
if (data != 0)
{
const int maxReasonableSelectionSize = 1000000;
// for very big chunks of data, we should use the "INCR" protocol , which is a pain in the *ss
if (evt.property != None && numDataItems < maxReasonableSelectionSize)
{
XChangeProperty (evt.display, evt.requestor,
evt.property, evt.target,
propertyFormat /* 8 or 32 */, PropModeReplace,
(const unsigned char*) data, numDataItems);
reply.property = evt.property; // " == success"
}
}
XSendEvent (evt.display, evt.requestor, 0, NoEventMask, (XEvent*) &reply);
}
//==============================================================================
void SystemClipboard::copyTextToClipboard (const String& clipText) throw()
{
initSelectionAtoms();
localClipboardContent = clipText;
XSetSelectionOwner (display, XA_PRIMARY, juce_messageWindowHandle, CurrentTime);
XSetSelectionOwner (display, atom_CLIPBOARD, juce_messageWindowHandle, CurrentTime);
}
const String SystemClipboard::getTextFromClipboard() throw()
{
initSelectionAtoms();
/* 1) try to read from the "CLIPBOARD" selection first (the "high
level" clipboard that is supposed to be filled by ctrl-C
etc). When a clipboard manager is running, the content of this
selection is preserved even when the original selection owner
exits.
2) and then try to read from "PRIMARY" selection (the "legacy" selection
filled by good old x11 apps such as xterm)
*/
String content;
Atom selection = XA_PRIMARY;
Window selectionOwner = None;
if ((selectionOwner = XGetSelectionOwner (display, selection)) == None)
{
selection = atom_CLIPBOARD;
selectionOwner = XGetSelectionOwner (display, selection);
}
if (selectionOwner != None)
{
if (selectionOwner == juce_messageWindowHandle)
{
content = localClipboardContent;
}
else
{
// first try: we want an utf8 string
bool ok = juce_requestSelectionContent (content, selection, atom_UTF8_STRING);
if (! ok)
{
// second chance, ask for a good old locale-dependent string ..
ok = juce_requestSelectionContent (content, selection, XA_STRING);
}
}
}
return content;
}
#endif

View file

@ -39,6 +39,62 @@ void FileChooser::showPlatformDialog (OwnedArray<File>& results,
bool selectMultipleFiles,
FilePreviewComponent* previewComponent)
{
const tchar* const separator = T(":");
String command ("zenity --file-selection");
if (title.isNotEmpty())
command << " --title=\"" << title << "\"";
if (file != File::nonexistent)
command << " --filename=\"" << file.getFullPathName () << "\"";
if (isDirectory)
command << " --directory";
if (isSave)
command << " --save";
if (selectMultipleFiles)
command << " --multiple --separator=\"" << separator << "\"";
command << " 2>&1";
MemoryOutputStream result;
int status = -1;
FILE* stream = popen ((const char*) command.toUTF8(), "r");
if (stream != 0)
{
for (;;)
{
char buffer [1024];
const int bytesRead = fread (buffer, 1, sizeof (buffer), stream);
if (bytesRead <= 0)
break;
result.write (buffer, bytesRead);
}
status = pclose (stream);
}
if (status == 0)
{
String resultString (String::fromUTF8 ((const uint8*) result.getData(), result.getDataSize()));
StringArray tokens;
if (selectMultipleFiles)
tokens.addTokens (resultString, separator, 0);
else
tokens.add (resultString);
for (int i = 0; i < tokens.size(); i++)
results.add (new File (tokens[i]));
return;
}
//xxx ain't got one!
jassertfalse
}

View file

@ -29,11 +29,11 @@
//==============================================================================
#ifdef JUCE_DEBUG
#define JUCE_DEBUG_XERRORS 1
#define JUCE_DEBUG_XERRORS 1
#endif
Display* display = 0; // This is also referenced from WindowDriver.cpp
static Window juce_messageWindowHandle = None;
Window juce_messageWindowHandle = None;
#define SpecialAtom "JUCESpecialAtom"
#define BroadcastAtom "JUCEBroadcastAtom"
@ -49,8 +49,70 @@ XContext improbableNumber;
// Defined in WindowDriver.cpp
extern void juce_windowMessageReceive (XEvent* event);
// Defined in ClipboardDriver.cpp
extern void juce_handleSelectionRequest (XSelectionRequestEvent &evt);
//==============================================================================
class InternalMessageQueue
{
public:
InternalMessageQueue()
{
int ret = ::socketpair (AF_LOCAL, SOCK_STREAM, 0, fd);
(void) ret; jassert (ret == 0);
}
~InternalMessageQueue()
{
close (fd[0]);
close (fd[1]);
}
void postMessage (Message* msg)
{
ScopedLock sl (lock);
queue.add (msg);
const unsigned char x = 0xff;
write (fd[0], &x, 1);
}
bool isEmpty() const
{
ScopedLock sl (lock);
return queue.size() == 0;
}
Message* popMessage()
{
Message* m = 0;
ScopedLock sl (lock);
if (queue.size() != 0)
{
unsigned char x;
read (fd[1], &x, 1);
m = queue.getUnchecked(0);
queue.remove (0, false /* deleteObject */);
}
return m;
}
int getWaitHandle() const { return fd[1]; }
private:
CriticalSection lock;
OwnedArray <Message> queue;
int fd[2];
};
//==============================================================================
struct MessageThreadFuncCall
{
enum { uniqueID = 0x73774623 };
MessageCallbackFunction* func;
void* parameter;
void* result;
@ -58,21 +120,23 @@ struct MessageThreadFuncCall
WaitableEvent event;
};
static bool errorCondition = false;
//==============================================================================
static InternalMessageQueue* juce_internalMessageQueue = 0;
// error handling in X11
static bool errorOccurred = false;
static bool keyboardBreakOccurred = false;
static XErrorHandler oldErrorHandler = (XErrorHandler) 0;
static XIOErrorHandler oldIOErrorHandler = (XIOErrorHandler) 0;
// (defined in another file to avoid problems including certain headers in this one)
extern bool juce_isRunningAsApplication();
// Usually happens when client-server connection is broken
static int ioErrorHandler (Display* display)
{
DBG (T("ERROR: connection to X server broken.. terminating."));
errorCondition = true;
errorOccurred = true;
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
Process::terminate();
return 0;
@ -100,20 +164,18 @@ static int errorHandler (Display* display, XErrorEvent* event)
return 0;
}
static bool breakIn = false;
// Breakin from keyboard
static void sig_handler (int sig)
static void signalHandler (int sig)
{
if (sig == SIGINT)
{
breakIn = true;
keyboardBreakOccurred = true;
return;
}
static bool reentrant = false;
if (reentrant == false)
if (! reentrant)
{
reentrant = true;
@ -121,14 +183,14 @@ static void sig_handler (int sig)
fflush (stdout);
Logger::outputDebugString ("ERROR: Program executed illegal instruction.. terminating");
errorCondition = true;
errorOccurred = true;
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
Process::terminate();
}
else
{
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
exit(0);
}
}
@ -146,7 +208,7 @@ void MessageManager::doPlatformSpecificInitialisation()
// This is fatal! Print error and closedown
Logger::outputDebugString ("Failed to initialise xlib thread support.");
if (juce_isRunningAsApplication())
if (JUCEApplication::getInstance() != 0)
Process::terminate();
return;
@ -165,7 +227,7 @@ void MessageManager::doPlatformSpecificInitialisation()
struct sigaction saction;
sigset_t maskSet;
sigemptyset (&maskSet);
saction.sa_handler = sig_handler;
saction.sa_handler = signalHandler;
saction.sa_mask = maskSet;
saction.sa_flags = 0;
sigaction (SIGINT, &saction, NULL);
@ -179,6 +241,10 @@ void MessageManager::doPlatformSpecificInitialisation()
sigaction (SIGSYS, &saction, NULL);
#endif
// Create the internal message queue
juce_internalMessageQueue = new InternalMessageQueue();
// Try to connect to a display
String displayName (getenv ("DISPLAY"));
if (displayName.isEmpty())
displayName = T(":0.0");
@ -187,12 +253,7 @@ void MessageManager::doPlatformSpecificInitialisation()
if (display == 0)
{
// This is fatal! Print error and closedown
Logger::outputDebugString ("Failed to open the X display.");
if (juce_isRunningAsApplication())
Process::terminate();
// This is not fatal! we can run headless.
return;
}
@ -223,7 +284,9 @@ void MessageManager::doPlatformSpecificInitialisation()
void MessageManager::doPlatformSpecificShutdown()
{
if (errorCondition == false)
deleteAndZero (juce_internalMessageQueue);
if (display != 0 && ! errorOccurred)
{
XDestroyWindow (display, juce_messageWindowHandle);
XCloseDisplay (display);
@ -242,9 +305,15 @@ void MessageManager::doPlatformSpecificShutdown()
bool juce_postMessageToSystemQueue (void* message)
{
if (errorCondition)
if (errorOccurred)
return false;
juce_internalMessageQueue->postMessage ((Message*) message);
return true;
}
/*bool juce_postMessageToX11Queue (void *message)
{
XClientMessageEvent clientMsg;
clientMsg.display = display;
clientMsg.window = juce_messageWindowHandle;
@ -264,131 +333,79 @@ bool juce_postMessageToSystemQueue (void* message)
XFlush (display); // This is necessary to ensure the event is delivered
return true;
}
}*/
void MessageManager::broadcastMessage (const String& value) throw()
{
/* TODO */
}
void* MessageManager::callFunctionOnMessageThread (MessageCallbackFunction* func,
void* parameter)
{
void* retVal = 0;
if (errorOccurred)
return 0;
if (! errorCondition)
if (! isThisTheMessageThread())
{
if (! isThisTheMessageThread())
{
static MessageThreadFuncCall messageFuncCallContext;
MessageThreadFuncCall messageCallContext;
messageCallContext.func = func;
messageCallContext.parameter = parameter;
const ScopedLock sl (messageFuncCallContext.lock);
juce_internalMessageQueue->postMessage (new Message (MessageThreadFuncCall::uniqueID,
0, 0, &messageCallContext));
XClientMessageEvent clientMsg;
clientMsg.display = display;
clientMsg.window = juce_messageWindowHandle;
clientMsg.type = ClientMessage;
clientMsg.format = 32;
clientMsg.message_type = specialCallbackId;
#if JUCE_64BIT
clientMsg.data.l[0] = (long) (0x00000000ffffffff & (((uint64) &messageFuncCallContext) >> 32));
clientMsg.data.l[1] = (long) (0x00000000ffffffff & (uint64) &messageFuncCallContext);
#else
clientMsg.data.l[0] = (long) &messageFuncCallContext;
#endif
// Wait for it to complete before continuing
messageCallContext.event.wait();
messageFuncCallContext.func = func;
messageFuncCallContext.parameter = parameter;
if (XSendEvent (display, juce_messageWindowHandle, false, NoEventMask, (XEvent*) &clientMsg) == 0)
return 0;
XFlush (display); // This is necessary to ensure the event is delivered
// Wait for it to complete before continuing
messageFuncCallContext.event.wait();
retVal = messageFuncCallContext.result;
}
else
{
// Just call the function directly
retVal = func (parameter);
}
return messageCallContext.result;
}
else
{
// Just call the function directly
return func (parameter);
}
return retVal;
}
bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
// Wait for an event (either XEvent, or an internal Message)
static bool juce_sleepUntilEvent (const int timeoutMs)
{
if (errorCondition)
return false;
if ((display != 0 && XPending (display)) || ! juce_internalMessageQueue->isEmpty())
return true;
if (breakIn)
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = timeoutMs * 1000;
int fd0 = juce_internalMessageQueue->getWaitHandle();
int fdmax = fd0;
fd_set readset;
FD_ZERO (&readset);
FD_SET (fd0, &readset);
if (display != 0)
{
errorCondition = true;
if (juce_isRunningAsApplication())
Process::terminate();
return false;
int fd1 = XConnectionNumber (display);
FD_SET (fd1, &readset);
fdmax = jmax (fd0, fd1);
}
if (returnIfNoPendingMessages && ! XPending (display))
int ret = select (fdmax + 1, &readset, 0, 0, &tv);
return (ret > 0); // ret <= 0 if error or timeout
}
// Handle next XEvent (if any)
static bool juce_dispatchNextXEvent()
{
if (display == 0 || ! XPending (display))
return false;
XEvent evt;
XNextEvent (display, &evt);
if (evt.type == ClientMessage && evt.xany.window == juce_messageWindowHandle)
if (evt.type == SelectionRequest && evt.xany.window == juce_messageWindowHandle)
{
XClientMessageEvent* const clientMsg = (XClientMessageEvent*) &evt;
if (clientMsg->format != 32)
{
jassertfalse
DBG ("Error: juce_dispatchNextMessageOnSystemQueue received malformed client message.");
}
else
{
JUCE_TRY
{
#if JUCE_64BIT
void* const messagePtr
= (void*) ((0xffffffff00000000 & (((uint64) clientMsg->data.l[0]) << 32))
| (clientMsg->data.l[1] & 0x00000000ffffffff));
#else
void* const messagePtr = (void*) (clientMsg->data.l[0]);
#endif
if (clientMsg->message_type == specialId)
{
MessageManager::getInstance()->deliverMessage (messagePtr);
}
else if (clientMsg->message_type == specialCallbackId)
{
MessageThreadFuncCall* const call = (MessageThreadFuncCall*) messagePtr;
MessageCallbackFunction* func = call->func;
call->result = (*func) (call->parameter);
call->event.signal();
}
else if (clientMsg->message_type == broadcastId)
{
#if 0
TCHAR buffer[8192];
zeromem (buffer, sizeof (buffer));
if (GlobalGetAtomName ((ATOM) lParam, buffer, 8192) != 0)
mq->deliverBroadcastMessage (String (buffer));
#endif
}
else
{
DBG ("Error: juce_dispatchNextMessageOnSystemQueue received unknown client message.");
}
}
JUCE_CATCH_ALL
}
juce_handleSelectionRequest (evt.xselectionrequest);
}
else if (evt.xany.window != juce_messageWindowHandle)
{
@ -398,4 +415,74 @@ bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
return true;
}
// Handle next internal Message (if any)
static bool juce_dispatchNextInternalMessage()
{
if (juce_internalMessageQueue->isEmpty())
return false;
ScopedPointer <Message> msg (juce_internalMessageQueue->popMessage());
if (msg->intParameter1 == MessageThreadFuncCall::uniqueID)
{
// Handle callback message
MessageThreadFuncCall* const call = (MessageThreadFuncCall*) msg->pointerParameter;
call->result = (*(call->func)) (call->parameter);
call->event.signal();
}
else
{
// Handle "normal" messages
MessageManager::getInstance()->deliverMessage (msg.release());
}
return true;
}
// this function expects that it will NEVER be called simultaneously for two concurrent threads
bool juce_dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages)
{
for (;;)
{
if (errorOccurred)
break;
if (keyboardBreakOccurred)
{
errorOccurred = true;
if (JUCEApplication::getInstance() != 0)
Process::terminate();
break;
}
static int totalEventCount = 0;
++totalEventCount;
// The purpose here is to give either priority to XEvents or
// to internal messages This is necessary to keep a "good"
// behaviour when the cpu is overloaded
if (totalEventCount & 1)
{
if (juce_dispatchNextXEvent() || juce_dispatchNextInternalMessage())
return true;
}
else
{
if (juce_dispatchNextInternalMessage() || juce_dispatchNextXEvent())
return true;
}
if (returnIfNoPendingMessages) // early exit
break;
// the timeout is to be on the safe side, but it does not seem to be useful
juce_sleepUntilEvent (2000);
}
return false;
}
#endif

View file

@ -100,12 +100,6 @@ bool Process::isForegroundProcess()
return isActiveApplication;
}
// (used in the messaging code, declared here for build reasons)
bool juce_isRunningAsApplication()
{
return JUCEApplication::getInstance() != 0;
}
//==============================================================================
// These are defined in juce_linux_Messaging.cpp
extern Display* display;
@ -611,7 +605,7 @@ public:
// blit results to screen.
#if JUCE_USE_XSHM
if (usingXShm)
XShmPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh, False);
XShmPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh, True);
else
#endif
XPutImage (display, (::Drawable) window, gc, xImage, sx, sy, dx, dy, dw, dh);
@ -1627,6 +1621,10 @@ public:
break;
default:
#if JUCE_USE_XSHM
if (event->xany.type == XShmGetEventBase (display))
repainter->notifyPaintCompleted();
#endif
break;
}
}
@ -1716,6 +1714,8 @@ private:
lastTimeImageUsed (0)
{
#if JUCE_USE_XSHM
shmCompletedDrawing = true;
useARGBImagesForRendering = isShmAvailable();
if (useARGBImagesForRendering)
@ -1738,7 +1738,7 @@ private:
void timerCallback()
{
if (! regionsNeedingRepaint.isEmpty())
if (! regionsNeedingRepaint.isEmpty() && shmCompletedDrawing)
{
stopTimer();
performAnyPendingRepaintsNow();
@ -1766,6 +1766,8 @@ private:
if (! totalArea.isEmpty())
{
shmCompletedDrawing = false;
if (image == 0 || image->getWidth() < totalArea.getWidth()
|| image->getHeight() < totalArea.getHeight())
{
@ -1809,6 +1811,13 @@ private:
startTimer (repaintTimerPeriod);
}
#if JUCE_USE_XSHM
void notifyPaintCompleted()
{
shmCompletedDrawing = true;
}
#endif
private:
LinuxComponentPeer* const peer;
ScopedPointer <XBitmapImage> image;
@ -1817,6 +1826,7 @@ private:
#if JUCE_USE_XSHM
bool useARGBImagesForRendering;
bool shmCompletedDrawing;
#endif
LinuxRepaintManager (const LinuxRepaintManager&);
const LinuxRepaintManager& operator= (const LinuxRepaintManager&);
@ -2555,6 +2565,9 @@ void juce_windowMessageReceive (XEvent* event)
//==============================================================================
void juce_updateMultiMonitorInfo (Array <Rectangle>& monitorCoords, const bool /*clipToWorkArea*/) throw()
{
if (display == 0)
return;
#if JUCE_USE_XINERAMA
int major_opcode, first_event, first_error;
@ -3096,85 +3109,6 @@ void OpenGLPixelFormat::getAvailablePixelFormats (Component* component,
#endif
//==============================================================================
static void initClipboard (Window root, Atom* cutBuffers) throw()
{
static bool init = false;
if (! init)
{
init = true;
// Make sure all cut buffers exist before use
for (int i = 0; i < 8; i++)
{
XChangeProperty (display, root, cutBuffers[i],
XA_STRING, 8, PropModeAppend, NULL, 0);
}
}
}
// Clipboard implemented currently using cut buffers
// rather than the more powerful selection method
void SystemClipboard::copyTextToClipboard (const String& clipText) throw()
{
Window root = RootWindow (display, DefaultScreen (display));
Atom cutBuffers[8] = { XA_CUT_BUFFER0, XA_CUT_BUFFER1, XA_CUT_BUFFER2, XA_CUT_BUFFER3,
XA_CUT_BUFFER4, XA_CUT_BUFFER5, XA_CUT_BUFFER6, XA_CUT_BUFFER7 };
initClipboard (root, cutBuffers);
XRotateWindowProperties (display, root, cutBuffers, 8, 1);
XChangeProperty (display, root, cutBuffers[0],
XA_STRING, 8, PropModeReplace, (const unsigned char*) (const char*) clipText,
clipText.length());
}
const String SystemClipboard::getTextFromClipboard() throw()
{
const int bufSize = 64; // in words
String returnData;
int byteOffset = 0;
Window root = RootWindow (display, DefaultScreen (display));
Atom cutBuffers[8] = { XA_CUT_BUFFER0, XA_CUT_BUFFER1, XA_CUT_BUFFER2, XA_CUT_BUFFER3,
XA_CUT_BUFFER4, XA_CUT_BUFFER5, XA_CUT_BUFFER6, XA_CUT_BUFFER7 };
initClipboard (root, cutBuffers);
for (;;)
{
unsigned long bytesLeft = 0, nitems = 0;
unsigned char* clipData = 0;
int actualFormat = 0;
Atom actualType;
if (XGetWindowProperty (display, root, cutBuffers[0], byteOffset >> 2, bufSize,
False, XA_STRING, &actualType, &actualFormat, &nitems, &bytesLeft,
&clipData) == Success)
{
if (actualType == XA_STRING && actualFormat == 8)
{
byteOffset += nitems;
returnData += String ((const char*) clipData, nitems);
}
else
{
bytesLeft = 0;
}
if (clipData != 0)
XFree (clipData);
}
if (bytesLeft == 0)
break;
}
return returnData;
}
//==============================================================================
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMoveFiles)
{

View file

@ -53,7 +53,6 @@ END_JUCE_NAMESPACE
- (void) captureOutput: (QTCaptureFileOutput*) captureOutput
didOutputSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection;
@end
BEGIN_JUCE_NAMESPACE
@ -120,6 +119,7 @@ public:
void resetFile()
{
[fileOutput recordToOutputFileURL: nil];
[session removeOutput: fileOutput];
[fileOutput release];
fileOutput = [[QTCaptureMovieFileOutput alloc] init];
@ -199,11 +199,14 @@ END_JUCE_NAMESPACE
withSampleBuffer: (QTSampleBuffer*) sampleBuffer
fromConnection: (QTCaptureConnection*) connection
{
const ScopedAutoReleasePool pool;
if (internal->listeners.size() > 0)
{
const ScopedAutoReleasePool pool;
internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame],
CVPixelBufferGetWidth (videoFrame),
CVPixelBufferGetHeight (videoFrame));
internal->callListeners ([CIImage imageWithCVImageBuffer: videoFrame],
CVPixelBufferGetWidth (videoFrame),
CVPixelBufferGetHeight (videoFrame));
}
}
- (void) captureOutput: (QTCaptureFileOutput*) captureOutput
@ -338,12 +341,11 @@ CameraDevice* CameraDevice::openDevice (int index,
int minWidth, int minHeight,
int maxWidth, int maxHeight)
{
CameraDevice* d = new CameraDevice (getAvailableDevices() [index], index);
ScopedPointer <CameraDevice> d (new CameraDevice (getAvailableDevices() [index], index));
if (((QTCameraDeviceInteral*) (d->internal))->openingError.isEmpty())
return d;
return d.release();
delete d;
return 0;
}