[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.


TCustomEdit appears to have two cases where AutoSelect is applied, the 
DoEnter and MouseUp methods and both have similar code:

if (FAutoSelect and not (csLButtonDown in ControlState)) then
     if (SelText = Text) then FAutoSelected := True;

if (FAutoSelect and not FAutoSelected) then
       if (SelText = Text) then FAutoSelected := True;

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

     // 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