Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mouse cursor invisible -- MacOS #1218

Closed
knubie opened this issue Dec 9, 2018 · 16 comments
Closed

Mouse cursor invisible -- MacOS #1218

knubie opened this issue Dec 9, 2018 · 16 comments

Comments

@knubie
Copy link

knubie commented Dec 9, 2018

Steps to reproduce:

  • Open kitty (maximize the window so it fills up most of the screen)
  • Open some other app (like finder)
  • Use kitty until the mouse cursor disappears.
  • Cmd+tab to the other app such that the mouse cursor is already positioned on the other app window.
    • Note that the mouse cursor is now visible.
  • Move the mouse cursor off of the other app window and on top of the kitty window.
    • Note that the mouse cursor will now disappear.
  • Move the mouse cursor back onto the other app window.
    • Note that the mouse cursor is still hidden

Expected behavior:

I would not expect kitty to ever hide the mouse cursor when it does not have focus. I would also not expect it to hide a moving mouse cursor.

It seems that kitty is too aggressively hiding the mouse cursor, even when it doesn't have focus.

@lithammer
Copy link

lithammer commented Dec 9, 2018

Does setting mouse_hide_wait to 0 alleviate the issue?

@Luflosi
Copy link
Contributor

Luflosi commented Dec 10, 2018

@lithammer pretty sure, that your suggestion will work around the issue for him.
@knubie Could you try to recompile kitty with Luflosi@362ab96 applied? It might fix your issue without needing to disable mouse cursor hiding.

@kovidgoyal
Copy link
Owner

I'm somewhat surprised that macos would even allow non focused applications to hide the mouse cursor. That seems like a security issue. Non focused applications should not be able to control the mouse cursor from under the focused application, at least without special privileges.

@knubie
Copy link
Author

knubie commented Dec 10, 2018

It's actually difficult to reproduce this when kitty first loads. Only once the bug happens "naturally" am I able to consistently reproduce it. I'm not sure exactly what's triggering it.

@kovidgoyal
Copy link
Owner

