Sign in Join

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

Mailing lists / lazarus / 2015-03

TCustomEdit and LM Messages Ordering

1 message · 1 person ·

Reply by email Subscribe to this list Your subscription

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

Tony Whyman

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?

Reply by email