While merging new version


#1

I’m finally merging from Juce 1.41 and here are some improvements / bugfixes / requests.

I’ll just list the diffs from svn revision 115 to our modified version :

// juce_linux_SystemStats.cpp (326) double Time::getMillisecondCounterHiRes() throw() { // was: * (1.0 / 1000000.0) return Time::getHighResolutionTicks() * (1.0 / 1000.0); }

[code]// juce_DirectoryContentsList.cpp (188)

// In our application, we use a directoryContentList object in a thread, that sends message to another thread, both of them are not the juce message loop. If we sendChangeMessage is called, it will have to wait for the message loop to get our event. Maybe it should be an option ?

void DirectoryContentsList::changed()
{
// was: sendChangeMessage (this);
sendSynchronousChangeMessage (this);
}
[/code]

// juce_StretchableLayoutManager.h (103) void StretchableLayoutManager::setTotalSize (const int newTotalSize) { // changes with setItemLayout() where discarded by this test //if (totalSize != newTotalSize)

[code] // juce_Viewport.h (217)

// theses methods let us use a Viewport with something else inside,
like adding scrollbars to an OpenGLComponent
virtual int getContentX() const throw ()                    { return contentComp ? contentComp->getX() : 0; }
virtual int getContentY() const throw ()                    { return contentComp ? contentComp->getY() : 0; }
virtual int getContentWidth() const throw ()                { return contentComp ? contentComp->getWidth() : 0; }
virtual int getContentHeight() const throw ()               { return contentComp ? contentComp->getHeight() : 0; }

// ...

protected:
void updateVisibleRegion();

// in juce_StretchableLayoutManager.cpp
// replace occurences of contentComp->getX() by getContentX()
// and so on …

[/code]

[code] // juce_ColourSelector.h (61)

// would be nice to be able to control what the background looks like
    showColourspace     = 1 << 3,    /**< if set, a big HSV selector is shown. */
    dontClearBackground = 1 << 4      /* if set, paint() dont clears the background of the component */


// ...
// moving this function from private to protected to lets us call it from inherited class to update the values
void sliderValueChanged (Slider*);

// in juce_ColourSelector.cpp (476)
if ((flags & dontClearBackground) == 0)
g.fillAll (Colour::greyLevel (0.9f));
[/code]

// juce_XmlDocument.cpp (478) // More information about last error is useful when it happens setLastError (T("illegal characters found in element ") + node->getTagName() + T(": '") + c + T("'"), false);

[code] // juce_XmlElement.h (159)
// very useful to create a text node when you don’t know the parent yet
static XmlElement* createTextElement(const String& text) throw();

// juce_XmlElement.cpp
XmlElement* XmlElement::createTextElement(const String& text) throw()
{
XmlElement* const e = new XmlElement ((int) 0);
e->setText (text);
return e;
}[/code]


#2

thanks for those, thomas. I’ve merged a lot of that, but…

  • I don’t understand what you’re doing with the directoryiterator. The whole point of it is that it uses its own thread and sends changes back to the message thread. Making it call synchronously would break the way it works, as it needs to aggregate the change callbacks. Surely waiting a few milliseconds for a message to arrive isn’t a problem?

  • I think a better way to handle the viewport would be to use a special content component that contains, e.g. your opengl component, and which keeps this component positioned correctly when it gets moved around by the viewport. Everything else in the viewport class assumes that the content is supplied by its subcomponent, so changing it like this would just feels like hacking it for one specific application.

  • instead of your colourselector idea, I’ll allow its background colour to be changed via setColour, so you can just make it transparent instead.


#3

[quote=“jules”]thanks for those, thomas. I’ve merged a lot of that, but…

  • I don’t understand what you’re doing with the directoryiterator. The whole point of it is that it uses its own thread and sends changes back to the message thread. Making it call synchronously would break the way it works, as it needs to aggregate the change callbacks. Surely waiting a few milliseconds for a message to arrive isn’t a problem?[/quote]
    sorry if I’m not clear. The object is used by a thread that decodes very set large sets of image files, the decoding thread needs to start as fast as possible, while the DirectoryContentsList continues to look for images it can decode in the directory.
    So waiting a few milliseconds is not an option for us, and also we can not take the risk of waiting for the message thread in case it’s too busy doing something else…

[quote=“jules”] - I think a better way to handle the viewport would be to use a special content component that contains, e.g. your opengl component, and which keeps this component positioned correctly when it gets moved around by the viewport. Everything else in the viewport class assumes that the content is supplied by its subcomponent, so changing it like this would just feels like hacking it for one specific application.
[/quote]
The problem with this solution is that we can not afford having an opengl context bigger than what is displayed, this too expensive in case we want to zoom inside a lot.

ok great !


#4

But if the callback is synchronous, it’ll block the file search thread while it makes the callback, which is what you say you don’t want (?) I can’t allow a synchronous callback to happen on the timeslice thread - it’s just not a sensible place for it. The whole point of using the changelistener is that it’ll only make one callback for each batch of new files it finds, so if your listener does its job properly and reads all the new files each time it gets a message, there’d be no measurable performance hit at all. I suspect there’s something else wrong with your design if this is causing problems.

