Difference between revisions of "LCL Interface Redesign Idea"

From Lazarus wiki
Jump to navigationJump to search
 
(11 intermediate revisions by 7 users not shown)
Line 4: Line 4:
 
However, many code using the LCL expects the handle being castable. Returning an object would break this.
 
However, many code using the LCL expects the handle being castable. Returning an object would break this.
  
NOTE: In case of gtk, we don't have to return the internal object in the case of gtk, we still can use the existing way of retrieving the widgetinfo
+
{{Note| In case of gtk, we don't have to return the internal object, we still can use the existing way of retrieving the widgetinfo}}
 +
{{Note| We also can start to use LCLHandle only, so that a later transition will be easier}}
  
 
==This is current Idea for the structure of the interface and how it relates to handles==
 
==This is current Idea for the structure of the interface and how it relates to handles==
Line 15: Line 16:
 
* Merge the branches
 
* Merge the branches
  
The change to .Handle will not break existing code.
+
'''The change to .Handle will not break existing code.'''
  
TWSxxWinControl.CreateHandle Returns a TLCLHandle
+
<syntaxhighlight lang=pascal>TWSxxWinControl.CreateHandle Returns a ILCLHandle
  
TLCLHandle = IInterface; // interfaces as com objects
+
ILCLHandle = IInterface; // interfaces as com objects
  
TxxPrivate = class(TPrivate, TLCLHandle);
+
TxxPrivate = class(TPrivate, ILCLHandle);
  
TGtkPrivateButton = class(TGtkBin, TLCLHandle);
+
TGtkPrivateButton = class(TGtkBin, ILCLHandle);</syntaxhighlight>
  
 
All TWSxx. methods  should be moved to the private class. for instance:
 
All TWSxx. methods  should be moved to the private class. for instance:
  class procedure TWSGtkWinControl.SetText(const AWinControl; const AText: String);
 
  var
 
    PrivWinControl: TGtkPrivateWinControl;
 
  begin
 
    PrivWinControl := TGtkPrivateWinControl(AWinControl.LCLHandle);
 
    PrivWinControl.SetText(AText);
 
  end;
 
  
NOTE:
+
<syntaxhighlight lang=pascal>
I'm not to sure if we should expose the TLCLHandle as Interface. This will cause an overhead of adding exception frames, addref and releaseref calls. We can do it internally and use TLCLHandle = PtrUInt (MWE).
+
class procedure TWSGtkWinControl.SetText(const AWinControl; const AText: String);
 +
var
 +
  PrivWinControl: TGtkPrivateWinControl;
 +
begin
 +
  PrivWinControl := TGtkPrivateWinControl(AWinControl.LCLHandle);
 +
  PrivWinControl.SetText(AText);
 +
end;
 +
</syntaxhighlight>
 +
 
 +
{{Note|I'm not to sure if we should expose the ILCLHandle as Interface. This will cause an overhead of adding exception frames, addref and releaseref calls. We can do it internally and use TLCLHandle &#61; PtrUInt (MWE).}}
  
 
==Other possibilities==
 
==Other possibilities==
  
 
For accessing widgetset native handles or IDs from the LCL, in the current situation, ppl have to cast the handle. In the case of gtk, to retrieve the XID, one needs the following cast:
 
For accessing widgetset native handles or IDs from the LCL, in the current situation, ppl have to cast the handle. In the case of gtk, to retrieve the XID, one needs the following cast:
  PGdkPrivateWindow(PGtkWidget(Handle)^.window)^.XID
+
 
 +
<syntaxhighlight lang=pascal>PGdkPrivateWindow(PGtkWidget(Handle)^.window)^.XID</syntaxhighlight>
  
 
When interfaces are used, one can imagine the following code
 
When interfaces are used, one can imagine the following code
  
{$IFDEF GtkHasX}
+
<syntaxhighlight lang=pascal>
TGtkPrivateWidget = class(TGtkPrivate, ILCLHandle, IX11Handle);
+
{$IFDEF GtkHasX}
 +
TGtkPrivateWidget = class(TGtkPrivate, ILCLHandle, IX11Handle);
  
(AWinControl.LCLHandle as IX11Handle).XID
+
(AWinControl.LCLHandle as IX11Handle).XID</syntaxhighlight>
  
 
or maybe better:
 
or maybe better:
if Supports(AWinControl.LCLHandle, IX11Handle, X11Handle) then
 
  ... DoSomething with X11Handle
 
  
Which leads to cleaner constructs, without the need of internal knowledge of the handle.
+
<syntaxhighlight lang=pascal>
 +
if Supports(AWinControl.LCLHandle, IX11Handle, X11Handle) then
 +
  ... DoSomething with X11Handle</syntaxhighlight>
 +
 
 +
Which leads to cleaner constructs, without the need of internal knowledge of the handle and can be the same in all widgetsets that use X11.
 +
 
 +
Note that for this we need COM interfaces and not CORBA, however we '''don't need reference counting''', so AddRef and ReleseRef can be implemented by just returning -1
 +
 
 +
:A problem with interfaces is that Qt for example runs in several operating systems. How do you know what is supported where? We will need to fill the class definition with ifdefs.
  
Note that for this we need COM interfaces and not CORBA, however we don't need reference counting, so AddRef and ReleseRef can be implemented by just returning -1
+
[[Category:LCL]]
 +
[[Category:Proposals]]
 +
[[Category:Lazarus Proposals]]

Latest revision as of 20:34, 8 April 2021

Why would we want this ?

In the present situation, the handle returned by TWSWinControl.CreateHandle is in case of win32 the winapi handle of the widget and in case of gtk a PGtkWidget. For the QT and Carbon widgetset a private internal object is returned. Using an internal object has some advantages. One of them is that we can use a true object hierarchy, with clear inheritence inside the widgetset. However, many code using the LCL expects the handle being castable. Returning an object would break this.

Light bulb  Note: In case of gtk, we don't have to return the internal object, we still can use the existing way of retrieving the widgetinfo
Light bulb  Note: We also can start to use LCLHandle only, so that a later transition will be easier

This is current Idea for the structure of the interface and how it relates to handles

Overview:

  • Fork a branch of lazarus/
  • Replace TWinControl.Handle with TWinControl.LCLHandle (there should exist no Handle yet)
  • Try to get the LCL compiled and maybe the IDE so it doesn't use the (inefficient) .Handle anymore
  • Introduce .Handle again, now as WSclass call
  • Merge the branches

The change to .Handle will not break existing code.

TWSxxWinControl.CreateHandle Returns a ILCLHandle

ILCLHandle = IInterface; // interfaces as com objects

TxxPrivate = class(TPrivate, ILCLHandle);

TGtkPrivateButton = class(TGtkBin, ILCLHandle);

All TWSxx. methods should be moved to the private class. for instance:

class procedure TWSGtkWinControl.SetText(const AWinControl; const AText: String);
var
  PrivWinControl: TGtkPrivateWinControl;
begin
  PrivWinControl := TGtkPrivateWinControl(AWinControl.LCLHandle);
  PrivWinControl.SetText(AText);
end;
Light bulb  Note: I'm not to sure if we should expose the ILCLHandle as Interface. This will cause an overhead of adding exception frames, addref and releaseref calls. We can do it internally and use TLCLHandle = PtrUInt (MWE).

Other possibilities

For accessing widgetset native handles or IDs from the LCL, in the current situation, ppl have to cast the handle. In the case of gtk, to retrieve the XID, one needs the following cast:

PGdkPrivateWindow(PGtkWidget(Handle)^.window)^.XID

When interfaces are used, one can imagine the following code

{$IFDEF GtkHasX}
TGtkPrivateWidget = class(TGtkPrivate, ILCLHandle, IX11Handle);

(AWinControl.LCLHandle as IX11Handle).XID

or maybe better:

if Supports(AWinControl.LCLHandle, IX11Handle, X11Handle) then
  ... DoSomething with X11Handle

Which leads to cleaner constructs, without the need of internal knowledge of the handle and can be the same in all widgetsets that use X11.

Note that for this we need COM interfaces and not CORBA, however we don't need reference counting, so AddRef and ReleseRef can be implemented by just returning -1

A problem with interfaces is that Qt for example runs in several operating systems. How do you know what is supported where? We will need to fill the class definition with ifdefs.