Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2009-08

Cursor handling on Windows

1 message · 1 person ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Vladimir Zhirov

Hi,

Martin and I started a discussion in the bugtracker and decided to move it here so more people can participate.

The bug report (http://bugs.freepascal.org/view.php?id=14336) is related to cursor handling on Windows.
To sum up, the bug is resolved, but we are still looking for more reliable means to set cursors in general and default cursor in particular.

Martin Friebe wrote 6 lines
There are 2 issues: 1) For SetCursor it is already documented on msdn that it does nothing, if the value is already set. Who is to say that future Window versions will check the position first, and ignore if it hasn't changed? It should work using "CallWindowProc "

CallWindowProc would require us to pass WParam an LParam values for WM_SETCURSOR message, and documentation about them seems a bit vague to me. I would not rely on default WindowProc behaviour unless I know what exactly must be passed in WParam and LParam. If I don't know it I would rather use SetCursorPos because at least it does not have documented restrictions like SetCursor has. SetCursorPos behavior can change later but for now it is predictable and clearly documented in contrast to WM_SETCURSOR. That's my thoughts on "CallWindowProc vs SetCursorPos".

The problem is, as you stated, both CallWindowProc and SetCursorPos will cause WindowProc execution, that is more expensive than SetCursor preceded by some calculations.

So, let me summarize your proposed changes for the future as I understand them and add my comments.

1) Remove cursor handling from MouseMove (at least in the cross widget part of the LCL)

I agree with this suggestion. AFAIU the first place to look at is TControl.WMMouseMove.

2) Add new LCL message talking controls to update their cursor (like WM_SETCURSOR on Windows) and ensure all WidgetSets use this message.

I'm not sure I understand you right here, but missing LM_SETMOUSE message led me to conclusion that you suggest what I stated above. If I get it right, it is hard to comment for me because I'm almost completely clueless about GTK and QT APIs so I cannot say if it worth the effort to make such change for all widgetsets.

3) Decide (or find out) if Control.SetCursor should trigger this message to update a cursor.

This is a controversial question, because triggering this message would involve costly message processing, but allow to handle cursors from one place. So it seems to evaluate to "execution speed vs code clarity" and the problem is to estimate differences.
I have not done any measurements but both
"CalculateBounds[+GetClassCursor]+SetCursor" (acting independently) and "GetCursorPos+SetCursorPos" (causing costly message processing) seems to work fast enough for me not to notice the difference. So maybe it is a matter of taste. It would be interesting to know what other think.

4) Optimize the current handling in WindowProc

See (3).

5) Decide if passing on handling to parent WinControl is wanted if
   "control.Cursor := crDefault" is done
   To conitue "Intended behaviour of crDefault cursor..." thread,
   here is what I think.
    a. We usually want to set a specific cursor for single control
       like Button, not for container like Panel
    b. It means containers usually have Cursor = crDefault,
       so it makes no difference whether cursor handling
       is passed to Parent or not.
    c. If we set custom cursor for container like Panel what
       do we most likely mean by it? Users coming from Delphi
       would expect Delphi behaviour that is setting it for
       Panel only. If there is a Button on the Panel and
       Button.Cursor = crDefault then it is system default
       cursor for buttons.
       <IMHO>
       So it seems crDefault in Delphi means
       "System default cursor for this kind of control".
       Screen.Cursor is an exception and crDefault here means
       "Do not override cursor settings"
       </IMHO>
    d. Sometimes it is useful to make child controls inherit
       cursor settings from parent. This helps to set e.g.
       crHourGlass for disabled panel with all child
       controls and then restore original cursor.
       In order to keep Delphi compatibility we can introduce
       crParent cursor and pass cursor handling to parent
       control if this cursor is set for child control.
       In this case crParent could still fallback to crDefault
       if the control has no parent.

Reply by email