[quote]
The problem with this solution is that we can not afford having an opengl context bigger than what is displayed, this too expensive in case we want to zoom inside a lot.[/quote]

I didn’t mean that - you could put a smaller opengl comp inside your viewed component and move it around when the viewed comp gets moved.

True, for this it’d be better to have a non-component based viewport, but that’d be a different kind of object; I don’t want to take a crowbar to this class just to make it do what you need. (Probably the best solution would be a new base class viewport that’s non-component based, and a derived class that re-implements the current one).


#5

But if the callback is synchronous, it’ll block the file search thread while it makes the callback, which is what you say you don’t want (?) I can’t allow a synchronous callback to happen on the timeslice thread - it’s just not a sensible place for it. The whole point of using the changelistener is that it’ll only make one callback for each batch of new files it finds, so if your listener does its job properly and reads all the new files each time it gets a message, there’d be no measurable performance hit at all. I suspect there’s something else wrong with your design if this is causing problems.
[/quote]

ok I think I understand what you mean -
The first (probably too naive) reason I changed this call is that we can not afford the possibility of being blocked if message thread is getting slower for any reason (like user resizing the window).
Secondly, we must get the first file found as soon as possible to start decoding and displaying it, cause it will block the opengl rendering in case the user doesn’t want frame drop.

here is how I do it :

class DirectoryImageSequencePlayerSource : public ImageSequencePlayerSource,
                                           public ChangeListener,
                                           public TimeSliceClient
{
  ReadWriteLock             _lock;
  ImageSequenceFileFilter   _file_filter;
  OwnedArray<InputStream>   _image_streams;
  TimeSliceThread           _directory_list_thread;
  DirectoryContentsList* volatile   _directory_lister;
  volatile bool             _directory_lister_changed;

  // ...

public:
  DirectoryImageSequencePlayerSource (const File& directory)
  {
    // ...
    _directory_lister = new DirectoryContentsList(&_file_filter, _directory_list_thread);
    _directory_lister->addChangeListener(this);
    _directory_lister->setDirectory(dir, false, true);

    _directory_list_thread.addTimeSliceClient(this);
    _directory_list_thread.startThread();
    // ...
  }

  virtual void changeListenerCallback (void* objectThatHasChanged)
  {
    ScopedWriteLock _(_lock);
    if (objectThatHasChanged == _directory_lister)
    {
      _directory_lister_changed = true;
      _directory_list_thread.notify();
    }

  virtual bool useTimeSlice()
  {
    if (_directory_lister_changed && _directory_lister)
    {
      ScopedWriteLock _(_lock);
      if (_image_streams.size() > _directory_lister->getNumFiles())
        _image_streams.clear();
      int image_streams_size = _image_streams.size();
      _image_streams.ensureStorageAllocated(_directory_lister->getNumFiles());
      for (int i = image_streams_size; i < _directory_lister->getNumFiles(); ++i)
        _image_streams.set(i, 0, false);
      _directory_lister_changed = false;
    }

  // this is called by the decoding thread
  virtual InputStream*  get_image_stream(int index)
  {
    ScopedWriteLock _(_lock);
    InputStream* stream = _image_streams.getUnchecked(index);
    if (stream == NULL && _directory_lister != NULL)
    {
      stream = _directory_lister->getFile(index).createInputStream();
      _image_streams.set(index, stream, false);
    }
    return stream;
  }

  // ...
};

According to what you say, it’s probably wrong direction, maybe I should make my own thread and use DirectoryIterator instead, for that I’ll need to modify it so that it can use a FileFilter…

[quote]

[quote]
The problem with this solution is that we can not afford having an opengl context bigger than what is displayed, this too expensive in case we want to zoom inside a lot.[/quote]

I didn’t mean that - you could put a smaller opengl comp inside your viewed component and move it around when the viewed comp gets moved.

True, for this it’d be better to have a non-component based viewport, but that’d be a different kind of object; I don’t want to take a crowbar to this class just to make it do what you need. (Probably the best solution would be a new base class viewport that’s non-component based, and a derived class that re-implements the current one).[/quote]

ok then - maybe we’ll try to propose a cleaner solution next time : )


#6

Hi again Jules,

I think you forgot to merge this :
in juce_ColourSelector.h, moving this function from private to protected to lets us call it from inherited class to update the values. Or maybe is it wrong ?

  protected:
    void sliderValueChanged (Slider*); 

Also, you didn’t answer my previous post, and I would be very interrested to ear your opinion on the best way to do that.


#7

You shouldn’t really have to call that sliderValueChanged method - if you change the value of a slider, then it’ll get triggered automatically, won’t it? And if you’re not changing the value of a slider, why would you need to call it?

Sorry, didn’t see your last post. Yes, if you really need to rip through a directory and churn its data fast, then a custom thread and directoryiterator is probably better (and probably easier to write, too). The point of the directorycontentslist class is to move the directory scanning into the background and batch together the changes so that the UI can redraw nicely. It’s not for doing serious data processing.


#8

you’re right. this modification was here for a long time now, I guess there was some other problem that doesn’t exist anymore, sorry for that

ok then, tanks a lot !


#9