Mouse Cursor only hidden when window gets focus


#1

I have a window that should hide the cursor. The contentcomponent and window itself have the setMouseCursor(MouseCursor::NoCursor); call in the constructor (i did it for both just to be save).
When the window shows and has focus the mouse is indeed hidden, but if the mouse comes from another window that has the focus (other app or other Juce window) the cursor isn’t hidden until i click on the window so that it grabs the focus.
I also notice that the MouseEnter call is not being made until the window get’s focus.

This happens only on OSX on Windows it does hide the cursor the moment i move over the window. Is this an OSX related issue.
I now made a hack that polls for the mouse position and when the mouse is over the window i let it grab the focus, this then triggers the mouseenter and thus hides the cursor.
This works but is a major hack and can mess up the correct focus in other situations.
Anyone has any idea what i could do about this and if this an OS related issue maybe?


#2

It does sound like OSX specific stuff.

Maybe instead of polling you can use Desktop::addGlobalMouseListener() and then query for your window.


#3

Hmm the global mouselistener is indeed better than having a timer of some sort which i’m using now.
Look what i have now, i’m trying to prevent grabbing the focus when another window is of front of it.
As you can see that is really a hacky solution:

	if (!this->hasKeyboardFocus(true))
	{
		MouseInputSource* const source = Desktop::getInstance().getMouseSource(0);
		if (source != 0)
		{
			bool windowOverlapsAndHasFocus = false;
			for (int i=0; i<TopLevelWindow::getNumTopLevelWindows(); ++i)
			{
				TopLevelWindow* tlw = TopLevelWindow::getTopLevelWindow (i);
				if (tlw->getPeer() != this->getPeer())
				{
					windowOverlapsAndHasFocus =  tlw->getScreenBounds().intersects(this->getScreenBounds()) && 
												 tlw->hasKeyboardFocus(true);
					if (windowOverlapsAndHasFocus)
					break;
				}
			}		
			//this will make sure we get focus and that the mouse cursor will be hidden when neccessary
			//and we don't take focus if any other toplevelwindow is on top of ours and already has focus
			if (!windowOverlapsAndHasFocus && this->getScreenBounds().contains(source->getScreenPosition()))
				this->grabKeyboardFocus();
		}
	}

After we grab the focus the mouseEnter callback is done and that’s where i hide the mouse by calling setMouseCursor(MouseCursor::NoCursor).
Is there another way to just change the cursor now and not calling Component::setMouseCursor ?


#4

That’s just how OSX works. The foreground application ALWAYS has control over the mouse cursor, even if it’s actually over someone else’s window. You can’t work around this, it’s the same for all apps.


#5

Maybe if you don’t want to steal the focus and the current foreground window is also yours, you can poll MouseInputSource::getComponentUnderMouse()
and then set it to no-cursor if it is above your window.


#6

Ok i agree that when another app has focus that’s just how it works. But the same happens when having two JUCE windows within the same app and moving between them. I would think that’s something we could deal with.

[quote=“Shlomi”]Maybe if you don’t want to steal the focus and the current foreground window is also yours, you can poll MouseInputSource::getComponentUnderMouse()
and then set it to no-cursor if it is above your window.[/quote]
Thanx, i might need to do something like this.


#7

I’m surprised that it doesn’t work in that case… Might just be an oversight, I’ll have a look…


#8

Thanx for having a look, in the meantime:

Desktop::getInstance().getMainMouseSource().getComponentUnderMouse() does not return Components that are not in the part on the active window so that does not work.
Why not actually, Jules?
It seems odd that the Desktop object won’t return components that are not part of the active window, shouldn’t loop through all top level windows not only the active one.
With the following code ‘component’ will be null when moving over a window that’s not the active one.

void MainWindow::timerCallback() { void MainWindow::timerCallback() { Component* component = Desktop::getInstance().getMainMouseSource().getComponentUnderMouse(); for (int i=0; i<TopLevelWindow::getNumTopLevelWindows(); ++i) { TopLevelWindow* tlw = TopLevelWindow::getTopLevelWindow (i); MyWindow* myWindow = dynamic_cast<MyWindow*> (tlw); if (myWindow != 0 && component !=0) { DBG(component->getName()); if (myWindow->isParentOf(component)) { if (myWindow->getShouldHideMouse()) setMouseCursor(MouseCursor::NoCursor); } } } }


#9

That’s because unlike on windows, all mouse-events go to the foreground window, not to whichever window the mouse is over. I thought I’d added a workaround for that, but maybe not…


#10

Are you willing to have a look at this Jules or not, just checking. I need to know wether i need to build around it, which turns out to be quite hard without getting too messy.
The problems boils down to the fact that the mouseEnter callback isn’t made on on windows that are not the active one. So if you would build an app with some floating windows this could be a setback.


#11

I will have a look, but can’t promise how soon. And I’m not really sure if it’s something that I would actually want to change - OSX really doesn’t like background windows doing things when you mouse-over them - notice that if you have two background windows (even in the same app), the deactivated one can’t even be resized without selecting it, and I can’t think of any apps which update their cursors in the way you’re trying to do. In fact most OSX apps leave the mouse cursor “stuck” in whatever shape it had when the mouse left the foreground window, regardless of where else you move it on-screen.