PluginEditor repeatedly resizing on LInux


#1

I have been developing a plugin on OSX for some time now, but I’m trying to move my workflow to Linux. When I open the GUI in Linux, I see some very strange behavior where the plugin window gets larger and larger, even though I’m not telling it anywhere to resize. In fact, I have called setResizable(false, false), so this shouldn’t resize at all. I had no such problems on MacOSX.

These are the sizes as checked by getHeight() and getWidth() in the PluginEditor::paint() and PluginEditor::resized() accessors. I only tell the window its size once, ever (960, 600). If I let it keep going, I fail an assertion in the Image class (almost certainly an out of memory error). The new sizes are not the same if I re-run the application.

Resized 960 600
Paint 960 600
Resized 1100 689
Paint 1100 689
Resized 1258 788
Resized 1438 901
Resized 1644 1030
Resized 1879 1178
Resized 2148 1347
Paint 2148 1347
Resized 2457 1542
Resized 2809 1764
Resized 3212 2017
Resized 3671 2306
Resized 4197 2638
Resized 4797 3016
Resized 5484 3449
Resized 6268 3943
Resized 7164 4508
Resized 8189 5153
Resized 9361 5892
Paint 9361 5892
Resized 10700 6735
Resized 12229 7698
Resized 13977 8799

Here is a stack trace from gdb of one of the calls to resize(). Any thoughts?

#0  MyAudioProcessorEditor::resized (this=0xf88bb0) at MyPlugin/PluginEditor.cpp:201
#1  0x00007fffdecb5fa6 in juce::Component::sendMovedResizedMessages (this=0xf88bb0, wasMoved=false, wasResized=true)
    at ThirdParty/Juce/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:1191
#2  0x00007fffdecb5f18 in juce::Component::sendMovedResizedMessagesIfPending (this=0xf88bb0) at ThirdParty/Juce/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:1173
#3  0x00007fffdecb5e9b in juce::Component::setBounds (this=0xf88bb0, x=0, y=0, w=1879, h=1182) at ThirdParty/Juce/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:1159
#4  0x00007fffdecb629b in juce::Component::setBounds (this=0xf88bb0, r=...) at ThirdParty/Juce/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:1237
#5  0x00007fffdee2a7ab in JuceVSTWrapper::EditorCompWrapper::resized (this=0x1029c30) at ThirdParty/Juce/JUCE/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:1293
#6  0x00007fffdecb5fa6 in juce::Component::sendMovedResizedMessages (this=0x1029c30, wasMoved=false, wasResized=true)
    at ThirdParty/Juce/JUCE/modules/juce_gui_basics/components/juce_Component.cpp:1191
#7  0x00007fffded3ff3b in juce::ComponentPeer::handleMovedOrResized (this=0x106ab10) at ThirdParty/Juce/JUCE/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp:328
#8  0x00007fffded8d0b8 in juce::LinuxComponentPeer::handleConfigureNotifyEvent (this=0x106ab10, confEvent=...) at ThirdParty/Juce/JUCE/modules/juce_gui_basics/native/juce_linux_Windowing.cpp:2346
#9  0x00007fffded8bdf8 in juce::LinuxComponentPeer::handleWindowMessage (this=0x106ab10, event=...) at ThirdParty/Juce/JUCE/modules/juce_gui_basics/native/juce_linux_Windowing.cpp:1991
#10 0x00007fffded8a171 in juce::LinuxComponentPeer::windowMessageReceive (event=...) at ThirdParty/Juce/JUCE/modules/juce_gui_basics/native/juce_linux_Windowing.cpp:1529
#11 0x00007fffdebd977f in juce::InternalMessageQueue::dispatchNextXEvent () at ThirdParty/Juce/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:174
#12 0x00007fffdebd9283 in juce::InternalMessageQueue::dispatchNextEvent (this=0x7fffb8000970) at ThirdParty/Juce/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:93
#13 0x00007fffdebd6c50 in juce::MessageManager::dispatchNextMessageOnSystemQueue (returnIfNoPendingMessages=true) at ThirdParty/Juce/JUCE/modules/juce_events/native/juce_linux_Messaging.cpp:393
#14 0x00007fffdebd2d17 in juce::MessageManager::runDispatchLoopUntil (this=0x7fffb8000910, millisecondsToRunFor=250)
    at ThirdParty/Juce/JUCE/modules/juce_events/messages/juce_MessageManager.cpp:94
