Mouse cursor handling is broken in GTK4
Steps to reproduce
- Run gtk4-demo
- Move mouse around
- Try to resize window
Current behavior
Mouse cursor often disappears, sometimes the cursor is not the right kind for the widget under the pointer, and it crashes eventually
Expected outcome
Everything should work
Version information
GTK4 master, W32
Additional information
I blame @fanc999 for this, it's due to a quick and dirty fix for GTK4 to compile after GdkCursor changes.
-
It doesn't take into account cursor status and will try to call DestroyCursor() on cursors that must not be destroyed (see this MSDN page for the list of cursors that must not be destroyed)
-
gdk_window_set_cursor() unrefs the window cursor at the beginning of the function. If that was the last reference, the cursor gets destroyed, and if it's still in use GDK does call SetCursor (NULL), which hides the cursor. gdk_window_set_cursor() creates and sets new cursor afterwards (more often than not - the same cursor!), but nevertheless there's a brief moment when there's no cursor. That can cause cursor blinking.
-
(this might actually be caused by other commits made by this point, not by this specific patch) WM_SETCURSOR handler does not try to set cursor for the window under the cursor, it can only set cursor if there's a grab. Note that Windows is not X. On X we have XDefineCursor(), which sets cursor for a specific X window. On Windows the cursor is global and handling WM_SETCURSOR is the way to set specific cursor for a specific window. In the same vein, set_window_cursor() function shouldn't call SetCursor() if the window is not under the cursor (though, luckily, it is currently called only in these exact circumstances, so nothing weird actually happens).
I think that the right fix for this is to roll the code back somewhat and reintroduce a Windows cursor class (not necessarily a subclass of GdkCursor) that keeps track of the HCURSOR type (to avoid destroying shared cursors), knows how to defer DestroyCursor() until the cursor is no longer in use (or just delay it for a bit, to ensure that the code up the stack had a chance to set a new cursor, which might be the same as the old one, in which case there's no need to destroy anything). And W32 window impl should either keep the cursor set for this window around, or we should call gdk_window_get_cursor () (keeping a HCURSOR means that we avoid a hashtable lookup, so that way we save up on CPU cycles).