A customer created a window class with no default cursor, meaning that they set the hCursor
to nullptr
. What they saw was that the window showed up with an hourglass cursor, and that cursor never went away on its own. But if the user moved the mouse over a border, then the border arrow cursor carried into the client area. What’s going on?
What’s going on is that by setting the cursor to nullptr
, you’re saying “I will take care of the cursor.” Some time ago, I discussed how the cursor gets set, and if nobody else takes responsibility, then DefWindowProc
sets the cursor to the window class’s registered class cursor.
If there is no registered class cursor (if you set it to nullptr
), then that final fallback step doesn’t do anything, and nobody sets the cursor.
If nobody sets the cursor, then the cursor remains unchanged, and whatever cursor is currently set continues to be the cursor. The cursor remains set until somebody else sets a new one. If the cursor wanders over a border, then the DefWindowProc
function sets the border cursor. And then when it wanders into the client area, nobody sets the cursor, so the old border cursor remains.
Nobody actively asked for the border cursor to appear in the client area. Rather, nobody said what they wanted to appear in the client area, so nothing was changed.
The moral of the story is that if you set your class cursor to nullptr
, then you are assuming responsibility for handling the WM_
message and making sure that, eventually, somehow, a cursor gets set. If you fail to fulfill that obligation, then nobody sets the cursor, and you get leftover garbage.
+1 for flexibility. But… seems kind of like a solution searching for a problem. Who really wants to micromanage the cursor like that?
You need to do it if your window uses different cursors depending on what part of the window the mouse is in. For example, the Header control wants to show an arrow most of the time, but a left-right resizing arrow if the mouse is on the border between two columns.
Just to start a tiny holy war, I find it quite non-semantic to use pointer types for handles and NULL for zero-valued handle.
I did take a look at how handle types in Windows headers are declared and I do understand the reason it is done this way. But still, handle is a number with no implied meaning (or even a string of bits). So, in spite of it technically being a pointer to a fake structure type (which is a workaround of C limitations, say, in Delphi this could easily be expressed as THandle = type NativeInt or something like...
FWIW, it’s defined as
in System.pas
Nothing is stopping you from using “THandle =type NativeInt” in your Delphi code. In fact that sounds like a good idea. Using a pointer to a dummy structure is just a C workaround for the inability to create new types via typedef.