#15 0x00007fffdee27688 in SharedMessageThread::run (this=0xf27c60) at ThirdParty/Juce/JUCE/modules/juce_audio_plugin_client/VST/juce_VST_Wrapper.cpp:197
#16 0x00007fffdeb56b56 in juce::Thread::threadEntryPoint (this=0xf27c60) at ThirdParty/Juce/JUCE/modules/juce_core/threads/juce_Thread.cpp:102
#17 0x00007fffdeb56bf9 in juce::juce_threadEntryPoint (userData=0xf27c60) at ThirdParty/Juce/JUCE/modules/juce_core/threads/juce_Thread.cpp:117
#18 0x00007fffdeb758ba in juce::threadEntryProc (userData=0xf27c60) at ThirdParty/Juce/JUCE/modules/juce_core/native/juce_posix_SharedCode.h:909
#19 0x00007ffff6a3570a in start_thread (arg=0x7fffde324700) at pthread_create.c:333


#2

Could you please share your plug-in loading and editor display code? I’m not sure what could be causing this.


#3

I took a crack at getting a minimal example together for this and it’s posted below.
tl;dr: All that’s left is Juce boilerplate code.

I’m therefore concluding that the problem is not in my c++ code. This doesn’t mean the problem isn’t my fault though. It’s probably a good time to mention that my workflow doesn’t involve the jucer or the generated makefile. I build my plugins using bazel, which means that I have a bazel build file that replicates the actions of the Juce makefile. As far as I can tell, the only thing that really could be different are some build flags, but that seems like a bit of a stretch for the problem that I am having. Can you think of any improperly configured flags that may cause UI issues like this? The message to call resize() looks like it comes from pretty high up in the stack trace, but I don’t know the source.


PluginEditor.h

#ifndef __CONSTELLATION_PLUGINEDITOR_H__
#define __CONSTELLATION_PLUGINEDITOR_H__
#include <cassert>

#include "ThirdParty/Juce/Juce.h"

#include "Constellation/PluginProcessor.h"

class ConstellationAudioProcessorEditor
    :  public juce::AudioProcessorEditor {
 public:
  ConstellationAudioProcessorEditor(ConstellationAudioProcessor& p) : AudioProcessorEditor(&p) {
    setSize(960, 600);
  }
 private:
  void paint(juce::Graphics& g) {}

  void resized() {
    fprintf(stderr, "%d\n", getWidth());
    assert(getWidth() < 6000);  // Prevent the window from getting arbitrarily large.
  }
  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ConstellationAudioProcessorEditor)
};

#endif  // __CONSTELLATION_PLUGINEDITOR_H__

PluginProcessor.h

#ifndef __CONSTELLATION_PLUGINPROCESSOR_H__
#define __CONSTELLATION_PLUGINPROCESSOR_H__

#include "ThirdParty/Juce/Juce.h"

class ConstellationAudioProcessor
    : public juce::AudioProcessor  {
 public:
  ConstellationAudioProcessor(){}
  ~ConstellationAudioProcessor(){}


  void prepareToPlay(double sampleRate, int samplesPerBlock) override {}
  void releaseResources()  override{}
  void processBlock(juce::AudioSampleBuffer& buffer, juce::MidiBuffer& midiMessages) override {}
  bool hasEditor() const  override { return true;}
  juce::AudioProcessorEditor* createEditor()  override;
  void getStateInformation(juce::MemoryBlock& destData)  override {}
  // If we fail to set the state, we just default to a blank plugin.
  void setStateInformation (const void* data, int sizeInBytes)  override {}

  const String getName() const override { return JucePlugin_Name;}
  int getNumParameters() override { return 0;}
  float getParameter (int index) override { return 0.0f;}
  void setParameter (int index, float newValue) override {}
  const String getParameterName (int index) override { return String();}
  const String getParameterText (int index) override { return String();}
  const String getInputChannelName (int channelIndex) const override { return String (channelIndex + 1);}
  const String getOutputChannelName (int channelIndex) const override { return String (channelIndex + 1);}
  bool isInputChannelStereoPair (int index) const override { return true;}
  bool isOutputChannelStereoPair (int index) const override { return true;}
  bool acceptsMidi() const override { return true;}
  bool producesMidi() const override {return false;}
  bool silenceInProducesSilenceOut() const override {return false;}
  double getTailLengthSeconds() const override {return 1.0;}
  int getCurrentProgram() override { return 0;}
  void setCurrentProgram (int index) override {}
  const String getProgramName (int index) override { return String();}
  void changeProgramName (int index, const String& newName) override {}
  int getNumPrograms() override {
    return 1;   // NB: some hosts don't cope very well if you tell them there are 0 programs,
    // so this should be at least 1, even if you're not really implementing programs.
  }

private:
  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConstellationAudioProcessor);
};

