Window doesn't get active when clicking on TitleBar


#1

It seems that setUsingNativeTitleBar(true); breaks window activation on Mac. If I don’t use native bar, isActiveWindow property is updated correctly and activeWindowStatusChanged method is called. When using native bar, I don’t receive these updates when clicking on title bar. Clicking on the form body updates its active state correctly.

Is it designed behavior? If yes, what’s the best approach to get the same behavior as with not-native bar?

Juce version is 2.0.27 (pulled from git 10 minutes ago). Mac is 10.8. I’ve not tested it on Windows yet.


#2

Not sure what’s going on, but this definitely seems to work ok for me, no matter where I click… ?


#3

Do you have 10.8 as well?


#4

No, I’m still on 10.7… I guess that could be the difference…


#5

Downloading previous version ISO. Will let you know then.


#6

Reinstalling your OS just to see whether that’s the reason seems a bit… hardcore. Maybe easier just to have a go at tracing the code and see what’s happening?


#7

No, I have Parallels on my machine:)
I’m perfectly new to JUCE and thus it’s easier for me to set a breakpoint on two machines and compare stack traces to find out what’s happening.


#8

Here is what happens on 10.8:
Inside Component::takeKeyboardFocus method peer->grabFocus () doesn’t make the window key window. So, this condition is never true and activeWindowStatusChanged method isn’t called:

Immediately after this the program receives a NSViewComponentPeer:becomeKeyWindow selector call. It calls grabFocus and the window indeed become key window.
Probably, we should also call

[code]WeakReference componentLosingFocus (currentlyFocusedComponent);
currentlyFocusedComponent = this;

Desktop::getInstance().triggerFocusCallback();

// call this after setting currentlyFocusedComponent so that the one that’s
// losing it has a chance to see where focus is going
if (componentLosingFocus != nullptr)
componentLosingFocus->internalFocusLoss (cause);

if (currentlyFocusedComponent == this)
internalFocusGain (cause, safePointer);[/code]
from the NSViewComponentPeer:becomeKeyWindow selector. Jules what do you think?


#9

I don’t think you’re looking at the right code-path…

For me, becomeKeyWindow calls NSViewComponentPeer::grabFocus, which calls viewFocusGain, and that call ComponentPeer::handleFocusGain(), and from there it ends up in TopLevelWindow::focusOfChildComponentChanged. It never goes inside Component::takeKeyboardFocus… (?)


#10

This happens earlier. takeKeyboardFocus is called from appFocusChanged. currentlyFocusedPeer is not null and its call handleFocusGain method. It calls grabKeyboardFocus method and it calls takeKeyboardFocus.

I’ve noticed that viewFocusLoss method is never called on my machine (currentlyFocusedPeer is never null). I get viewFocusGain call from the becomeFirstResponder method, but never viewFocusLost since resignFirstResponder is never called.

I can solve the problem by changing becomeKeyWindow to

void becomeKeyWindow() { handleBroughtToFront(); component.grabKeyboardFocus(); }

But this forces activeWindowStatusChanged to be called several times on activation.

I also tried to null currentlyFocusedPeer in appFocusChanged but this didn’t solve the problem.


#11

If I could reproduce it, it’d be easy to fix… Are you sure this is an OS version thing, and not just a difference between the apps we’re testing? Can you reproduce this with the juce demo?


#12

I added

void activeWindowStatusChanged () { static int c = 0; std::cout << "activeWindowStatusChanged #" << ++c << ": " << isActiveWindow() << "\r\n"; }

to MainDemoWindow class and it works the same way as in my test app. You should enable native titlebar, of course.


#13

This fix solves the problem for JuceDemo

static void appFocusChanged() { ... if (isValidPeer (currentlyFocusedPeer)) { if (Process::isForegroundProcess()) { .... } else { ComponentPeer* focusedPeer = currentlyFocusedPeer; currentlyFocusedPeer = nullptr; focusedPeer->handleFocusLoss(); } } }


#14

And this fix solves the problem for my app (I animate window on activity change):

void TopLevelWindow::visibilityChanged() { if (isShowing() && Process::isForegroundProcess() && (getPeer()->getStyleFlags() & (ComponentPeer::windowIsTemporary | ComponentPeer::windowIgnoresKeyPresses)) == 0) { toFront (true); } }


#15

Ok…

When I added your suggested callback method to MainDemoWindow, then I also saw it failing to get called.

But… When I added a call to the superclass (which you do need to do, because the superclasses do some significant stuff in there), then everything was fine:

[code]void activeWindowStatusChanged ()
{
DocumentWindow::activeWindowStatusChanged();

static int c = 0;
std::cout << "activeWindowStatusChanged #" << ++c <<  ": " << isActiveWindow() << "\r\n";

}
[/code]


#16

I don’t know Jules… Calling base method doesn’t help on my mac. I need to click into window content to get it activated. You may need to activate/deactivate the window about 3 times to get wrong behavior.

Here is video how the bug looks like: https://docs.google.com/open?id=0B9Xn9hMS2mRuVVJBMVdOTlBHd1k
It’s an empty vw with a fresh git clone from git://juce.git.sourceforge.net/gitroot/juce/juce and unaltered demo code.

Do you have a Mountain Lion nearby? Just to check I don’t fail somewhere else.


#17

Yeah, I don’t see that behaviour at all, so I guess it must be a 10.8 difference. I’ll upgrade soon, just haven’t got around to it yet.