@@ -28,10 +28,15 @@ | |||
#define JUCE_COREAUDIOLOG(a) | |||
#endif | |||
#ifdef __clang__ | |||
#pragma clang diagnostic push | |||
#pragma clang diagnostic ignored "-Wnonnull" // aovid some spurious 10.11 SDK warnings | |||
#endif | |||
//============================================================================== | |||
struct SystemVol | |||
{ | |||
SystemVol (AudioObjectPropertySelector selector) | |||
SystemVol (AudioObjectPropertySelector selector) noexcept | |||
: outputDeviceID (kAudioObjectUnknown) | |||
{ | |||
addr.mScope = kAudioObjectPropertyScopeGlobal; | |||
@@ -56,7 +61,7 @@ struct SystemVol | |||
} | |||
} | |||
float getGain() | |||
float getGain() const noexcept | |||
{ | |||
Float32 gain = 0; | |||
@@ -70,7 +75,7 @@ struct SystemVol | |||
return (float) gain; | |||
} | |||
bool setGain (float gain) | |||
bool setGain (float gain) const noexcept | |||
{ | |||
if (outputDeviceID != kAudioObjectUnknown && canSetVolume()) | |||
{ | |||
@@ -84,7 +89,7 @@ struct SystemVol | |||
return false; | |||
} | |||
bool isMuted() | |||
bool isMuted() const noexcept | |||
{ | |||
UInt32 muted = 0; | |||
@@ -98,7 +103,7 @@ struct SystemVol | |||
return muted != 0; | |||
} | |||
bool setMuted (bool mute) | |||
bool setMuted (bool mute) const noexcept | |||
{ | |||
if (outputDeviceID != kAudioObjectUnknown && canSetVolume()) | |||
{ | |||
@@ -116,7 +121,7 @@ private: | |||
AudioDeviceID outputDeviceID; | |||
AudioObjectPropertyAddress addr; | |||
bool canSetVolume() | |||
bool canSetVolume() const noexcept | |||
{ | |||
Boolean isSettable = NO; | |||
return AudioHardwareServiceIsPropertySettable (outputDeviceID, &addr, &isSettable) == noErr | |||
@@ -124,6 +129,10 @@ private: | |||
} | |||
}; | |||
#ifdef __clang__ | |||
#pragma clang diagnostic pop | |||
#endif | |||
#define JUCE_SYSTEMAUDIOVOL_IMPLEMENTED 1 | |||
float JUCE_CALLTYPE SystemAudioVolume::getGain() { return SystemVol (kAudioHardwareServiceDeviceProperty_VirtualMasterVolume).getGain(); } | |||
bool JUCE_CALLTYPE SystemAudioVolume::setGain (float gain) { return SystemVol (kAudioHardwareServiceDeviceProperty_VirtualMasterVolume).setGain (gain); } | |||
@@ -507,7 +507,7 @@ public: | |||
UInt32 GetAudioChannelLayout (AudioUnitScope scope, | |||
AudioUnitElement element, | |||
AudioChannelLayout *outLayoutPtr, | |||
Boolean &outWritable) | |||
Boolean &outWritable) override | |||
{ | |||
// fallback to old code if this plug-in does not have multi channel IO | |||
if (! hasMultiChannelConfiguration()) | |||
@@ -62,17 +62,25 @@ namespace SocketHelpers | |||
#endif | |||
} | |||
static bool resetSocketOptions (const SocketHandle handle, const bool isDatagram, const bool allowBroadcast) noexcept | |||
template <typename Type> | |||
static bool setOption (const SocketHandle handle, int mode, int property, Type value) noexcept | |||
{ | |||
const int sndBufSize = 65536; | |||
const int rcvBufSize = 65536; | |||
const int one = 1; | |||
return setsockopt (handle, mode, property, reinterpret_cast<const char*> (&value), sizeof (value)) == 0; | |||
} | |||
template <typename Type> | |||
static bool setOption (const SocketHandle handle, int property, Type value) noexcept | |||
{ | |||
return setOption (handle, SOL_SOCKET, property, value); | |||
} | |||
static bool resetSocketOptions (const SocketHandle handle, const bool isDatagram, const bool allowBroadcast) noexcept | |||
{ | |||
return handle > 0 | |||
&& setsockopt (handle, SOL_SOCKET, SO_RCVBUF, (const char*) &rcvBufSize, sizeof (rcvBufSize)) == 0 | |||
&& setsockopt (handle, SOL_SOCKET, SO_SNDBUF, (const char*) &sndBufSize, sizeof (sndBufSize)) == 0 | |||
&& (isDatagram ? ((! allowBroadcast) || setsockopt (handle, SOL_SOCKET, SO_BROADCAST, (const char*) &one, sizeof (one)) == 0) | |||
: (setsockopt (handle, IPPROTO_TCP, TCP_NODELAY, (const char*) &one, sizeof (one)) == 0)); | |||
&& setOption (handle, SO_RCVBUF, (int) 65536) | |||
&& setOption (handle, SO_SNDBUF, (int) 65536) | |||
&& (isDatagram ? ((! allowBroadcast) || setOption (handle, SO_BROADCAST, (int) 1)) | |||
: setOption (handle, IPPROTO_TCP, TCP_NODELAY, (int) 1)); | |||
} | |||
static void closeSocket (volatile int& handle, CriticalSection& readLock, | |||
@@ -136,8 +144,12 @@ namespace SocketHelpers | |||
servTmpAddr.sin_addr.s_addr = htonl (INADDR_ANY); | |||
servTmpAddr.sin_port = htons ((uint16) port); | |||
#if JUCE_WINDOWS | |||
if (address.isNotEmpty()) | |||
servTmpAddr.sin_addr.s_addr = ::inet_addr (address.toUTF8()); | |||
#else | |||
ignoreUnused (address); | |||
#endif | |||
return bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) >= 0; | |||
} | |||
@@ -308,8 +320,7 @@ namespace SocketHelpers | |||
hints.ai_flags = AI_NUMERICSERV; | |||
struct addrinfo* info = nullptr; | |||
if (getaddrinfo (hostName.toUTF8(), String (portNumber).toUTF8(), &hints, &info) == 0 | |||
&& info != nullptr) | |||
if (getaddrinfo (hostName.toUTF8(), String (portNumber).toUTF8(), &hints, &info) == 0) | |||
return info; | |||
return nullptr; | |||
@@ -364,8 +375,7 @@ namespace SocketHelpers | |||
static void makeReusable (int handle) noexcept | |||
{ | |||
const int reuse = 1; | |||
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse)); | |||
setOption (handle, SO_REUSEADDR, (int) 1); | |||
} | |||
static bool multicast (int handle, const String& multicastIPAddress, | |||
@@ -380,9 +390,10 @@ namespace SocketHelpers | |||
if (interfaceIPAddress.isNotEmpty()) | |||
mreq.imr_interface.s_addr = inet_addr (interfaceIPAddress.toUTF8()); | |||
int joinCmd = join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; | |||
return setsockopt (handle, IPPROTO_IP, joinCmd, (const char*) &mreq, sizeof (mreq)) == 0; | |||
return setsockopt (handle, IPPROTO_IP, | |||
join ? IP_ADD_MEMBERSHIP | |||
: IP_DROP_MEMBERSHIP, | |||
(const char*) &mreq, sizeof (mreq)) == 0; | |||
} | |||
} | |||
@@ -569,6 +580,7 @@ DatagramSocket::DatagramSocket (const bool canBroadcast) | |||
SocketHelpers::initSockets(); | |||
handle = (int) socket (AF_INET, SOCK_DGRAM, 0); | |||
if (handle >= 0) | |||
{ | |||
SocketHelpers::resetSocketOptions (handle, true, canBroadcast); | |||
@@ -579,7 +591,7 @@ DatagramSocket::DatagramSocket (const bool canBroadcast) | |||
DatagramSocket::~DatagramSocket() | |||
{ | |||
if (lastServerAddress != nullptr) | |||
freeaddrinfo (static_cast <struct addrinfo*> (lastServerAddress)); | |||
freeaddrinfo (static_cast<struct addrinfo*> (lastServerAddress)); | |||
shutdown(); | |||
} | |||
@@ -660,7 +672,7 @@ int DatagramSocket::write (const String& remoteHostname, int remotePortNumber, | |||
if (handle < 0) | |||
return -1; | |||
struct addrinfo*& info = reinterpret_cast <struct addrinfo*&> (lastServerAddress); | |||
struct addrinfo*& info = reinterpret_cast<struct addrinfo*&> (lastServerAddress); | |||
// getaddrinfo can be quite slow so cache the result of the address lookup | |||
if (info == nullptr || remoteHostname != lastServerHost || remotePortNumber != lastServerPort) | |||
@@ -698,25 +710,18 @@ bool DatagramSocket::leaveMulticast (const String& multicastIPAddress) | |||
bool DatagramSocket::setEnablePortReuse (bool enabled) | |||
{ | |||
#if JUCE_ANDROID | |||
return false; | |||
#else | |||
const int reuse = enabled ? 1 : 0; | |||
#if JUCE_WINDOWS | |||
// port re-use is implied by addr re-use on windows | |||
const int optname = SO_REUSEADDR; | |||
#else | |||
const int optname = SO_REUSEPORT; | |||
#endif | |||
#if ! JUCE_ANDROID | |||
if (handle >= 0) | |||
return (setsockopt (handle, SOL_SOCKET, optname, | |||
(const char*) &reuse, sizeof (reuse)) == 0); | |||
return SocketHelpers::setOption (handle, | |||
#if JUCE_WINDOWS || JUCE_LINUX | |||
SO_REUSEADDR, // port re-use is implied by addr re-use on these platforms | |||
#else | |||
SO_REUSEPORT, | |||
#endif | |||
(int) (enabled ? 1 : 0)); | |||
#endif | |||
return false; | |||
#endif | |||
} | |||
#if JUCE_MSVC | |||
@@ -958,22 +958,26 @@ XmlElement* ValueTree::createXml() const | |||
ValueTree ValueTree::fromXml (const XmlElement& xml) | |||
{ | |||
// ValueTrees don't have any equivalent to XML text elements! | |||
jassert (! xml.isTextElement()); | |||
if (! xml.isTextElement()) | |||
{ | |||
ValueTree v (xml.getTagName()); | |||
v.object->properties.setFromXmlAttributes (xml); | |||
ValueTree v (xml.getTagName()); | |||
v.object->properties.setFromXmlAttributes (xml); | |||
forEachXmlChildElement (xml, e) | |||
v.addChild (fromXml (*e), -1, nullptr); | |||
forEachXmlChildElement (xml, e) | |||
v.addChild (fromXml (*e), -1, nullptr); | |||
return v; | |||
} | |||
return v; | |||
// ValueTrees don't have any equivalent to XML text elements! | |||
jassertfalse; | |||
return ValueTree(); | |||
} | |||
String ValueTree::toXmlString() const | |||
{ | |||
const ScopedPointer<XmlElement> xml (createXml()); | |||
return xml != nullptr ? xml->createDocument ("") : String(); | |||
return xml != nullptr ? xml->createDocument (StringRef()) : String(); | |||
} | |||
//============================================================================== | |||
@@ -654,12 +654,13 @@ void GlyphArrangement::splitLines (const String& text, Font font, int startIndex | |||
float lineY = y; | |||
float widthPerLine = lineWidth / numLines; | |||
for (int line = 0; line < numLines; ++line) | |||
while (lineY < y + height) | |||
{ | |||
int i = startIndex; | |||
float lineStartX = glyphs.getReference (startIndex).getLeft(); | |||
const float lineStartX = glyphs.getReference (startIndex).getLeft(); | |||
const float lineBottomY = lineY + font.getHeight(); | |||
if (line == numLines - 1) | |||
if (lineBottomY >= y + height) | |||
{ | |||
widthPerLine = width; | |||
i = glyphs.size(); | |||
@@ -732,7 +733,7 @@ void GlyphArrangement::splitLines (const String& text, Font font, int startIndex | |||
minimumHorizontalScale); | |||
startIndex = i; | |||
lineY += font.getHeight(); | |||
lineY = lineBottomY; | |||
if (startIndex >= glyphs.size()) | |||
break; | |||
@@ -32,7 +32,8 @@ FileBrowserComponent::FileBrowserComponent (int flags_, | |||
previewComp (previewComp_), | |||
currentPathBox ("path"), | |||
fileLabel ("f", TRANS ("file:")), | |||
thread ("Juce FileBrowser") | |||
thread ("Juce FileBrowser"), | |||
wasProcessActive (false) | |||
{ | |||
// You need to specify one or other of the open/save flags.. | |||
jassert ((flags & (saveMode | openMode)) != 0); | |||
@@ -109,6 +110,8 @@ FileBrowserComponent::FileBrowserComponent (int flags_, | |||
setRoot (currentRoot); | |||
thread.startThread (4); | |||
startTimer (2000); | |||
} | |||
FileBrowserComponent::~FileBrowserComponent() | |||
@@ -178,7 +181,7 @@ void FileBrowserComponent::deselectAllFiles() | |||
bool FileBrowserComponent::isFileSuitable (const File& file) const | |||
{ | |||
return (flags & canSelectFiles) != 0 | |||
&& (fileFilter == nullptr || fileFilter->isFileSuitable (file)); | |||
&& (fileFilter == nullptr || fileFilter->isFileSuitable (file)); | |||
} | |||
bool FileBrowserComponent::isDirectorySuitable (const File&) const | |||
@@ -190,10 +193,10 @@ bool FileBrowserComponent::isFileOrDirSuitable (const File& f) const | |||
{ | |||
if (f.isDirectory()) | |||
return (flags & canSelectDirectories) != 0 | |||
&& (fileFilter == nullptr || fileFilter->isDirectorySuitable (f)); | |||
&& (fileFilter == nullptr || fileFilter->isDirectorySuitable (f)); | |||
return (flags & canSelectFiles) != 0 && f.exists() | |||
&& (fileFilter == nullptr || fileFilter->isFileSuitable (f)); | |||
&& (fileFilter == nullptr || fileFilter->isFileSuitable (f)); | |||
} | |||
//============================================================================== | |||
@@ -401,8 +404,6 @@ void FileBrowserComponent::browserRootChanged (const File&) {} | |||
bool FileBrowserComponent::keyPressed (const KeyPress& key) | |||
{ | |||
(void) key; | |||
#if JUCE_LINUX || JUCE_WINDOWS | |||
if (key.getModifiers().isCommandDown() | |||
&& (key.getKeyCode() == 'H' || key.getKeyCode() == 'h')) | |||
@@ -413,6 +414,7 @@ bool FileBrowserComponent::keyPressed (const KeyPress& key) | |||
} | |||
#endif | |||
ignoreUnused (key); | |||
return false; | |||
} | |||
@@ -589,3 +591,16 @@ void FileBrowserComponent::getRoots (StringArray& rootNames, StringArray& rootPa | |||
{ | |||
getDefaultRoots (rootNames, rootPaths); | |||
} | |||
void FileBrowserComponent::timerCallback() | |||
{ | |||
const bool isProcessActive = Process::isForegroundProcess(); | |||
if (wasProcessActive != isProcessActive) | |||
{ | |||
wasProcessActive = isProcessActive; | |||
if (isProcessActive && fileList != nullptr) | |||
refresh(); | |||
} | |||
} |
@@ -41,7 +41,8 @@ class JUCE_API FileBrowserComponent : public Component, | |||
private TextEditorListener, | |||
private ButtonListener, | |||
private ComboBoxListener, // (can't use ComboBox::Listener due to idiotic VC2005 bug) | |||
private FileFilter | |||
private FileFilter, | |||
private Timer | |||
{ | |||
public: | |||
//============================================================================== | |||
@@ -103,8 +104,7 @@ public: | |||
*/ | |||
File getSelectedFile (int index) const noexcept; | |||
/** Deselects any files that are currently selected. | |||
*/ | |||
/** Deselects any files that are currently selected. */ | |||
void deselectAllFiles(); | |||
/** Returns true if the currently selected file(s) are usable. | |||
@@ -150,8 +150,7 @@ public: | |||
*/ | |||
virtual String getActionVerb() const; | |||
/** Returns true if the saveMode flag was set when this component was created. | |||
*/ | |||
/** Returns true if the saveMode flag was set when this component was created. */ | |||
bool isSaveMode() const noexcept; | |||
/** Sets the label that will be displayed next to the filename entry box. | |||
@@ -243,10 +242,8 @@ public: | |||
bool isFileSuitable (const File&) const override; | |||
/** @internal */ | |||
bool isDirectorySuitable (const File&) const override; | |||
/** @internal */ | |||
FilePreviewComponent* getPreviewComponent() const noexcept; | |||
/** @internal */ | |||
DirectoryContentsDisplayComponent* getDisplayComponent() const noexcept; | |||
@@ -263,13 +260,13 @@ protected: | |||
private: | |||
//============================================================================== | |||
ScopedPointer <DirectoryContentsList> fileList; | |||
ScopedPointer<DirectoryContentsList> fileList; | |||
const FileFilter* fileFilter; | |||
int flags; | |||
File currentRoot; | |||
Array<File> chosenFiles; | |||
ListenerList <FileBrowserListener> listeners; | |||
ListenerList<FileBrowserListener> listeners; | |||
ScopedPointer<DirectoryContentsDisplayComponent> fileListComponent; | |||
FilePreviewComponent* previewComp; | |||
@@ -277,11 +274,12 @@ private: | |||
TextEditor filenameBox; | |||
Label fileLabel; | |||
ScopedPointer<Button> goUpButton; | |||
TimeSliceThread thread; | |||
bool wasProcessActive; | |||
void timerCallback() override; | |||
void sendListenerChangeMessage(); | |||
bool isFileOrDirSuitable (const File& f) const; | |||
bool isFileOrDirSuitable (const File&) const; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileBrowserComponent) | |||
}; | |||
@@ -41,7 +41,7 @@ | |||
Note: If all that you need to do is to respond to files being drag-and-dropped from | |||
the operating system onto your component, you don't need any of these classes: you can do this | |||
simply by overriding Component::filesDropped(). | |||
simply by overriding FileDragAndDropTarget::filesDropped(). | |||
@see DragAndDropTarget | |||
*/ | |||
@@ -1082,12 +1082,16 @@ void TextEditor::colourChanged() | |||
} | |||
void TextEditor::lookAndFeelChanged() | |||
{ | |||
recreateCaret(); | |||
} | |||
void TextEditor::recreateCaret() | |||
{ | |||
if (isCaretVisible()) | |||
{ | |||
setCaretVisible (false); | |||
setCaretVisible (true); | |||
updateCaretPosition(); | |||
} | |||
} | |||
@@ -1096,7 +1100,10 @@ void TextEditor::setCaretVisible (const bool shouldCaretBeVisible) | |||
if (shouldCaretBeVisible && ! isReadOnly()) | |||
{ | |||
if (caret == nullptr) | |||
{ | |||
textHolder->addChildComponent (caret = getLookAndFeel().createCaretComponent (this)); | |||
updateCaretPosition(); | |||
} | |||
} | |||
else | |||
{ | |||
@@ -2126,6 +2133,7 @@ void TextEditor::handleCommandMessage (const int commandId) | |||
void TextEditor::enablementChanged() | |||
{ | |||
recreateCaret(); | |||
repaint(); | |||
} | |||
@@ -712,6 +712,7 @@ private: | |||
void moveCaret (int newCaretPos); | |||
void moveCaretTo (int newPosition, bool isSelecting); | |||
void recreateCaret(); | |||
void handleCommandMessage (int) override; | |||
void coalesceSimilarSections(); | |||
void splitSection (int sectionIndex, int charToSplitAt); | |||