#endif  // __CONSTELLATION_PLUGINPROCESSOR_H__

PluginProcessor.cpp

#include "Constellation/PluginProcessor.h"
#include "Constellation/PluginEditor.h"

juce::AudioProcessorEditor* ConstellationAudioProcessor::createEditor() {
  return new ConstellationAudioProcessorEditor(*this);
}

// This creates new instances of the plugin..
juce::AudioProcessor* JUCE_CALLTYPE createPluginFilter() {
  return new ConstellationAudioProcessor();
}

#4

Yep, that’s now entirely JUCE code and it should work as expected. Could you share how you are loading your plug-in and displaying the editor? I’ve tried displaying your editor manually and in the JUCE demo host and I don’t see any extra resize requests.


#5

Sorry, I guess I thought that code was what you were asking for. I am loading and viewing the plugin using the Juce Plugin Host.


#6

Don’t worry - if the problem is happening with the boilerplate code above then we know that it’s probably a problem with the host rather than the plug-in.

Just to double check though: do you see the same problem when you load the JUCE demo plug-in in the JUCE demo host?


#7

Indeed I do.

Do you agree that this problem is likely not caused by a problem with the build stage? I have no expectation that you’re familiar with bazel, but say for the purpose of discussion that I had written my own makefile; do you agree that my issues seem unlikely to have been caused by a problem in the makefile?

Thanks again for your time. I’ve been working on getting my code to build on Linux for months now (this isn’t my day job, after all) and I feel like I’m so close.


#8

Yes, I think it’s unlikely to be caused by the build system - but isn’t this is something you can check quite easily? Simply build the demo plug-in using both bazel and the Projucer generated Makefiles and compare the behaviour. If they both end up resizing then it’s almost certainly the host or something else on your operating system. I assume you built the demo host using the Projucer Makefiles? Loading the demo plug-in in the demo host is pretty well tested, so if things are still going wrong then the main culprit is the OS.

Which flavour of Linux are you using? Is there anything unusual about the machine?


#9

Good suggestion. Any combination of the bazel-built plugin host, makefile-built plugin host, bazel-built plugin demo, and makefile-built plugin demo produces the problem.

I’m running Ubuntu 16.04 LTS 64 bit. It’s a custom built machine, but that shouldn’t matter. I can’t think of anything unusual off the top of my head.


#10

I’m afraid I don’t know why this is happening, and I can’t reproduce anything like it on an Ubuntu 16.04 LTS 64 bit VM.

What happens to other non-JUCE plug-ins in the demo host?
What happens to both JUCE and non-JUCE plug-ins in a different host?


#11

I have Ardour, but I haven’t successfully been able to find my plugins in its interface. The built in plugins work fine, but I don’t think they’re actually VST format. I don’t have other VSTs as of now. I’ve mostly been working on getting this stuff working since I got the computer and was kind of banking on doing the bulk of my testing in the plugin host. I’ll try and get some other things working and post again later. Thanks.


#12

Hello again. I chased the problem around a bit and ended up in juce_gui_basics/native/juce_linux_Windowing.cpp:updateWindowBounds() where a bunch of mysterious (to me) bounding box changes are done. I’m not sure exactly what causes the problem, but I found that disabling use of xrandr fixes it. The problem was likely introduced in this change.

My computer is only using a single monitor, but I do have a dedicated graphics card. I’m not sure if that’s important or not.


#13

Hi Chet,

Thanks for the report. The issue was that the VST2 plug-in code directly tries to re-size the window without respecting the scaling factor. I think I’ve fixed this now on develop.

Fabian