Two windows, one appears in background


#1

When a Juce OSX app starts up that shows two desktop windows, one of the windows appears in the foreground and the other one appears behind other applications (instead of in front with the first window).

To replicate this, use IntroJucer and create a new project: GUI application with auto-create main.cpp and a basic window. Each place "mainWindow" is used, add a second window (e.g. mainWin2): initialise, shutdown, and member variables. The two windows should appear one on top of the other in front of other apps, but one appears in front and the other appears behind other applications.

I'm using Juce 3.1.1 on a Mac with OS 10.9.5.


#2

Are you running in the debugger? Sometimes I've found window ordering can go a bit wrong when in the debugger, but it's fine when running an app normally.


#3

Yes, it's just like that. I normally run in the debugger - and from there the bug happens. But when I run the built app from the Finder, both windows appear normally.


#4

Ok - it's not a bug, probably just the debugger bringing itself to the front after the first window appears.


#5

is there a way to work around that problem? like a delayed, async call to restore windows to the state they report being in via Juce's API? right now debugging modal dialogs under Xcode is so volatile it's almost a guaranteed goose chase. The fact that a release build with all asserts disabled may "work" is little comfort...

thx!

-- p


#6

Not quite sure what you mean, TBH.. Debugging any kind of window ordering on any platform is always a pain because of this kind of thing. If you can suggest a change that would help you, please do, and we'll consider it!


#7

the case I've been working on had 2 (ordinary) document windows up then on a menu command it pops a modal dialog (prefs) that is seen on screen less than 5% of the time, yet dumping its state to log said it was the topmost active window, visible, enabled, with a valid rect, is a current modal window, is not blocked by another modal window, etc. Unless I missed some state flag, Juce reports it as legit yet it's not shown when running inside Xcode.

I don't trigger any breakpoint along the way, so it's not an issue of LLDB/Xcode disrupting the window z-order in an obvious way. I couldn't figure out what the problem was, but it works fine from the Finder.

I guess (and I really mean guess) it would be useful to have a generic function to serialize the Juce window scenegraph and report when Juce's state variables are out of sync with the system window hierarchy, at best to determine what Xcode is doing, at worst to rebuild the window hierarchy so system & Juce are back in sync.

thx!

-- p


#8

I've considered that kind of scene-graph saving before, but don't think that dealing with raw component positions is a good way to approach the saving of state. In things I've written where this sort of thing matters, I've always just tried to make it so that restoring UI from the model ends up with things in the correct order. (But obviously your situation may be a valid use-case for this, I don't know..)


#9

Ok, serialization may be a bad idea. Either way it's most important to identify *if* the scenegraph is out-of-sync since rebuilding it all the time makes no sense (whatever the method).

So something like TopLevelWinwow::CheckState() returning a bool or better yet an error string. I know it's not a pretty solution but it's better than an assert or the program silently continuing as if all is well. It looks like an Xcode bug that should eventually be fixed.

My 2 cents.

-- p

 


#10

update: it also happens when launched from the Finder, just less frequently than when launched from Xcode. Also my modal window doesn't show at all; it's not just hidden by another TLW because its area is larger than any other window.

So it doesn't seem to be Xcode-related but a generic race condition, possibly between the menu bar rescinding focus and the modal window gaining it.

Cheers,

-- p


#11

this problem seems "solved" by mixing-in an AsyncUpdater into JUCEApplication and instantiating DocumentWindows from handleAsyncUpdate(), i.e. after the main message loop has kicked in. That's what the Juce demo does but the comment says it's in order to determine the number of available rendering engines, when it should probably be done in all cases because manipulating Components/Windows before initialise() appears to do nothing or nothing reliable anyway (like calling toFront()).

It seems there are a number of non-deterministic behaviours that could be tightened, f.ex. the global FontList is randomly sorted and client code shouldn't have to call hail marys like deleteAndZero()  at WindowsDemo.cpp:255.

IMHO it's ok to require/recommend TLW creation post-event loop if it makes client code more predictable. It won't fix OS-level race conditions but reducing noice would be nice.

Just my 2 cents, naturally.

-- p


#12

Thanks for the observations. This feels to me like this is just OSX choosing to juggle windows around according to its own whims when you create them before the event loop starts, and with OSes you just have to accept that they'll sometimes do unexpected things to your window order.

I don't want to impose an asynchronous callback to perform initialisation on everyone, because it would likely break a lot of other people's code in subtle ways, but if that works in your case then great - it maybe worth me noting this in the comments somewhere.


#13

Cool. Maybe a helper class would, uh, help. Something like WindowSorter one could call to ensure expected z-order so windows are as reliable as a game's 2D sprite screnegraph.

Btw on OSX it's not quite as mundane as window z ordering being randomized; with TLWs instantiated pre-event loop, modal dialogs don't appear at *all*. One has to physically click on the dock with the mouse for subsequent windows to show. Otherwise the get silently dropped.

Thx for listening!

-- p