I cannot reproduce, and looking at the code, I dont see anything wrong that kitty is doing. There are only two places where kitty asks the OS to hide the mouse cursor.

  1. When cocoa fires the mouseEnter event and the cursor is supposed to be hidden (this is the code path @Luflosi is referencing). There is a corresponding showCursor call in mouseExit.

  2. When the mouse hide timeout expires, here kitty calls glfwSetInputMode, which calls _glfwPlatformSetCursorMode which in turn only does anything if _glfwPlatformWindowIsFocused returns true (i.e. if the cocoa isKeyWindow method returns true which means the window is focused.

So kitty never asks the OS to hide the mouse unless the window has focus. I'm guessing the issue is because mouseEntered/mouseExited is not being sent by cocoa when you dont actually move the mouse but instead use cmd-tab to switch applications. Not sure what can be done about that. Perhaps this patch, which I cannot test since I cannot reproduce:

diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m
index b6c63488..7305159c 100644
--- a/glfw/cocoa_window.m
+++ b/glfw/cocoa_window.m
@@ -455,6 +455,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
     _glfwInputWindowFocus(window, GLFW_TRUE);
     updateCursorMode(window);
+    if (window->cursorMode == GLFW_CURSOR_HIDDEN) hideCursor(window);
     if (_glfw.ns.disabledCursorWindow != window && cursorInClientArea(window))
     {
         double x = 0, y = 0;
@@ -467,6 +468,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 {
     if (window->monitor && window->autoIconify)
         _glfwPlatformIconifyWindow(window);
+    showCursor(window);
 
     _glfwInputWindowFocus(window, GLFW_FALSE);
 }
@@ -713,17 +715,11 @@ static GLFWapplicationshouldhandlereopenfun handle_reopen_callback = NULL;
 
 - (void)mouseExited:(NSEvent *)event
 {
-    if (window->cursorMode == GLFW_CURSOR_HIDDEN)
-        showCursor(window);
-
     _glfwInputCursorEnter(window, GLFW_FALSE);
 }
 
 - (void)mouseEntered:(NSEvent *)event
 {
-    if (window->cursorMode == GLFW_CURSOR_HIDDEN)
-        hideCursor(window);
-
     _glfwInputCursorEnter(window, GLFW_TRUE);
 }

@Luflosi
Copy link
Contributor

Luflosi commented Dec 11, 2018

I'll try your patch for a week or so.

@knubie
Copy link
Author

knubie commented Dec 14, 2018

Thanks for the patch @kovidgoyal, I will keep using the un-patched version to see if I can figure out steps to reliable reproduce the bug.

@knubie
Copy link
Author

knubie commented Dec 21, 2018

Haven't noticed this issue in a few days, so I'll close the issue.

@knubie knubie closed this as completed Dec 21, 2018
@Luflosi
Copy link
Contributor

Luflosi commented Dec 22, 2018

@knubie you probably meant @kovidgoyal.

Sorry for the giant wall of text that follows.

So kitty never asks the OS to hide the mouse unless the window has focus.

I don't think that's the case: mouseEntered() and mouseExited() are called whenever the mouse cursor enters or exits the window. The window decoration at the top with the title and the three buttons and the other three window borders don't count. It doesn't matter if the window has focus or not, it only matters that there is no other window above kitty at the cursor position. So if I have another program with a very small window above the kitty window, so that the kitty window is visible to all four sides of the smaller window, then moving the mouse cursor from inside the small window to the outside, over the kitty window, will cause mouseEntered() to be called, even though kitty has no focus.
I still don't understand, why this would cause issues as kitty doesn't seem to be able to hide the cursor when it doesn't have focus. I removed all calls to showCursor(window) and hideCursor(window) from glfw/cocoa_window.m and added a call to showCursor(window) in mouseExited() and a call to hideCursor(window) in mouseEntered(). As expected, the cursor is hidden inside the window and visible outside the window. This however doesn't work if kitty doesn't have focus, then the cursor is always visible. I also tried swapping the two calls, which didn't change anything when kitty has no focus.
And even if that would cause issues, hideCursor(window) should only be called, when window->cursorMode is GLFW_CURSOR_HIDDEN, right?. Why would that be the case? Shouldn't the cursor always be visible while it's moving?
I also experimented with windowDidBecomeKey(), windowDidResignKey(), mouseEntered() and mouseExited() by printing whenever they are called. It is indeed possible that mouseExited() is not called when windowDidResignKey() is called. This is the case when the cursor is outside the window while pressing cmd+tab or when pressing and releasing cmd+tab so fast, that the little menu with all the apps in it doesn't show up. There is also something really weird going on when the mouse cursor is over the window while pressing and releasing cmd+tab long enough so that the menu doesn't show up:

  1. Open a window of some app
  2. Open kitty
  3. Have the two windows next to each other, preferably not overlapping
  4. Focus the kitty window
  5. Move the mouse cursor over the kitty window
  6. Press and release cmd+tab so that the app switcher menu shows up (switch to the other app)
  7. windowDidResignKey() and mouseExited() are called
  8. Press cmd
  9. Press and release tab
  10. mouseEntered() is called (what the heck???)
  11. Release cmd (so that kitty has focus again)
  12. windowDidBecomeKey() and mouseExited() is called (what the heck again???)
  13. Moving the cursor will call mouseEntered() again

This was just something weird I wanted you to know about.

Your patch adds if (window->cursorMode == GLFW_CURSOR_HIDDEN) hideCursor(window); to windowDidBecomeKey(). windowDidBecomeKey() calls updateCursorMode(window);, which calls updateCursorImage(window); if cursorInClientArea(window) is true. updateCursorImage() calls hideCursor(window); if window->cursorMode is not GLFW_CURSOR_NORMAL. Therefore I don't think that your added line does anything.

All that said though, I can't remember having experienced the bug since I've been using your patch. But that was also the case with my patch.
My guess what the real problem is, is that os_window->last_mouse_activity_at is not properly updated in all cases, causing window->cursorMode to be set to GLFW_CURSOR_HIDDEN. When kitty doesn't have focus, the time is only updated when the mouse enters the window, not when moving inside the window or when exiting the window. When kitty has focus, everything seems fine with that time though.

@Luflosi
Copy link
Contributor

Luflosi commented Dec 22, 2018

Or maybe we need a check in if (OPT(mouse_hide_wait) > 0 && !is_mouse_hidden(os_window)) { in kitty/child-monitor.c if the window has focus.

@kovidgoyal
Copy link
Owner

last_mouse_activity is updated when there is any mouse activity at all, enter/leave, button press, movement.

As I said right at the beginning, no unfocused application should be able to change the mouse cursor visibility, no matter what it does, as that is a security risk. And I cannot reproduce this issue. So simply flailing in the dark doesn't seem like a very effective way to fix this.

@octplane
Copy link

octplane commented Jan 7, 2019

I also see the same issue, although I did not found any way to reproduce it. It happens randomly but quite often and my recent increased usage of kitty suggests relation between the two. 🤷‍♂️

@knubie
Copy link
Author

knubie commented Jan 11, 2019

I've also started noticing it again, but it's very difficult to reproduce.

@amarshall
Copy link
Contributor

I see this behavior a lot (it drives me nuts, hadn’t realized it might be Kitty), and I don’t know how to reproduce it starting to happen, either (but once it starts, the original reproduction steps work). I’m going to run Kitty with the above patch for a week and report back.

@DealPete
Copy link

This issue should not be closed, it happens frequently to me as well.

@knubie knubie reopened this Jan 30, 2019
@amarshall
Copy link
Contributor

I used the above patch applied to v0.13.3 all week without exiting Kitty on two different machines both running macOS 10.13.6. Didn’t have the cursor disappearing issue once. At the end, I decided to try the unpatched v0.13.3 for a bit, and within an hour had the cursor disappearance issue. Further, there didn’t appear to be any issues functionally with the normal behavior of the cursor disappearing after the configured time period when Kitty has focus.

As such, it’d be great to see the patch merged and released, as it appears to resolve the issue.

thorncp added a commit to thorncp/dotfiles that referenced this issue May 24, 2019
0.14 added the option to hide the mouse on keypress and may have also
fixed the bug I was having with the mouse becoming permanently
invisible: kovidgoyal/kitty#1218
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants