[Lazarus] TCustomEdit and LM Messages Ordering
Tony Whyman
tony.whyman at mccallumwhyman.com
Fri Mar 20 11:48:46 CET 2015
I have been investigating why TCustomEdit descendents (such as
TDBDateEdit) do not appear to obey AutoSelect when selected using a
mouse click. On the other hand, AutoSelect appears to work when tab is
used to select the control. I am using Linux Mint 17/AMD64/GTK2 and, if
you read on, the issue does seem to be with the GTK2 interface.
Investigation:
TCustomEdit appears to have two cases where AutoSelect is applied, the
DoEnter and MouseUp methods and both have similar code:
DoEnter:
if (FAutoSelect and not (csLButtonDown in ControlState)) then
begin
SelectAll;
if (SelText = Text) then FAutoSelected := True;
end;
MouseUp:
if (FAutoSelect and not FAutoSelected) then
begin
SelectAll;
if (SelText = Text) then FAutoSelected := True;
end;
Note that DoEnter is not expected to call SelectAll if it occurs during
a mouse click. This seems correct as otherwise FAutoSelected will be
true when MouseUp is called and hence will not call SelectAll. The mouse
click will override the SelectAll in DoEnter and just position the cursor.
However, running the debugger it seems that DoEnter is called before
TControl.WndProc which is where the ControlState is updated to include
csLButtonDown. Hence, it will fire even during a mouse click.
For this to happen, it means that CM_ENTER (and hence LM_FOCUS) occurs
before LM_LBUTTONDOWN, which seems intuitively wrong. It was the mouse
click that caused the focus to move to the control!
However, this does seem to be deliberate with GTK2. Line 2193 of
./lcl/interfaces/gtk/gtkcallback.inc (Lazarus 1.4RC2) contains the comment:
{always send LM_SETFOCUS first}
and true enough, this is followed by :
if ((MessI.Msg = LM_LBUTTONDOWN) or (MessI.Msg = LM_RBUTTONDOWN) or
(MessI.Msg = LM_MBUTTONDOWN) or (MessI.Msg = LM_LBUTTONDBLCLK)) and
not AWinControl.Focused and AWinControl.CanFocus and
not (csDesigning in AWinControl.ComponentState) and (AWinControl
is TCustomEdit) then
begin
...
LCLIntf.SetFocus(AWinControl.Handle);
...
end;
// send the message directly to the LCL
NotifyApplicationUserInput(AWinControl, MessI.Msg);
Result := DeliverMessage(AWinControl, MessI);
Clearly, this seems to be the cause of TCustomEdit.AutoSelect not
functioning as expected, but is also deliberate. Does this solve another
problem or is this a case of what seemed like a good idea at the time?
More information about the Lazarus
mailing list