diff --git a/build/macosx/platform_specific_code/juce_mac_Windowing.cpp b/build/macosx/platform_specific_code/juce_mac_Windowing.cpp
index 459e7753f7..10c6733062 100644
--- a/build/macosx/platform_specific_code/juce_mac_Windowing.cpp
+++ b/build/macosx/platform_specific_code/juce_mac_Windowing.cpp
@@ -1937,15 +1937,15 @@ bool juce_isHIViewCreatedByJuce (HIViewRef view)
&& HIObjectIsOfClass ((HIObjectRef) view, juceHiViewClassNameCFString);
}
-bool juce_isWindowCreatedByJuce (WindowRef window)
-{
- for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
- if (ComponentPeer::getPeer(i)->getNativeHandle() == window)
- return true;
-
- return false;
-}
-
+bool juce_isWindowCreatedByJuce (WindowRef window)
+{
+ for (int i = ComponentPeer::getNumPeers(); --i >= 0;)
+ if (ComponentPeer::getPeer(i)->getNativeHandle() == window)
+ return true;
+
+ return false;
+}
+
static void trackNextMouseEvent()
{
UInt32 mods;
diff --git a/docs/JUCE changelist.txt b/docs/JUCE changelist.txt
index 004e3e12f3..e5a9d80a68 100644
--- a/docs/JUCE changelist.txt
+++ b/docs/JUCE changelist.txt
@@ -8,11 +8,11 @@ Changelist for version 1.45
- big new project in the "extras" folder - a basic audio plugin host! Currently it loads VSTs on PC/Mac, and lets you put them together in a filter graph, which it plays. Hosting functionality is very basic at the moment, but I'm laying down a good architecture to hopefully develop into a full cross-platform plugin host.
- audio plugins: I've simplified the processBlock() call in AudioFilterBase. It now just takes a single buffer for all input and output channels, and the accumulate parameter has gone. This will mean tweaking your plugin code, but will probably make it much less complicated.
-- audio plugins: AudioFilterBase now requires a few extra methods to be implemented by your plugin: getInputChannelName, getOutputChannelName, isInputChannelStereoPair, isOutputChannelStereoPair.
+- audio plugins: AudioFilterBase now requires a few extra methods to be implemented by your plugin: getInputChannelName, getOutputChannelName, isInputChannelStereoPair, isOutputChannelStereoPair, getLatencySamples (which supersedes the old macro for setting the latency)
- audio plugins: new method AudioFilterBase::updateHostDisplay() to tell the host that something about your plugin has changed and that it should refresh its display.
- audio plugins: new methods AudioFilterBase::beginParameterChangeGesture() and endParameterChangeGesture() let you tell the host when a parameter-change action starts and finishes.
- new class: FileSearchPathListComponent, for letting the user edit a FileSearchPath.
-
+- added a critical section option to ReferenceCountedArray
==============================================================================
Changelist for version 1.44
diff --git a/extras/audio plugins/How to use this framework.txt b/extras/audio plugins/How to use this framework.txt
index 3fbc2c5f7e..9cde1475a6 100644
--- a/extras/audio plugins/How to use this framework.txt
+++ b/extras/audio plugins/How to use this framework.txt
@@ -151,27 +151,28 @@ Compiling the juce demo RTAS on the PC:
- In Visual Studio, add all of this lot to your include path:
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\common
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\common\Platform
- c:\yourdirectory\PT_711_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public
- c:\yourdirectory\PT_711_SDK\AlturaPorts\SADriver\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\DigiPublic\Interfaces
- c:\yourdirectory\PT_711_SDK\AlturaPorts\Fic\Interfaces\DAEClient
- c:\yourdirectory\PT_711_SDK\AlturaPorts\NewFileLibs\Cmn
- c:\yourdirectory\PT_711_SDK\AlturaPorts\NewFileLibs\DOA
- c:\yourdirectory\PT_711_SDK\AlturaPorts\AlturaSource\PPC_H
- c:\yourdirectory\PT_711_SDK\AlturaPorts\AlturaSource\AppSupport
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\EffectClasses
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ProcessClasses\Interfaces
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Utilities
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\RTASP_Adapt
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\CoreClasses
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Controls
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Meters
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\ViewClasses
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\DSPClasses
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\PluginLibrary\Interfaces
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\common
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\common\Platform
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\TDMPlugins\SignalProcessing\Public
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\SADriver\Interfaces
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\DigiPublic\Interfaces
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\Fic\Interfaces\DAEClient
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\NewFileLibs\Cmn
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\NewFileLibs\DOA
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\AlturaSource\PPC_H
+ c:\yourdirectory\PT_73_SDK\AlturaPorts\AlturaSource\AppSupport
+ c:\yourdirectory\PT_73_SDK\AvidCode\AVX2sdk\AVX\avx2\avx2sdk\inc
- The Visual Studio juce_RTAS project contains a folder called "libs", with "debug" and
"release" subdirectories - these should contain links to the Digidesign lib files
@@ -180,6 +181,12 @@ Compiling the juce demo RTAS on the PC:
- Fingers crossed, this should now compile..
+- IMPORTANT NOTE! If you're using MSVC2005 to build your plugin, the users will need to
+ have the Microsoft VC8 Runtime installed on their machines, otherwise the DLL will
+ silently fail to load. You should probably add the runtime to your plugin's installer,
+ and you can get a copy of it here:
+ http://www.microsoft.com/downloads/details.aspx?FamilyID=32bc1bee-a3f9-4c13-9c99-220b62a191ee&DisplayLang=en
+
Creating a project for your own RTAS on the PC:
=================================================
diff --git a/extras/audio plugins/demo/build/RTAS_Win32/juce_RTAS.vcproj b/extras/audio plugins/demo/build/RTAS_Win32/juce_RTAS.vcproj
index f782ce1c17..eeb6728f52 100644
--- a/extras/audio plugins/demo/build/RTAS_Win32/juce_RTAS.vcproj
+++ b/extras/audio plugins/demo/build/RTAS_Win32/juce_RTAS.vcproj
@@ -542,7 +542,7 @@
Name="debug"
>
GetStreamFormat().mChannelsPerFrame : 0;
+ const int numOuts = GetOutput(0) != 0 ? GetOutput(0)->GetStreamFormat().mChannelsPerFrame : 0;
+
+ bool isValidChannelConfig = false;
+
+ for (int i = 0; i < numChannelConfigs; ++i)
+ if (numIns == channelConfigs[i][0] && numOuts == channelConfigs[i][1])
+ isValidChannelConfig = true;
+
+ if (! isValidChannelConfig)
+ return kAudioUnitErr_FormatNotSupported;
+
prepareToPlay();
return noErr;
}
diff --git a/extras/audio plugins/wrapper/formats/RTAS/juce_RTASUtilities.cpp b/extras/audio plugins/wrapper/formats/RTAS/juce_RTASUtilities.cpp
index 3f415b196f..cab2f03d33 100644
--- a/extras/audio plugins/wrapper/formats/RTAS/juce_RTASUtilities.cpp
+++ b/extras/audio plugins/wrapper/formats/RTAS/juce_RTASUtilities.cpp
@@ -35,8 +35,16 @@
// at the same time as the Digi headers)
#include
+
+#ifdef _MSC_VER
+ #pragma pack (push, 8)
+#endif
+
#include "../../juce_AudioFilterBase.h"
-#include "../../juce_AudioFilterEditor.h"
+
+#ifdef _MSC_VER
+ #pragma pack (pop)
+#endif
//==============================================================================
diff --git a/extras/audio plugins/wrapper/formats/RTAS/juce_RTASWrapper.cpp b/extras/audio plugins/wrapper/formats/RTAS/juce_RTASWrapper.cpp
index 92eaa515ac..a8db307062 100644
--- a/extras/audio plugins/wrapper/formats/RTAS/juce_RTASWrapper.cpp
+++ b/extras/audio plugins/wrapper/formats/RTAS/juce_RTASWrapper.cpp
@@ -79,9 +79,18 @@
#include "CPluginControl_OnOff.h"
//==============================================================================
+#ifdef _MSC_VER
+ #pragma pack (push, 8)
+#endif
+
#include "../../juce_AudioFilterBase.h"
#include "../../juce_AudioFilterEditor.h"
#include "../../juce_IncludeCharacteristics.h"
+
+#ifdef _MSC_VER
+ #pragma pack (pop)
+#endif
+
#undef Component
//==============================================================================
@@ -526,7 +535,7 @@ protected:
ComponentResult GetDelaySamplesLong (long* aNumSamples)
{
if (aNumSamples != 0)
- *aNumSamples = JucePlugin_Latency;
+ *aNumSamples = juceFilter != 0 ? juceFilter->getLatencySamples() : 0;
return noErr;
}
diff --git a/extras/audio plugins/wrapper/formats/RTAS/juce_RTAS_dlldefs.def b/extras/audio plugins/wrapper/formats/RTAS/juce_RTAS_dlldefs.def
index 709ecd9f07..31b09258e4 100644
--- a/extras/audio plugins/wrapper/formats/RTAS/juce_RTAS_dlldefs.def
+++ b/extras/audio plugins/wrapper/formats/RTAS/juce_RTAS_dlldefs.def
@@ -1,5 +1,3 @@
EXPORTS
NewPlugIn @1
_PI_GetRoutineDescriptor @2
-
-
diff --git a/extras/audio plugins/wrapper/formats/VST/juce_VstWrapper.cpp b/extras/audio plugins/wrapper/formats/VST/juce_VstWrapper.cpp
index fb710cdf6c..9ae7650be4 100644
--- a/extras/audio plugins/wrapper/formats/VST/juce_VstWrapper.cpp
+++ b/extras/audio plugins/wrapper/formats/VST/juce_VstWrapper.cpp
@@ -91,7 +91,16 @@
#endif
//==============================================================================
+#ifdef _MSC_VER
+ #pragma pack (push, 8)
+#endif
+
#include "../../juce_AudioFilterBase.h"
+
+#ifdef _MSC_VER
+ #pragma pack (pop)
+#endif
+
#undef MemoryBlock
class JuceVSTWrapper;
@@ -349,7 +358,7 @@ public:
isSynth ((JucePlugin_IsSynth) != 0);
noTail ((JucePlugin_SilenceInProducesSilenceOut) != 0);
- setInitialDelay (JucePlugin_Latency);
+ setInitialDelay (filter->getLatencySamples());
programsAreChunks (true);
activePlugins.add (this);
@@ -669,6 +678,8 @@ public:
filter->prepareToPlay (rate, blockSize);
midiEvents.clear();
+ setInitialDelay (filter->getLatencySamples());
+
AudioEffectX::resume();
#if JucePlugin_ProducesMidiOutput
diff --git a/extras/audio plugins/wrapper/juce_AudioFilterBase.cpp b/extras/audio plugins/wrapper/juce_AudioFilterBase.cpp
index 1fdc87a02a..f076088a8c 100644
--- a/extras/audio plugins/wrapper/juce_AudioFilterBase.cpp
+++ b/extras/audio plugins/wrapper/juce_AudioFilterBase.cpp
@@ -40,6 +40,7 @@ AudioFilterBase::AudioFilterBase()
blockSize (0),
numInputChannels (0),
numOutputChannels (0),
+ latencySamples (0),
suspended (false)
{
}
@@ -71,6 +72,15 @@ void AudioFilterBase::setPlayConfigDetails (const int numIns,
blockSize = blockSize_;
}
+void JUCE_CALLTYPE AudioFilterBase::setLatencySamples (const int newLatency)
+{
+ if (latencySamples != newLatency)
+ {
+ latencySamples = newLatency;
+ updateHostDisplay();
+ }
+}
+
void AudioFilterBase::setParameterNotifyingHost (const int parameterIndex,
const float newValue)
{
diff --git a/extras/audio plugins/wrapper/juce_AudioFilterBase.h b/extras/audio plugins/wrapper/juce_AudioFilterBase.h
index 1a6b099633..6bb89f5f20 100644
--- a/extras/audio plugins/wrapper/juce_AudioFilterBase.h
+++ b/extras/audio plugins/wrapper/juce_AudioFilterBase.h
@@ -32,10 +32,6 @@
#ifndef __JUCE_AUDIOFILTERBASE_JUCEHEADER__
#define __JUCE_AUDIOFILTERBASE_JUCEHEADER__
-#ifdef _MSC_VER
- #pragma pack (push, 8)
-#endif
-
#include "../../../juce.h"
#include "juce_AudioFilterEditor.h"
#undef MemoryBlock
@@ -274,6 +270,21 @@ public:
/** Returns true if the specified channel is part of a stereo pair with its neighbour. */
virtual bool JUCE_CALLTYPE isOutputChannelStereoPair (int index) const = 0;
+ /** This returns the number of samples delay that the filter imposes on the audio
+ passing through it.
+
+ The host will call this to find the latency - the filter itself should set this value
+ by calling setLatencySamples() as soon as it can during its initialisation.
+ */
+ int JUCE_CALLTYPE getLatencySamples() const throw() { return latencySamples; }
+
+ /** The filter should call this to set the number of samples delay that it introduces.
+
+ The filter should call this as soon as it can during initialisation, and can call it
+ later if the value changes.
+ */
+ void JUCE_CALLTYPE setLatencySamples (const int newLatency);
+
//==============================================================================
/** This returns a critical section that will automatically be locked while the host
is calling the processBlock() method.
@@ -586,7 +597,7 @@ protected:
private:
AudioFilterEditor* activeEditor;
double sampleRate;
- int blockSize, numInputChannels, numOutputChannels;
+ int blockSize, numInputChannels, numOutputChannels, latencySamples;
bool suspended;
CriticalSection callbackLock;
@@ -601,9 +612,5 @@ private:
*/
extern AudioFilterBase* JUCE_CALLTYPE createPluginFilter();
-#ifdef _MSC_VER
- #pragma pack (pop)
-#endif
-
#endif // __JUCE_AUDIOFILTERBASE_JUCEHEADER__
diff --git a/extras/audio plugins/wrapper/juce_AudioFilterEditor.h b/extras/audio plugins/wrapper/juce_AudioFilterEditor.h
index 843cc280b6..d5f685c554 100644
--- a/extras/audio plugins/wrapper/juce_AudioFilterEditor.h
+++ b/extras/audio plugins/wrapper/juce_AudioFilterEditor.h
@@ -32,10 +32,6 @@
#ifndef __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__
#define __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__
-#ifdef _MSC_VER
- #pragma pack (push, 8)
-#endif
-
#include "../../../juce.h"
class AudioFilterBase;
@@ -72,8 +68,5 @@ private:
AudioFilterBase* const ownerFilter;
};
-#ifdef _MSC_VER
- #pragma pack (pop)
-#endif
#endif // __JUCE_AUDIOFILTEREDITOR_JUCEHEADER__
diff --git a/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h b/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h
index 34779ca0d9..fc67d8ec97 100644
--- a/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h
+++ b/extras/audio plugins/wrapper/juce_IncludeCharacteristics.h
@@ -79,8 +79,8 @@
#error "You need to define the JucePlugin_PreferredChannelConfigurations value in your JucePluginCharacteristics.h file!"
#endif
-#ifndef JucePlugin_Latency
- #error "You need to define the JucePlugin_Latency value in your JucePluginCharacteristics.h file!"
+#ifdef JucePlugin_Latency
+ #error "JucePlugin_Latency is now deprecated - instead, call the AudioFilterBase::setLatencySamples() method if your plugin has a non-zero delay"
#endif
#ifndef JucePlugin_SilenceInProducesSilenceOut
diff --git a/extras/juce demo/src/MainDemoWindow.cpp b/extras/juce demo/src/MainDemoWindow.cpp
index e87c898430..133098d12f 100644
--- a/extras/juce demo/src/MainDemoWindow.cpp
+++ b/extras/juce demo/src/MainDemoWindow.cpp
@@ -1,605 +1,605 @@
-/*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-7 by Raw Material Software ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the
- GNU General Public License, as published by the Free Software Foundation;
- either version 2 of the License, or (at your option) any later version.
-
- 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.
-
- You should have received a copy of the GNU General Public License
- along with JUCE; if not, visit www.gnu.org/licenses or write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ------------------------------------------------------------------------------
-
- If you'd like to release a closed-source product which uses JUCE, commercial
- licenses are also available: visit www.rawmaterialsoftware.com/juce for
- more information.
-
- ==============================================================================
-*/
-
-#include "jucedemo_headers.h"
-#include "MainDemoWindow.h"
-
-
-//==============================================================================
-class SourceCodeWindow;
-static SourceCodeWindow* sourceWindow = 0;
-
-
-//==============================================================================
-class SourceCodeWindow : public DialogWindow
-{
- TextEditor* textBox;
-
-public:
- SourceCodeWindow()
- : DialogWindow (T("JUCE Demo Source Code!"),
- Colours::floralwhite,
- false)
- {
- setContentComponent (textBox = new TextEditor());
-
- textBox->setColour (TextEditor::backgroundColourId, Colours::white);
- textBox->setMultiLine (true, false);
- textBox->setReturnKeyStartsNewLine (true);
-
- setResizable (true, true); // we'll choose a corner-resizer component for this window,
- // as a contrast to the resizable border on the main window
- }
-
- ~SourceCodeWindow()
- {
- // the text editor gets deleted automatically because it's the
- // window's content component.
-
- sourceWindow = 0;
- }
-
- void closeButtonPressed()
- {
- delete this;
- }
-
- void updateSourceCode (const String& text)
- {
- Font font (14.0f);
- font.setTypefaceName (Font::getDefaultMonospacedFontName());
- textBox->setFont (font);
-
- textBox->setText (text);
-
- toFront (true);
- }
-};
-
-//==============================================================================
-class ContentComp : public Component,
- public MenuBarModel,
- public ApplicationCommandTarget
-{
- //==============================================================================
- MainDemoWindow* mainWindow;
-
- OldSchoolLookAndFeel oldLookAndFeel;
-
- Component* currentDemo;
- int currentDemoId;
- const char* demoSourceCodeText;
-
- TooltipWindow tooltipWindow; // to add tooltips to an application, you
- // just need to create one of these and leave it
- // there to do its work..
-
- enum CommandIDs
- {
- showPathsAndTransforms = 0x2000,
- showFontsAndText = 0x2001,
- showWidgets = 0x2002,
- showThreading = 0x2003,
- showTreeView = 0x2004,
- showAudio = 0x2005,
- showDragAndDrop = 0x2006,
- showOpenGL = 0x2007,
- showQuicktime = 0x2008,
- showInterprocessComms = 0x2009,
- showTable = 0x2010,
-
- showSourceCode = 0x200a,
-
- setDefaultLookAndFeel = 0x200b,
- setOldSchoolLookAndFeel = 0x200c,
- useNativeTitleBar = 0x200d,
- useNativeMenus = 0x200e
- };
-
-public:
- //==============================================================================
- ContentComp (MainDemoWindow* mainWindow_)
- : mainWindow (mainWindow_),
- currentDemo (0),
- currentDemoId (0),
- demoSourceCodeText (0)
- {
- invokeDirectly (showWidgets, true);
- }
-
- ~ContentComp()
- {
- // (need to do this because the old school look-and-feel object is one of our members,
- // so will be deleted with us, and would leave a dangling pointer if it's selected)
- LookAndFeel::setDefaultLookAndFeel (0);
-
- deleteAllChildren();
-
- deleteAndZero (sourceWindow);
- }
-
- //==============================================================================
- void resized()
- {
- if (currentDemo != 0)
- currentDemo->setBounds (0, 0, getWidth(), getHeight());
- }
-
- //==============================================================================
- void showDemo (Component* demoComp, const char* sourceCodeText)
- {
- delete currentDemo;
- currentDemo = demoComp;
-
- addAndMakeVisible (currentDemo);
- resized();
-
- demoSourceCodeText = sourceCodeText;
- }
-
- void showSource()
- {
- if (sourceWindow == 0)
- {
- sourceWindow = new SourceCodeWindow();
- sourceWindow->centreAroundComponent (this, 750, 600);
- sourceWindow->setVisible (true);
- }
-
- sourceWindow->updateSourceCode (demoSourceCodeText);
- }
-
- //==============================================================================
- const StringArray getMenuBarNames()
- {
- const tchar* const names[] = { T("Demo"), T("Source Code"), T("Look-and-feel"), 0 };
-
- return StringArray ((const tchar**) names);
- }
-
- const PopupMenu getMenuForIndex (int menuIndex,
- const String& menuName)
- {
- ApplicationCommandManager* const commandManager = mainWindow->commandManager;
-
- PopupMenu menu;
-
- if (menuIndex == 0)
- {
- menu.addCommandItem (commandManager, showPathsAndTransforms);
- menu.addCommandItem (commandManager, showFontsAndText);
- menu.addCommandItem (commandManager, showWidgets);
- menu.addCommandItem (commandManager, showThreading);
- menu.addCommandItem (commandManager, showTreeView);
- menu.addCommandItem (commandManager, showTable);
- menu.addCommandItem (commandManager, showAudio);
- menu.addCommandItem (commandManager, showDragAndDrop);
- menu.addCommandItem (commandManager, showOpenGL);
- menu.addCommandItem (commandManager, showQuicktime);
- menu.addCommandItem (commandManager, showInterprocessComms);
-
- menu.addSeparator();
- menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
- }
- else if (menuIndex == 1)
- {
- menu.addCommandItem (commandManager, showSourceCode);
- }
- else if (menuIndex == 2)
- {
- menu.addCommandItem (commandManager, setDefaultLookAndFeel);
- menu.addCommandItem (commandManager, setOldSchoolLookAndFeel);
- menu.addSeparator();
- menu.addCommandItem (commandManager, useNativeTitleBar);
-
-#if JUCE_MAC
- menu.addCommandItem (commandManager, useNativeMenus);
-#endif
- }
-
- return menu;
- }
-
- void menuItemSelected (int menuItemID,
- int topLevelMenuIndex)
- {
- // all our menu items are invoked automatically as commands, so no need to do
- // anything in this callback
- }
-
- //==============================================================================
- // The following methods implement the ApplicationCommandTarget interface, allowing
- // this window to publish a set of actions it can perform, and which can be mapped
- // onto menus, keypresses, etc.
-
- ApplicationCommandTarget* getNextCommandTarget()
- {
- // this will return the next parent component that is an ApplicationCommandTarget (in this
- // case, there probably isn't one, but it's best to use this method in your own apps).
- return findFirstTargetParentComponent();
- }
-
- void getAllCommands (Array & commands)
- {
- // this returns the set of all commands that this target can perform..
- const CommandID ids[] = { showPathsAndTransforms,
- showFontsAndText,
- showWidgets,
- showThreading,
- showTreeView,
- showTable,
- showAudio,
- showDragAndDrop,
- showOpenGL,
- showQuicktime,
- showInterprocessComms,
- showSourceCode,
- setDefaultLookAndFeel,
- setOldSchoolLookAndFeel,
- useNativeTitleBar
-#if JUCE_MAC
- , useNativeMenus
-#endif
- };
-
- commands.addArray (ids, numElementsInArray (ids));
- }
-
- // This method is used when something needs to find out the details about one of the commands
- // that this object can perform..
- void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
- {
- const String generalCategory (T("General"));
- const String demosCategory (T("Demos"));
-
- switch (commandID)
- {
- case showPathsAndTransforms:
- result.setInfo (T("Paths and Transforms"), T("Shows the paths & transforms demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showPathsAndTransforms);
- result.addDefaultKeypress (T('1'), ModifierKeys::commandModifier);
- break;
-
- case showFontsAndText:
- result.setInfo (T("Fonts and Text"), T("Shows the fonts & text demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showFontsAndText);
- result.addDefaultKeypress (T('2'), ModifierKeys::commandModifier);
- break;
-
- case showWidgets:
- result.setInfo (T("Widgets"), T("Shows the widgets demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showWidgets);
- result.addDefaultKeypress (T('3'), ModifierKeys::commandModifier);
- break;
-
- case showThreading:
- result.setInfo (T("Multithreading"), T("Shows the threading demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showThreading);
- result.addDefaultKeypress (T('4'), ModifierKeys::commandModifier);
- break;
-
- case showTreeView:
- result.setInfo (T("Treeviews"), T("Shows the treeviews demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showTreeView);
- result.addDefaultKeypress (T('5'), ModifierKeys::commandModifier);
- break;
-
- case showTable:
- result.setInfo (T("Table Components"), T("Shows the table component demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showTable);
- result.addDefaultKeypress (T('6'), ModifierKeys::commandModifier);
- break;
-
- case showAudio:
- result.setInfo (T("Audio"), T("Shows the audio demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showAudio);
- result.addDefaultKeypress (T('7'), ModifierKeys::commandModifier);
- break;
-
- case showDragAndDrop:
- result.setInfo (T("Drag-and-drop"), T("Shows the drag & drop demo"), demosCategory, 0);
- result.setTicked (currentDemoId == showDragAndDrop);
- result.addDefaultKeypress (T('8'), ModifierKeys::commandModifier);
- break;
-
- case showOpenGL:
- result.setInfo (T("OpenGL"), T("Shows the OpenGL demo"), demosCategory, 0);
- result.addDefaultKeypress (T('9'), ModifierKeys::commandModifier);
- result.setTicked (currentDemoId == showOpenGL);
-#ifndef JUCE_OPENGL
- result.setActive (false);
-#endif
- break;
-
- case showQuicktime:
- result.setInfo (T("Quicktime"), T("Shows the Quicktime demo"), demosCategory, 0);
- result.addDefaultKeypress (T('b'), ModifierKeys::commandModifier);
- result.setTicked (currentDemoId == showQuicktime);
-#if ! (JUCE_QUICKTIME && ! JUCE_LINUX)
- result.setActive (false);
-#endif
- break;
-
- case showInterprocessComms:
- result.setInfo (T("Interprocess Comms"), T("Shows the interprocess communications demo"), demosCategory, 0);
- result.addDefaultKeypress (T('0'), ModifierKeys::commandModifier);
- result.setTicked (currentDemoId == showInterprocessComms);
- break;
-
- case showSourceCode:
- result.setInfo (T("Show the source code for this demo"), T("Opens a window containing this demo's source code"), generalCategory, 0);
- result.addDefaultKeypress (T('s'), ModifierKeys::commandModifier);
- break;
-
- case setDefaultLookAndFeel:
- result.setInfo (T("Use default look-and-feel"), String::empty, generalCategory, 0);
- result.setTicked ((typeid (LookAndFeel) == typeid (getLookAndFeel())) != 0);
- break;
-
- case setOldSchoolLookAndFeel:
- result.setInfo (T("Use the old, original juce look-and-feel"), String::empty, generalCategory, 0);
- result.setTicked ((typeid (OldSchoolLookAndFeel) == typeid (getLookAndFeel())) != 0);
- break;
-
- case useNativeTitleBar:
- result.setInfo (T("Use native window title bar"), String::empty, generalCategory, 0);
- result.setTicked (mainWindow->isUsingNativeTitleBar());
- break;
-
-#if JUCE_MAC
- case useNativeMenus:
- result.setInfo (T("Use the native OSX menu bar"), String::empty, generalCategory, 0);
- result.setTicked (MenuBarModel::getMacMainMenu() != 0);
- break;
-#endif
-
- default:
- break;
- };
- }
-
- // this is the ApplicationCommandTarget method that is used to actually perform one of our commands..
- bool perform (const InvocationInfo& info)
- {
- switch (info.commandID)
- {
- case showPathsAndTransforms:
- showDemo (createPathsAndTransformsDemo(), BinaryData::pathsandtransformsdemo_cpp);
- currentDemoId = showPathsAndTransforms;
- break;
-
- case showFontsAndText:
- showDemo (createFontsAndTextDemo(), BinaryData::fontsandtextdemo_cpp);
- currentDemoId = showFontsAndText;
- break;
-
- case showWidgets:
- showDemo (createWidgetsDemo (mainWindow->commandManager), BinaryData::widgetsdemo_cpp);
- currentDemoId = showWidgets;
- break;
-
- case showThreading:
- showDemo (createThreadingDemo(), BinaryData::threadingdemo_cpp);
- currentDemoId = showThreading;
- break;
-
- case showTreeView:
- showDemo (createTreeViewDemo(), BinaryData::treeviewdemo_cpp);
- currentDemoId = showTreeView;
- break;
-
- case showTable:
- showDemo (createTableDemo(), BinaryData::tabledemo_cpp);
- currentDemoId = showTable;
- break;
-
- case showAudio:
- showDemo (createAudioDemo(), BinaryData::audiodemo_cpp);
- currentDemoId = showAudio;
- break;
-
- case showDragAndDrop:
- showDemo (createDragAndDropDemo(), BinaryData::draganddropdemo_cpp);
- currentDemoId = showDragAndDrop;
- break;
-
- case showOpenGL:
-#if JUCE_OPENGL
- showDemo (createOpenGLDemo(), BinaryData::opengldemo_cpp);
- currentDemoId = showOpenGL;
-#endif
- break;
-
- case showQuicktime:
-#if JUCE_QUICKTIME && ! JUCE_LINUX
- showDemo (createQuickTimeDemo(), BinaryData::quicktimedemo_cpp);
- currentDemoId = showQuicktime;
-#endif
- break;
-
- case showInterprocessComms:
- showDemo (createInterprocessCommsDemo(), BinaryData::interprocesscommsdemo_cpp);
- currentDemoId = showInterprocessComms;
- break;
-
- case showSourceCode:
- showSource();
- break;
-
- case setDefaultLookAndFeel:
- LookAndFeel::setDefaultLookAndFeel (0);
- break;
-
- case setOldSchoolLookAndFeel:
- LookAndFeel::setDefaultLookAndFeel (&oldLookAndFeel);
- break;
-
- case useNativeTitleBar:
- mainWindow->setUsingNativeTitleBar (! mainWindow->isUsingNativeTitleBar());
- break;
-
-#if JUCE_MAC
- case useNativeMenus:
- if (MenuBarModel::getMacMainMenu() != 0)
- {
- MenuBarModel::setMacMainMenu (0);
- mainWindow->setMenuBar ((ContentComp*) mainWindow->getContentComponent());
- }
- else
- {
- MenuBarModel::setMacMainMenu ((ContentComp*) mainWindow->getContentComponent());
- mainWindow->setMenuBar (0);
- }
-
- break;
-#endif
-
- default:
- return false;
- };
-
- return true;
- }
-
- juce_UseDebuggingNewOperator
-};
-
-//==============================================================================
-#if JUCE_WIN32 || JUCE_LINUX
-
-// Just add a simple icon to the Window system tray area..
-class DemoTaskbarComponent : public SystemTrayIconComponent
-{
-public:
- DemoTaskbarComponent()
- {
- // Create an icon which is just a square with a "j" in it..
- Image icon (Image::RGB, 32, 32, true);
- Graphics g (icon);
- g.fillAll (Colours::lightblue);
- g.setColour (Colours::black);
- g.setFont ((float) icon.getHeight(), Font::bold);
- g.drawText (T("j"), 0, 0, icon.getWidth(), icon.getHeight(), Justification::centred, false);
-
- setIconImage (icon);
-
- setIconTooltip (T("Juce Demo App!"));
- }
-
- ~DemoTaskbarComponent()
- {
- }
-
- void mouseDown (const MouseEvent& e)
- {
- PopupMenu m;
- m.addItem (1, T("Quit the Juce demo"));
-
- const int result = m.show();
-
- if (result == 1)
- JUCEApplication::getInstance()->systemRequestedQuit();
- }
-};
-
-#endif
-
-//==============================================================================
-MainDemoWindow::MainDemoWindow()
- : DocumentWindow (T("JUCE Demo!"),
- Colours::azure,
- DocumentWindow::allButtons,
- true)
-{
- commandManager = new ApplicationCommandManager();
-
- setResizable (true, false); // resizability is a property of ResizableWindow
-
- ContentComp* contentComp = new ContentComp (this);
-
- commandManager->registerAllCommandsForTarget (contentComp);
- commandManager->registerAllCommandsForTarget (JUCEApplication::getInstance());
-
- // this lets the command manager use keypresses that arrive in our window to send
- // out commands
- addKeyListener (commandManager->getKeyMappings());
-
- // sets the main content component for the window to be this tabbed
- // panel. This will be deleted when the window is deleted.
- setContentComponent (contentComp);
-
- // this tells the DocumentWindow to automatically create and manage a MenuBarComponent
- // which uses our contentComp as its MenuBarModel
- setMenuBar (contentComp);
-
- // tells our menu bar model that it should watch this command manager for
- // changes, and send change messages accordingly.
- contentComp->setApplicationCommandManagerToWatch (commandManager);
-
- setVisible (true);
-
-#if JUCE_WIN32 || JUCE_LINUX
- taskbarIcon = new DemoTaskbarComponent();
-#endif
-}
-
-MainDemoWindow::~MainDemoWindow()
-{
-#if JUCE_WIN32 || JUCE_LINUX
- deleteAndZero (taskbarIcon);
-#endif
-
- // because we've set the content comp to be used as our menu bar model, we
- // have to switch this off before deleting the content comp..
- setMenuBar (0);
-
- // setting our content component to 0 will delete the current one, and
- // that will in turn delete all its child components. You don't always
- // have to do this explicitly, because the base class's destructor will
- // also delete the content component, but in this case we need to
- // make sure our content comp has gone away before deleting our command
- // manager.
- setContentComponent (0, true);
-
- delete commandManager;
-}
-
-void MainDemoWindow::closeButtonPressed()
-{
- // The correct thing to do when you want the app to quit is to call the
- // JUCEApplication::systemRequestedQuit() method.
-
- // That means that requests to quit that come from your own UI, or from other
- // OS-specific sources (e.g. the dock menu on the mac) all get handled in the
- // same way.
-
- JUCEApplication::getInstance()->systemRequestedQuit();
-}
+/*
+ ==============================================================================
+
+ This file is part of the JUCE library - "Jules' Utility Class Extensions"
+ Copyright 2004-7 by Raw Material Software ltd.
+
+ ------------------------------------------------------------------------------
+
+ JUCE can be redistributed and/or modified under the terms of the
+ GNU General Public License, as published by the Free Software Foundation;
+ either version 2 of the License, or (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with JUCE; if not, visit www.gnu.org/licenses or write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ Boston, MA 02111-1307 USA
+
+ ------------------------------------------------------------------------------
+
+ If you'd like to release a closed-source product which uses JUCE, commercial
+ licenses are also available: visit www.rawmaterialsoftware.com/juce for
+ more information.
+
+ ==============================================================================
+*/
+
+#include "jucedemo_headers.h"
+#include "MainDemoWindow.h"
+
+
+//==============================================================================
+class SourceCodeWindow;
+static SourceCodeWindow* sourceWindow = 0;
+
+
+//==============================================================================
+class SourceCodeWindow : public DialogWindow
+{
+ TextEditor* textBox;
+
+public:
+ SourceCodeWindow()
+ : DialogWindow (T("JUCE Demo Source Code!"),
+ Colours::floralwhite,
+ false)
+ {
+ setContentComponent (textBox = new TextEditor());
+
+ textBox->setColour (TextEditor::backgroundColourId, Colours::white);
+ textBox->setMultiLine (true, false);
+ textBox->setReturnKeyStartsNewLine (true);
+
+ setResizable (true, true); // we'll choose a corner-resizer component for this window,
+ // as a contrast to the resizable border on the main window
+ }
+
+ ~SourceCodeWindow()
+ {
+ // the text editor gets deleted automatically because it's the
+ // window's content component.
+
+ sourceWindow = 0;
+ }
+
+ void closeButtonPressed()
+ {
+ delete this;
+ }
+
+ void updateSourceCode (const String& text)
+ {
+ Font font (14.0f);
+ font.setTypefaceName (Font::getDefaultMonospacedFontName());
+ textBox->setFont (font);
+
+ textBox->setText (text);
+
+ toFront (true);
+ }
+};
+
+//==============================================================================
+class ContentComp : public Component,
+ public MenuBarModel,
+ public ApplicationCommandTarget
+{
+ //==============================================================================
+ MainDemoWindow* mainWindow;
+
+ OldSchoolLookAndFeel oldLookAndFeel;
+
+ Component* currentDemo;
+ int currentDemoId;
+ const char* demoSourceCodeText;
+
+ TooltipWindow tooltipWindow; // to add tooltips to an application, you
+ // just need to create one of these and leave it
+ // there to do its work..
+
+ enum CommandIDs
+ {
+ showPathsAndTransforms = 0x2000,
+ showFontsAndText = 0x2001,
+ showWidgets = 0x2002,
+ showThreading = 0x2003,
+ showTreeView = 0x2004,
+ showAudio = 0x2005,
+ showDragAndDrop = 0x2006,
+ showOpenGL = 0x2007,
+ showQuicktime = 0x2008,
+ showInterprocessComms = 0x2009,
+ showTable = 0x2010,
+
+ showSourceCode = 0x200a,
+
+ setDefaultLookAndFeel = 0x200b,
+ setOldSchoolLookAndFeel = 0x200c,
+ useNativeTitleBar = 0x200d,
+ useNativeMenus = 0x200e
+ };
+
+public:
+ //==============================================================================
+ ContentComp (MainDemoWindow* mainWindow_)
+ : mainWindow (mainWindow_),
+ currentDemo (0),
+ currentDemoId (0),
+ demoSourceCodeText (0)
+ {
+ invokeDirectly (showWidgets, true);
+ }
+
+ ~ContentComp()
+ {
+ // (need to do this because the old school look-and-feel object is one of our members,
+ // so will be deleted with us, and would leave a dangling pointer if it's selected)
+ LookAndFeel::setDefaultLookAndFeel (0);
+
+ deleteAllChildren();
+
+ deleteAndZero (sourceWindow);
+ }
+
+ //==============================================================================
+ void resized()
+ {
+ if (currentDemo != 0)
+ currentDemo->setBounds (0, 0, getWidth(), getHeight());
+ }
+
+ //==============================================================================
+ void showDemo (Component* demoComp, const char* sourceCodeText)
+ {
+ delete currentDemo;
+ currentDemo = demoComp;
+
+ addAndMakeVisible (currentDemo);
+ resized();
+
+ demoSourceCodeText = sourceCodeText;
+ }
+
+ void showSource()
+ {
+ if (sourceWindow == 0)
+ {
+ sourceWindow = new SourceCodeWindow();
+ sourceWindow->centreAroundComponent (this, 750, 600);
+ sourceWindow->setVisible (true);
+ }
+
+ sourceWindow->updateSourceCode (demoSourceCodeText);
+ }
+
+ //==============================================================================
+ const StringArray getMenuBarNames()
+ {
+ const tchar* const names[] = { T("Demo"), T("Source Code"), T("Look-and-feel"), 0 };
+
+ return StringArray ((const tchar**) names);
+ }
+
+ const PopupMenu getMenuForIndex (int menuIndex,
+ const String& menuName)
+ {
+ ApplicationCommandManager* const commandManager = mainWindow->commandManager;
+
+ PopupMenu menu;
+
+ if (menuIndex == 0)
+ {
+ menu.addCommandItem (commandManager, showPathsAndTransforms);
+ menu.addCommandItem (commandManager, showFontsAndText);
+ menu.addCommandItem (commandManager, showWidgets);
+ menu.addCommandItem (commandManager, showThreading);
+ menu.addCommandItem (commandManager, showTreeView);
+ menu.addCommandItem (commandManager, showTable);
+ menu.addCommandItem (commandManager, showAudio);
+ menu.addCommandItem (commandManager, showDragAndDrop);
+ menu.addCommandItem (commandManager, showOpenGL);
+ menu.addCommandItem (commandManager, showQuicktime);
+ menu.addCommandItem (commandManager, showInterprocessComms);
+
+ menu.addSeparator();
+ menu.addCommandItem (commandManager, StandardApplicationCommandIDs::quit);
+ }
+ else if (menuIndex == 1)
+ {
+ menu.addCommandItem (commandManager, showSourceCode);
+ }
+ else if (menuIndex == 2)
+ {
+ menu.addCommandItem (commandManager, setDefaultLookAndFeel);
+ menu.addCommandItem (commandManager, setOldSchoolLookAndFeel);
+ menu.addSeparator();
+ menu.addCommandItem (commandManager, useNativeTitleBar);
+
+#if JUCE_MAC
+ menu.addCommandItem (commandManager, useNativeMenus);
+#endif
+ }
+
+ return menu;
+ }
+
+ void menuItemSelected (int menuItemID,
+ int topLevelMenuIndex)
+ {
+ // all our menu items are invoked automatically as commands, so no need to do
+ // anything in this callback
+ }
+
+ //==============================================================================
+ // The following methods implement the ApplicationCommandTarget interface, allowing
+ // this window to publish a set of actions it can perform, and which can be mapped
+ // onto menus, keypresses, etc.
+
+ ApplicationCommandTarget* getNextCommandTarget()
+ {
+ // this will return the next parent component that is an ApplicationCommandTarget (in this
+ // case, there probably isn't one, but it's best to use this method in your own apps).
+ return findFirstTargetParentComponent();
+ }
+
+ void getAllCommands (Array & commands)
+ {
+ // this returns the set of all commands that this target can perform..
+ const CommandID ids[] = { showPathsAndTransforms,
+ showFontsAndText,
+ showWidgets,
+ showThreading,
+ showTreeView,
+ showTable,
+ showAudio,
+ showDragAndDrop,
+ showOpenGL,
+ showQuicktime,
+ showInterprocessComms,
+ showSourceCode,
+ setDefaultLookAndFeel,
+ setOldSchoolLookAndFeel,
+ useNativeTitleBar
+#if JUCE_MAC
+ , useNativeMenus
+#endif
+ };
+
+ commands.addArray (ids, numElementsInArray (ids));
+ }
+
+ // This method is used when something needs to find out the details about one of the commands
+ // that this object can perform..
+ void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result)
+ {
+ const String generalCategory (T("General"));
+ const String demosCategory (T("Demos"));
+
+ switch (commandID)
+ {
+ case showPathsAndTransforms:
+ result.setInfo (T("Paths and Transforms"), T("Shows the paths & transforms demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showPathsAndTransforms);
+ result.addDefaultKeypress (T('1'), ModifierKeys::commandModifier);
+ break;
+
+ case showFontsAndText:
+ result.setInfo (T("Fonts and Text"), T("Shows the fonts & text demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showFontsAndText);
+ result.addDefaultKeypress (T('2'), ModifierKeys::commandModifier);
+ break;
+
+ case showWidgets:
+ result.setInfo (T("Widgets"), T("Shows the widgets demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showWidgets);
+ result.addDefaultKeypress (T('3'), ModifierKeys::commandModifier);
+ break;
+
+ case showThreading:
+ result.setInfo (T("Multithreading"), T("Shows the threading demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showThreading);
+ result.addDefaultKeypress (T('4'), ModifierKeys::commandModifier);
+ break;
+
+ case showTreeView:
+ result.setInfo (T("Treeviews"), T("Shows the treeviews demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showTreeView);
+ result.addDefaultKeypress (T('5'), ModifierKeys::commandModifier);
+ break;
+
+ case showTable:
+ result.setInfo (T("Table Components"), T("Shows the table component demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showTable);
+ result.addDefaultKeypress (T('6'), ModifierKeys::commandModifier);
+ break;
+
+ case showAudio:
+ result.setInfo (T("Audio"), T("Shows the audio demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showAudio);
+ result.addDefaultKeypress (T('7'), ModifierKeys::commandModifier);
+ break;
+
+ case showDragAndDrop:
+ result.setInfo (T("Drag-and-drop"), T("Shows the drag & drop demo"), demosCategory, 0);
+ result.setTicked (currentDemoId == showDragAndDrop);
+ result.addDefaultKeypress (T('8'), ModifierKeys::commandModifier);
+ break;
+
+ case showOpenGL:
+ result.setInfo (T("OpenGL"), T("Shows the OpenGL demo"), demosCategory, 0);
+ result.addDefaultKeypress (T('9'), ModifierKeys::commandModifier);
+ result.setTicked (currentDemoId == showOpenGL);
+#ifndef JUCE_OPENGL
+ result.setActive (false);
+#endif
+ break;
+
+ case showQuicktime:
+ result.setInfo (T("Quicktime"), T("Shows the Quicktime demo"), demosCategory, 0);
+ result.addDefaultKeypress (T('b'), ModifierKeys::commandModifier);
+ result.setTicked (currentDemoId == showQuicktime);
+#if ! (JUCE_QUICKTIME && ! JUCE_LINUX)
+ result.setActive (false);
+#endif
+ break;
+
+ case showInterprocessComms:
+ result.setInfo (T("Interprocess Comms"), T("Shows the interprocess communications demo"), demosCategory, 0);
+ result.addDefaultKeypress (T('0'), ModifierKeys::commandModifier);
+ result.setTicked (currentDemoId == showInterprocessComms);
+ break;
+
+ case showSourceCode:
+ result.setInfo (T("Show the source code for this demo"), T("Opens a window containing this demo's source code"), generalCategory, 0);
+ result.addDefaultKeypress (T('s'), ModifierKeys::commandModifier);
+ break;
+
+ case setDefaultLookAndFeel:
+ result.setInfo (T("Use default look-and-feel"), String::empty, generalCategory, 0);
+ result.setTicked ((typeid (LookAndFeel) == typeid (getLookAndFeel())) != 0);
+ break;
+
+ case setOldSchoolLookAndFeel:
+ result.setInfo (T("Use the old, original juce look-and-feel"), String::empty, generalCategory, 0);
+ result.setTicked ((typeid (OldSchoolLookAndFeel) == typeid (getLookAndFeel())) != 0);
+ break;
+
+ case useNativeTitleBar:
+ result.setInfo (T("Use native window title bar"), String::empty, generalCategory, 0);
+ result.setTicked (mainWindow->isUsingNativeTitleBar());
+ break;
+
+#if JUCE_MAC
+ case useNativeMenus:
+ result.setInfo (T("Use the native OSX menu bar"), String::empty, generalCategory, 0);
+ result.setTicked (MenuBarModel::getMacMainMenu() != 0);
+ break;
+#endif
+
+ default:
+ break;
+ };
+ }
+
+ // this is the ApplicationCommandTarget method that is used to actually perform one of our commands..
+ bool perform (const InvocationInfo& info)
+ {
+ switch (info.commandID)
+ {
+ case showPathsAndTransforms:
+ showDemo (createPathsAndTransformsDemo(), BinaryData::pathsandtransformsdemo_cpp);
+ currentDemoId = showPathsAndTransforms;
+ break;
+
+ case showFontsAndText:
+ showDemo (createFontsAndTextDemo(), BinaryData::fontsandtextdemo_cpp);
+ currentDemoId = showFontsAndText;
+ break;
+
+ case showWidgets:
+ showDemo (createWidgetsDemo (mainWindow->commandManager), BinaryData::widgetsdemo_cpp);
+ currentDemoId = showWidgets;
+ break;
+
+ case showThreading:
+ showDemo (createThreadingDemo(), BinaryData::threadingdemo_cpp);
+ currentDemoId = showThreading;
+ break;
+
+ case showTreeView:
+ showDemo (createTreeViewDemo(), BinaryData::treeviewdemo_cpp);
+ currentDemoId = showTreeView;
+ break;
+
+ case showTable:
+ showDemo (createTableDemo(), BinaryData::tabledemo_cpp);
+ currentDemoId = showTable;
+ break;
+
+ case showAudio:
+ showDemo (createAudioDemo(), BinaryData::audiodemo_cpp);
+ currentDemoId = showAudio;
+ break;
+
+ case showDragAndDrop:
+ showDemo (createDragAndDropDemo(), BinaryData::draganddropdemo_cpp);
+ currentDemoId = showDragAndDrop;
+ break;
+
+ case showOpenGL:
+#if JUCE_OPENGL
+ showDemo (createOpenGLDemo(), BinaryData::opengldemo_cpp);
+ currentDemoId = showOpenGL;
+#endif
+ break;
+
+ case showQuicktime:
+#if JUCE_QUICKTIME && ! JUCE_LINUX
+ showDemo (createQuickTimeDemo(), BinaryData::quicktimedemo_cpp);
+ currentDemoId = showQuicktime;
+#endif
+ break;
+
+ case showInterprocessComms:
+ showDemo (createInterprocessCommsDemo(), BinaryData::interprocesscommsdemo_cpp);
+ currentDemoId = showInterprocessComms;
+ break;
+
+ case showSourceCode:
+ showSource();
+ break;
+
+ case setDefaultLookAndFeel:
+ LookAndFeel::setDefaultLookAndFeel (0);
+ break;
+
+ case setOldSchoolLookAndFeel:
+ LookAndFeel::setDefaultLookAndFeel (&oldLookAndFeel);
+ break;
+
+ case useNativeTitleBar:
+ mainWindow->setUsingNativeTitleBar (! mainWindow->isUsingNativeTitleBar());
+ break;
+
+#if JUCE_MAC
+ case useNativeMenus:
+ if (MenuBarModel::getMacMainMenu() != 0)
+ {
+ MenuBarModel::setMacMainMenu (0);
+ mainWindow->setMenuBar ((ContentComp*) mainWindow->getContentComponent());
+ }
+ else
+ {
+ MenuBarModel::setMacMainMenu ((ContentComp*) mainWindow->getContentComponent());
+ mainWindow->setMenuBar (0);
+ }
+
+ break;
+#endif
+
+ default:
+ return false;
+ };
+
+ return true;
+ }
+
+ juce_UseDebuggingNewOperator
+};
+
+//==============================================================================
+#if JUCE_WIN32 || JUCE_LINUX
+
+// Just add a simple icon to the Window system tray area..
+class DemoTaskbarComponent : public SystemTrayIconComponent
+{
+public:
+ DemoTaskbarComponent()
+ {
+ // Create an icon which is just a square with a "j" in it..
+ Image icon (Image::RGB, 32, 32, true);
+ Graphics g (icon);
+ g.fillAll (Colours::lightblue);
+ g.setColour (Colours::black);
+ g.setFont ((float) icon.getHeight(), Font::bold);
+ g.drawText (T("j"), 0, 0, icon.getWidth(), icon.getHeight(), Justification::centred, false);
+
+ setIconImage (icon);
+
+ setIconTooltip (T("Juce Demo App!"));
+ }
+
+ ~DemoTaskbarComponent()
+ {
+ }
+
+ void mouseDown (const MouseEvent& e)
+ {
+ PopupMenu m;
+ m.addItem (1, T("Quit the Juce demo"));
+
+ const int result = m.show();
+
+ if (result == 1)
+ JUCEApplication::getInstance()->systemRequestedQuit();
+ }
+};
+
+#endif
+
+//==============================================================================
+MainDemoWindow::MainDemoWindow()
+ : DocumentWindow (T("JUCE Demo!"),
+ Colours::azure,
+ DocumentWindow::allButtons,
+ true)
+{
+ commandManager = new ApplicationCommandManager();
+
+ setResizable (true, false); // resizability is a property of ResizableWindow
+
+ ContentComp* contentComp = new ContentComp (this);
+
+ commandManager->registerAllCommandsForTarget (contentComp);
+ commandManager->registerAllCommandsForTarget (JUCEApplication::getInstance());
+
+ // this lets the command manager use keypresses that arrive in our window to send
+ // out commands
+ addKeyListener (commandManager->getKeyMappings());
+
+ // sets the main content component for the window to be this tabbed
+ // panel. This will be deleted when the window is deleted.
+ setContentComponent (contentComp);
+
+ // this tells the DocumentWindow to automatically create and manage a MenuBarComponent
+ // which uses our contentComp as its MenuBarModel
+ setMenuBar (contentComp);
+
+ // tells our menu bar model that it should watch this command manager for
+ // changes, and send change messages accordingly.
+ contentComp->setApplicationCommandManagerToWatch (commandManager);
+
+ setVisible (true);
+
+#if JUCE_WIN32 || JUCE_LINUX
+ taskbarIcon = new DemoTaskbarComponent();
+#endif
+}
+
+MainDemoWindow::~MainDemoWindow()
+{
+#if JUCE_WIN32 || JUCE_LINUX
+ deleteAndZero (taskbarIcon);
+#endif
+
+ // because we've set the content comp to be used as our menu bar model, we
+ // have to switch this off before deleting the content comp..
+ setMenuBar (0);
+
+ // setting our content component to 0 will delete the current one, and
+ // that will in turn delete all its child components. You don't always
+ // have to do this explicitly, because the base class's destructor will
+ // also delete the content component, but in this case we need to
+ // make sure our content comp has gone away before deleting our command
+ // manager.
+ setContentComponent (0, true);
+
+ delete commandManager;
+}
+
+void MainDemoWindow::closeButtonPressed()
+{
+ // The correct thing to do when you want the app to quit is to call the
+ // JUCEApplication::systemRequestedQuit() method.
+
+ // That means that requests to quit that come from your own UI, or from other
+ // OS-specific sources (e.g. the dock menu on the mac) all get handled in the
+ // same way.
+
+ JUCEApplication::getInstance()->systemRequestedQuit();
+}
diff --git a/src/juce_core/containers/juce_ReferenceCountedArray.h b/src/juce_core/containers/juce_ReferenceCountedArray.h
index 7b7a956a86..61d8a60275 100644
--- a/src/juce_core/containers/juce_ReferenceCountedArray.h
+++ b/src/juce_core/containers/juce_ReferenceCountedArray.h
@@ -46,9 +46,12 @@
and takes care of incrementing and decrementing their ref counts when they
are added and removed from the array.
+ To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
+ TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
+
@see Array, OwnedArray, StringArray
*/
-template
+template
class ReferenceCountedArray : private ArrayAllocationBase
{
public:
@@ -68,26 +71,32 @@ public:
}
/** Creates a copy of another array */
- ReferenceCountedArray (const ReferenceCountedArray& other) throw()
+ ReferenceCountedArray (const ReferenceCountedArray& other) throw()
: ArrayAllocationBase (other.granularity),
numUsed (other.numUsed)
{
+ other.lockArray();
this->setAllocatedSize (numUsed);
memcpy (this->elements, other.elements, numUsed * sizeof (ObjectClass*));
for (int i = numUsed; --i >= 0;)
if (this->elements[i] != 0)
this->elements[i]->incReferenceCount();
+
+ other.unlockArray();
}
/** Copies another array into this one.
Any existing objects in this array will first be released.
*/
- const ReferenceCountedArray& operator= (const ReferenceCountedArray& other) throw()
+ const ReferenceCountedArray& operator= (const ReferenceCountedArray& other) throw()
{
if (this != &other)
{
+ other.lockArray();
+ lock.enter();
+
clear();
this->granularity = other.granularity;
@@ -99,6 +108,9 @@ public:
for (int i = numUsed; --i >= 0;)
if (this->elements[i] != 0)
this->elements[i]->incReferenceCount();
+
+ lock.exit();
+ other.unlockArray();
}
return *this;
@@ -120,12 +132,16 @@ public:
*/
void clear()
{
+ lock.enter();
+
while (numUsed > 0)
if (this->elements [--numUsed] != 0)
this->elements [numUsed]->decReferenceCount();
jassert (numUsed == 0);
this->setAllocatedSize (0);
+
+ lock.exit();
}
/** Returns the current number of objects in the array. */
@@ -144,8 +160,10 @@ public:
*/
inline ObjectClass* operator[] (const int index) const throw()
{
+ lock.enter();
return (index >= 0 && index < numUsed) ? this->elements [index]
: (ObjectClass*) 0;
+ lock.exit();
}
/** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
@@ -155,8 +173,10 @@ public:
*/
inline ObjectClass* getUnchecked (const int index) const throw()
{
+ lock.enter();
jassert (index >= 0 && index < numUsed);
return this->elements [index];
+ lock.exit();
}
/** Returns a pointer to the first object in the array.
@@ -166,8 +186,12 @@ public:
*/
inline ObjectClass* getFirst() const throw()
{
- return (numUsed > 0) ? this->elements [0]
- : (ObjectClass*) 0;
+ lock.enter();
+ ObjectClass* const result = (numUsed > 0) ? this->elements [0]
+ : (ObjectClass*) 0;
+ lock.exit();
+
+ return result;
}
/** Returns a pointer to the last object in the array.
@@ -177,8 +201,12 @@ public:
*/
inline ObjectClass* getLast() const throw()
{
- return (numUsed > 0) ? this->elements [numUsed - 1]
- : (ObjectClass*) 0;
+ lock.enter();
+ ObjectClass* const result = (numUsed > 0) ? this->elements [numUsed - 1]
+ : (ObjectClass*) 0;
+ lock.exit();
+
+ return result;
}
//==============================================================================
@@ -189,17 +217,24 @@ public:
*/
int indexOf (const ObjectClass* const objectToLookFor) const throw()
{
+ int result = -1;
+
+ lock.enter();
ObjectClass** e = this->elements;
for (int i = numUsed; --i >= 0;)
{
if (objectToLookFor == *e)
- return (int) (e - this->elements);
+ {
+ result = (int) (e - this->elements);
+ break;
+ }
++e;
}
- return -1;
+ lock.exit();
+ return result;
}
/** Returns true if the array contains a specified object.
@@ -209,16 +244,21 @@ public:
*/
bool contains (const ObjectClass* const objectToLookFor) const throw()
{
+ lock.enter();
ObjectClass** e = this->elements;
for (int i = numUsed; --i >= 0;)
{
if (objectToLookFor == *e)
+ {
+ lock.exit();
return true;
+ }
++e;
}
+ lock.exit();
return false;
}
@@ -231,11 +271,14 @@ public:
*/
void add (ObjectClass* const newObject) throw()
{
+ lock.enter();
this->ensureAllocatedSize (numUsed + 1);
this->elements [numUsed++] = newObject;
if (newObject != 0)
newObject->incReferenceCount();
+
+ lock.exit();
}
/** Inserts a new object into the array at the given index.
@@ -256,6 +299,7 @@ public:
{
if (indexToInsertAt >= 0)
{
+ lock.enter();
if (indexToInsertAt > numUsed)
indexToInsertAt = numUsed;
@@ -273,6 +317,7 @@ public:
newObject->incReferenceCount();
++numUsed;
+ lock.exit();
}
else
{
@@ -289,8 +334,12 @@ public:
*/
void addIfNotAlreadyThere (ObjectClass* const newObject) throw()
{
+ lock.enter();
+
if (! contains (newObject))
add (newObject);
+
+ lock.exit();
}
/** Replaces an object in the array with a different one.
@@ -310,6 +359,8 @@ public:
{
if (indexToChange >= 0)
{
+ lock.enter();
+
if (newObject != 0)
newObject->incReferenceCount();
@@ -325,6 +376,8 @@ public:
this->ensureAllocatedSize (numUsed + 1);
this->elements [numUsed++] = newObject;
}
+
+ lock.exit();
}
}
@@ -337,10 +390,13 @@ public:
all available elements will be copied.
@see add
*/
- void addArray (const ReferenceCountedArray& arrayToAddFrom,
+ void addArray (const ReferenceCountedArray& arrayToAddFrom,
int startIndex = 0,
int numElementsToAdd = -1) throw()
{
+ arrayToAddFrom.lockArray();
+ lock.enter();
+
if (startIndex < 0)
{
jassertfalse
@@ -357,6 +413,9 @@ public:
while (--numElementsToAdd >= 0)
add (arrayToAddFrom.getUnchecked (startIndex++));
}
+
+ lock.exit();
+ arrayToAddFrom.unlockArray();
}
/** Inserts a new object into the array assuming that the array is sorted.
@@ -374,7 +433,9 @@ public:
void addSorted (ElementComparator& comparator,
ObjectClass* newObject) throw()
{
+ lock.enter();
insert (findInsertIndexInSortedArray (comparator, this->elements, newObject, 0, numUsed), newObject);
+ lock.exit();
}
//==============================================================================
@@ -393,6 +454,8 @@ public:
*/
void remove (const int indexToRemove)
{
+ lock.enter();
+
if (indexToRemove >= 0 && indexToRemove < numUsed)
{
ObjectClass** const e = this->elements + indexToRemove;
@@ -409,6 +472,8 @@ public:
if ((numUsed << 1) < this->numAllocated)
minimiseStorageOverheads();
}
+
+ lock.exit();
}
/** Removes the first occurrence of a specified object from the array.
@@ -421,7 +486,9 @@ public:
*/
void removeObject (ObjectClass* const objectToRemove)
{
+ lock.enter();
remove (indexOf (objectToRemove));
+ lock.exit();
}
/** Removes a range of objects from the array.
@@ -442,6 +509,8 @@ public:
void removeRange (const int startIndex,
const int numberToRemove)
{
+ lock.enter();
+
const int start = jlimit (0, numUsed, startIndex);
const int end = jlimit (0, numUsed, startIndex + numberToRemove);
@@ -471,6 +540,8 @@ public:
if ((numUsed << 1) < this->numAllocated)
minimiseStorageOverheads();
}
+
+ lock.exit();
}
/** Removes the last n objects from the array.
@@ -483,11 +554,15 @@ public:
*/
void removeLast (int howManyToRemove = 1)
{
+ lock.enter();
+
if (howManyToRemove > numUsed)
howManyToRemove = numUsed;
while (--howManyToRemove >= 0)
remove (numUsed - 1);
+
+ lock.exit();
}
/** Swaps a pair of objects in the array.
@@ -498,12 +573,16 @@ public:
void swap (const int index1,
const int index2) throw()
{
+ lock.enter();
+
if (index1 >= 0 && index1 < numUsed
&& index2 >= 0 && index2 < numUsed)
{
swapVariables (this->elements [index1],
this->elements [index2]);
}
+
+ lock.exit();
}
/** Moves one of the objects to a different position.
@@ -524,6 +603,8 @@ public:
{
if (currentIndex != newIndex)
{
+ lock.enter();
+
if (currentIndex >= 0 && currentIndex < numUsed)
{
if (newIndex < 0 || newIndex > numUsed - 1)
@@ -546,6 +627,8 @@ public:
this->elements [newIndex] = value;
}
+
+ lock.exit();
}
}
@@ -554,23 +637,36 @@ public:
@returns true only if the other array contains the same objects in the same order
*/
- bool operator== (const ReferenceCountedArray& other) const throw()
+ bool operator== (const ReferenceCountedArray& other) const throw()
{
- if (numUsed != other.numUsed)
- return false;
+ other.lockArray();
+ lock.enter();
- for (int i = numUsed; --i >= 0;)
- if (this->elements [i] != other.elements [i])
- return false;
+ bool result = numUsed == other.numUsed;
+
+ if (result)
+ {
+ for (int i = numUsed; --i >= 0;)
+ {
+ if (this->elements [i] != other.elements [i])
+ {
+ result = false;
+ break;
+ }
+ }
+ }
- return true;
+ lock.exit();
+ other.unlockArray();
+
+ return result;
}
/** Compares this array to another one.
@see operator==
*/
- bool operator!= (const ReferenceCountedArray& other) const throw()
+ bool operator!= (const ReferenceCountedArray& other) const throw()
{
return ! operator== (other);
}
@@ -608,7 +704,10 @@ public:
{
(void) comparator; // if you pass in an object with a static compareElements() method, this
// avoids getting warning messages about the parameter being unused
+
+ lock.enter();
sortArray (comparator, this->elements, 0, size() - 1, retainOrderOfEquivalentItems);
+ lock.exit();
}
//==============================================================================
@@ -620,6 +719,8 @@ public:
*/
void minimiseStorageOverheads() throw()
{
+ lock.enter();
+
if (numUsed == 0)
{
this->setAllocatedSize (0);
@@ -631,6 +732,33 @@ public:
if (newAllocation < this->numAllocated)
this->setAllocatedSize (newAllocation);
}
+
+ lock.exit();
+ }
+
+ //==============================================================================
+ /** Locks the array's CriticalSection.
+
+ Of course if the type of section used is a DummyCriticalSection, this won't
+ have any effect.
+
+ @see unlockArray
+ */
+ void lockArray() const throw()
+ {
+ lock.enter();
+ }
+
+ /** Unlocks the array's CriticalSection.
+
+ Of course if the type of section used is a DummyCriticalSection, this won't
+ have any effect.
+
+ @see lockArray
+ */
+ void unlockArray() const throw()
+ {
+ lock.exit();
}
@@ -639,6 +767,7 @@ public:
private:
int numUsed;
+ TypeOfCriticalSectionToUse lock;
};
diff --git a/src/juce_core/containers/juce_ReferenceCountedObject.h b/src/juce_core/containers/juce_ReferenceCountedObject.h
index 4dbdcae525..e13cb9c1ec 100644
--- a/src/juce_core/containers/juce_ReferenceCountedObject.h
+++ b/src/juce_core/containers/juce_ReferenceCountedObject.h
@@ -178,10 +178,11 @@ public:
if (newObject != 0)
newObject->incReferenceCount();
- if (referencedObject != 0)
- referencedObject->decReferenceCount();
-
+ ReferenceCountedObjectClass* const oldObject = referencedObject;
referencedObject = newObject;
+
+ if (oldObject != 0)
+ oldObject->decReferenceCount();
}
return *this;
@@ -199,10 +200,11 @@ public:
if (newObject != 0)
newObject->incReferenceCount();
- if (referencedObject != 0)
- referencedObject->decReferenceCount();
-
+ ReferenceCountedObjectClass* const oldObject = referencedObject;
referencedObject = newObject;
+
+ if (oldObject != 0)
+ oldObject->decReferenceCount();
}
return *this;