Difference between revisions of "Carbon interface internals"

From Free Pascal wiki
Jump to navigationJump to search
m (Relocated Platform templates to page template)
 
(44 intermediate revisions by 11 users not shown)
Line 1: Line 1:
 
{{Carbon interface internals}}
 
{{Carbon interface internals}}
 +
==Introduction==
  
This page gives an overview of the LCL Carbon interface for Mac OS X and will help new developers.
+
{{Warning|With the release of macOS 10.15 Catalina in October 2019, Apple has removed all support for the 32 bit Carbon framework from the operating system in favour of the [[Cocoa Internals|64 bit Cocoa framework]]. Consequently, the Carbon widgetset is no longer being developed.}}
 +
 
 +
This page gives an overview of the LCL Carbon interface for macOS and will help new developers.
  
 
For installation and creating a first Carbon application refer to [[Carbon Interface]].
 
For installation and creating a first Carbon application refer to [[Carbon Interface]].
 +
 +
{{Other Interfaces}}
  
 
== Documentation about Carbon ==
 
== Documentation about Carbon ==
  
[http://developer.apple.com/documentation/Carbon Apple Carbon docs]
+
* [http://developer.apple.com/documentation/Carbon Apple Carbon docs]
  
[http://www.mactech.com/macintosh-c/downloads.html Carbon Book for download]
+
* [http://search.lists.apple.com Apple Mailing List search]
  
[http://www.carbondev.com/site/ Carbon Dev]
+
* [http://www.mactech.com/macintosh-c/downloads.html Carbon Book for download]
  
[http://www.oreilly.com/catalog/learncarbon "Learning Carbon" sample book chapter]
+
* [http://www.carbondev.com/site/ Carbon Dev]
  
Free Pascal's Carbon API unit is FPCMacOSAll.pas in /usr/local/share/fpcsrc/packages/extra/univint.
+
* [http://www.oreilly.com/catalog/learncarbon "Learning Carbon" sample book chapter]
 +
 
 +
* Free Pascal's Carbon API unit is FPCMacOSAll.pas in /usr/local/share/fpcsrc/packages/extra/univint.
  
 
== Carbon interface development basics ==
 
== Carbon interface development basics ==
  
* Target Mac OS X version is 10.4
+
* Target Mac Tiger version is 10.4
 
* Avoid using obsolete or deprecated APIs and functions (e. g. QuickDraw vs. ''Quartz 2D'')
 
* Avoid using obsolete or deprecated APIs and functions (e. g. QuickDraw vs. ''Quartz 2D'')
 
* Use object approach
 
* Use object approach
Line 37: Line 44:
 
== What needs to be done next? ==
 
== What needs to be done next? ==
  
{|BORDER="1" CELLSPACING="0"
+
See [http://www.freepascal.org/mantis/view_all_set.php?type=3&source_query_id=1017 Bug Tracker Carbon open issues]
!STYLE="background:#99D2FD;"|Item
+
 
!STYLE="background:#99D2FD;"|Note
+
== Carbon IDE Bugs ==
!STYLE="background:#99D2FD;"|Dependencies
+
 
!STYLE="background:#99D2FD;"|Responsible
+
{| class="wikitable"
|----
+
! Item !! Note !! Dependencies !! Responsible
|Mouse Capture releasing|| || ||
 
|----
 
|TBrush Patterns||CGPatternCreate|| ||
 
 
|----
 
|----
|StretchMaskBlt||Implement: ROP, stretch mode||||
+
|'...' buttons in dialogs||Now they are too large I think|| ||
 
|----
 
|----
|TCalendar||no counterpart|| ||
+
|OK/Cancel||Many dialogs have non-Mac check-X glyphs|| ||  
 
|----
 
|----
|TFontDialog||FPShowHideFontPanel|| ||[[User:Tombo|Tombo]]
+
||Menu bar||Too wide for 1024x768 display resolution|| ||
 
|----
 
|----
|TListView||CreateDataBrowserControl|| ||[[User:Tombo|Tombo]]
+
||Lazarus menu||Help About and app prefs (Environment options) should be accessible here|| ||
 
|----
 
|----
|TScrollBox, TCustomControl with scrollbars, TScrollingWinControl||HIScrollViewCreate|| || [[User:Tombo|Tombo]]
+
||Menus||Many missing or non-standard menu shortcuts:<BR>
|----
+
File New should be Cmd+N<BR>
|IDE form designer||kOverlayWindowClass|| ||
+
File Save As should be Shift+Cmd+S<BR>
|----
+
File Quit should be Cmd+Q<BR>
|TPageSetupDialog||PMSessionPageSetupDialog|| ||
+
Search Find should be Cmd+F<BR>
|----
+
Search Find Next should be Cmd+G<BR>
|TPrintDialog, TPrinterSetupDialog||PMSessionPrintDialog|| ||
+
Search Find Previous should be Shift+Cmd+G<BR>
 +
(Goto line and Procedure List need to be reassigned)<BR>
 +
Option+Cmd+F does not bring up Search Results<BR>
 +
F11 behaves weird!
 +
|| ||  
 
|}
 
|}
  
== Bugs ==
+
See [http://www.freepascal.org/mantis/view_all_set.php?type=3&source_query_id=1018 Bug Tracker Carbon IDE open issues]
 +
 
 +
== Implementation Details ==
 +
 
 +
=== Keyboard ===
 +
* Apple Command key is mapped to ssMeta
 +
* Apple Control key is mapped to ssCtrl
 +
* Apple Option key is mapped to its inscription, i.e. ssAlt
 +
* Virtual key codes mapping is not reliable (depends on keyboard language layout!)
 +
 
 +
=== Application ===
 +
 
 +
* Title: You cannot change it at runtime. You have to set it in Application Bundle.
 +
* OnDropFiles event is fired when file is dropped on application dock icon or opened via Finder if is associated. You have to enable this event in Application Bundle.
 +
 
 +
=== Drawing and measuring text precisely in parts ===
 +
 
 +
If you want to draw (via TextOut, TextRect) or measure (via TextWidth, TextHeight) text divided into various parts and rely it will be displayed same each time not depending on its division, you have to disable some default typographic features (like kerning, fractional positioning, ...) of Canvas. You can choose one of the following:
 +
* CarbonWidgetSet.SetTextFractional(Canvas, False); // from CarbonInt unit
 +
* TCarbonCustomControl(CustomControl.Handle).TextFractional := False; // from CarbonPrivate unit
 +
* TCarbonDeviceContext(Canvas.Handle)..TextFractional := False; // from CarbonCanvas unit
  
{|BORDER="1" CELLSPACING="0"
+
=== Screenshot taking ===
!STYLE="background:#FF9999;"|Item
+
 
!STYLE="background:#FF9999;"|Note
+
The only possible efficient way of taking a screenshot on macOS is using OpenGL. Apple provides a demonstration function which returns a CGImageRef with the screenshot. This function was converted to Pascal and is available on the glgrab.pas unit on the carbon interface directory. This function requires the Apple-specific parts of the Apple OpenGL headers, and those aren't yet on the FPC Packages, so they were translated and are located on lazarus/lcl/interfaces/carbon/opengl.pas until they are released on a stable Free Pascal.
!STYLE="background:#FF9999;"|Dependencies
+
 
!STYLE="background:#FF9999;"|Responsible
+
After obtaining a CGImageRef, the next step to implement the RawImage_fromDevice method is obtaining a local copy of it's pixel data. It isn't possible to directly access the bytes of a CGImageRef, so the image needs to be drawn to a CGContextRef which uses a memory area allocated by us as buffer. This method has the great advantage of converting from the internal format of the screenshot bytes to the very convenient ARGB, 32-bits depth, 8-bits per channel format that is default to LCL.
|----
+
 
|TCustomControl - keyboard focus|| || ||
+
=== Focusing ===
|----
+
 
|TCustomEdit.CharCase||Is ignored when typing text|| ||
+
 
|----
+
macOS has two possible ways of focusing: Full keyboard navigation (enabled with Accessibility options), Text field navigation (only controls that are to receive text input should be focused).
|TMemo.WordWrap||persistent bug, when word wrap is disabled the memo doesn't scroll to caret|| ||
+
Full keyboard navigation is the same as any other widgetset.
|----
+
 
|TMaskEdit||Every typed char is doubled|| ||
+
There's no way to say if control is text-input or not. Native OS controls will handle focus themselves. The Carbon Widgetset checks if bound LCLObject is SynEdit and will switch the focus to it.
|----
 
|TStringGird||Crashes sometimes when userinput is to fast|| ||
 
|}
 
  
== Carbon IDE Bugs ==
+
=== Canvas Clipping ===
  
{|BORDER="1" CELLSPACING="0"
+
Because Quartz 2D's clipping is decreasing, care must be taken for proper clipping region change.
!STYLE="background:#FF9999;"|Item
+
There should be no code, that changes CGContext's clip region directly. Carbon widget API's functions should be used instead.
!STYLE="background:#FF9999;"|Note
 
!STYLE="background:#FF9999;"|Dependencies
 
!STYLE="background:#FF9999;"|Responsible
 
|----
 
|Synedit||1. Font metrics 2. No caret || ||
 
|----
 
|Mouse||Wrong position is reported when mouse over component toolbar|| ||
 
|----
 
|PageControl||no arrows to switch tabs|| ||
 
|----
 
|ListView||IDE crash in Dialogs with TListView|| ||
 
|----
 
|Bitmap stretching||Help->About lazarus dialog show image bigger than need|| ||
 
|----
 
|'...' buttons in dialogs||When button is too small '...' text painted at the bottom of button|| ||
 
|}
 
  
 
== Compatibility issues ==
 
== Compatibility issues ==
  
=== Keyboard ===
+
These are things that will probably never be solved.
 +
 
 +
=== Mouse.CursorPos changing does not generate mouse (move) events ===
 +
 
 +
=== Release mouse capture is not supported ===
 +
 
 +
=== Command line parameters ===
 +
 
 +
Because Carbon applications are executed via Application Bundle, command line parameters are not passed. You have to use OnDropFiles event to detect openning associated files.
 +
 
 +
=== Shortcuts indication is not supported ===
 +
 
 +
=== Drawing on Canvas outside OnPaint event is not supported ===
 +
 
 +
=== Drawing on screen device context is not supported ===
 +
 
 +
=== TCustomControl.Color of clBtnFace makes its background transparent ===
 +
 
 +
=== TWinControl.Font fsStrikeOut is not supported ===
 +
 
 +
=== TForm ===
 +
 
 +
* Icon is not supported
 +
* ShowInTaskbar is not supported
 +
* TForm.top=0 is not good. Use TForm.top=23
 +
 
 +
=== TEdit.PasswordChar different then default is not supported ===
 +
 
 +
=== TMemo.WordWrap when is disabled, does not allow to scroll text horizontally ===
 +
 
 +
=== TListBox.Columns is not supported ===
 +
=== TComboBox ===
 +
 
 +
* DroppedDown does not show drop down list when style is csDropDownList
 +
* DropDownCount is not supported
 +
* Style: csSimple, csOwnerDrawFixed and csOwnerDrawVariable are not supported
 +
 
 +
=== TPanel.Bevelxxx: bvLowered and bvSpace are not supported ===
 +
=== TBitBtn.Spacing is not supported ===
 +
=== TTrackBar ===
 +
 
 +
* LineSize is not supported
 +
* ScalePos is not supported
 +
* TickMarks are not supported
 +
 
 +
=== TProgressBar ===
 +
 
 +
* BarShowText is not supported
 +
* Smooth is not supported
 +
* Step is not supported
 +
 
 +
=== TColorDialog.Title is not supported ===
 +
 
 +
=== macOS System (Windows' and Controls') Handles  ===
 +
 
 +
It’s some times necessary to access system windows or control handles directly. For example, you wish to use some system features that are not available (not yet implemented?) for LCL.
 +
It’s very common for LCL Windows developers (and Delphi developers) to use TControl.Handle property, since Handle is a system window handle for Win32 widgetset. It can be used with any system function.
 +
But it’s not so for Carbon widgetset. TControl.Handle would return handle native to widgetset not macOS. TControl.Handle would return TCarbonWidget class  (declared at CarbonDef unit). This’s a wrapper class, and you can use it to get system handle.
 +
 
 +
<syntaxhighlight lang="pascal">
 +
var
 +
AHiView: HiViewRef;
 +
begin
 +
...
 +
//this is incorrect way of getting system handle for Carbon widgetset
 +
//AHiView:= HiViewRef(Button1.Handle)
 +
 
 +
//this is correct way
 +
AHiView := TCarbonWidget(Button1.Handle).Widget;
 +
...
 +
end;
 +
</syntaxhighlight>
 +
 
 +
You should also note, that there’s difference in getting WindowRef in LCL versions.
 +
If you’re using Lazarus 0.9.26 or earlier you should get WindowRef in the following way:
 +
 
 +
<syntaxhighlight lang="pascal">
 +
var
 +
  MacWin: WindowRef;
 +
begin
 +
...
 +
MacWin := TCarbonWidget(Form1.Handle).Widget;
 +
...
 +
end;
 +
</syntaxhighlight>
 +
 
 +
If you’re using svn LCL version (latest trunk), then you should use the following way:
 +
 
 +
<syntaxhighlight lang="pascal">
 +
uses
 +
    ..CarbonPrivate..
 +
var
 +
  MacWin: WindowRef;
 +
begin
 +
...
 +
MacWin := TCarbonWindow(Form1.Handle).Window;
 +
...
 +
end;
 +
</syntaxhighlight>
  
* Apple Command key is mapped to ssCtrl per [http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html Apple Guidelines]
+
Keep in mind, that LCL is designed to be cross-platform library, and accessing system handles to use with system functions makes you program hardly portable. The way of getting system objects handle might also be changed in future.
* Apple control key is mapped to ssMeta
 
* Apple option key is mapped to its inscription, i.e. ssAlt
 
* Virtual key codes mapping (depends on keyboard language layout!)
 
* Shortcuts indication (ampersand)
 
  
=== Drawing on canvas outside OnPaint event ===
+
===TTrayIcon===
  
* won't be implemented
+
====Checking if the TTrayIcon menu is visible====
  
=== Drawing on screen device context===
+
Unfortunately Apple only added a facility to check menu visibility in Snow Leopard 10.6. To overcome this limitation in a simple way in previous versions one can use the following code, which should work in previous versions using a class method in TCarbonWSCustomTrayIcon:
  
* won't be implemented
+
<syntaxhighlight lang="pascal">
 +
uses
 +
  CarbonWSExtCtrls;
  
=== TControl.Color ===
+
...
  
* background of Carbon controls is transparent
+
begin
 +
  if TCarbonWSCustomTrayIcon.IsTrayIconMenuVisible(TrayIcon1) then Caption := 'Visible'
 +
  else Caption := 'Not visible';
 +
end;
 +
</syntaxhighlight>
  
 
== How to add a new control ==
 
== How to add a new control ==
Line 136: Line 245:
 
Its Carbon interface class is in lcl/interfaces/carbon/carbonwsbuttons.pp:
 
Its Carbon interface class is in lcl/interfaces/carbon/carbonwsbuttons.pp:
  
  TCarbonWSButton = class(TWSButton)
+
<syntaxhighlight lang="pascal">
  private
+
TCarbonWSButton = class(TWSButton)
  protected
+
private
  public
+
protected
    class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
+
public
  end;
+
  class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
 +
end;
 +
</syntaxhighlight>
  
 
Every WS class that actually implements something must be registered. See the initialization section at the end of the carbonwsXXX.pp unit:
 
Every WS class that actually implements something must be registered. See the initialization section at the end of the carbonwsXXX.pp unit:
  RegisterWSComponent(TCustomButton, TCarbonWSButton);
+
<syntaxhighlight lang="pascal">RegisterWSComponent(TCustomButton, TCarbonWSButton);</syntaxhighlight>
  
 
TCarbonWSButton overrides CreateHandle to create a Carbon button helper class called TCarbonButton in carbonprivate.pp, which really creates the button control in the Carbon and installs event handlers.
 
TCarbonWSButton overrides CreateHandle to create a Carbon button helper class called TCarbonButton in carbonprivate.pp, which really creates the button control in the Carbon and installs event handlers.

Latest revision as of 05:02, 4 August 2021

Deutsch (de) English (en)

macOSlogo.png

This article applies to macOS only.

See also: Multiplatform Programming Guide

Apple iOS new.svg

This article applies to iOS only.

See also: Multiplatform Programming Guide


Introduction

Warning-icon.png

Warning: With the release of macOS 10.15 Catalina in October 2019, Apple has removed all support for the 32 bit Carbon framework from the operating system in favour of the 64 bit Cocoa framework. Consequently, the Carbon widgetset is no longer being developed.

This page gives an overview of the LCL Carbon interface for macOS and will help new developers.

For installation and creating a first Carbon application refer to Carbon Interface.

Other Interfaces

Platform specific Tips

Interface Development Articles

Documentation about Carbon

  • Free Pascal's Carbon API unit is FPCMacOSAll.pas in /usr/local/share/fpcsrc/packages/extra/univint.

Carbon interface development basics

  • Target Mac Tiger version is 10.4
  • Avoid using obsolete or deprecated APIs and functions (e. g. QuickDraw vs. Quartz 2D)
  • Use object approach
  • Check Carbon calls result with OSError function
  • Assume UTF-8 encoded strings between LCL and Carbon widgetset (for future Lazarus Unicode support)

What is already working ?

Working components in the Carbon interface

What needs to be done next?

See Bug Tracker Carbon open issues

Carbon IDE Bugs

Item Note Dependencies Responsible
'...' buttons in dialogs Now they are too large I think
OK/Cancel Many dialogs have non-Mac check-X glyphs
Menu bar Too wide for 1024x768 display resolution
Lazarus menu Help About and app prefs (Environment options) should be accessible here
Menus Many missing or non-standard menu shortcuts:

File New should be Cmd+N
File Save As should be Shift+Cmd+S
File Quit should be Cmd+Q
Search Find should be Cmd+F
Search Find Next should be Cmd+G
Search Find Previous should be Shift+Cmd+G
(Goto line and Procedure List need to be reassigned)
Option+Cmd+F does not bring up Search Results
F11 behaves weird!

See Bug Tracker Carbon IDE open issues

Implementation Details

Keyboard

  • Apple Command key is mapped to ssMeta
  • Apple Control key is mapped to ssCtrl
  • Apple Option key is mapped to its inscription, i.e. ssAlt
  • Virtual key codes mapping is not reliable (depends on keyboard language layout!)

Application

  • Title: You cannot change it at runtime. You have to set it in Application Bundle.
  • OnDropFiles event is fired when file is dropped on application dock icon or opened via Finder if is associated. You have to enable this event in Application Bundle.

Drawing and measuring text precisely in parts

If you want to draw (via TextOut, TextRect) or measure (via TextWidth, TextHeight) text divided into various parts and rely it will be displayed same each time not depending on its division, you have to disable some default typographic features (like kerning, fractional positioning, ...) of Canvas. You can choose one of the following:

  • CarbonWidgetSet.SetTextFractional(Canvas, False); // from CarbonInt unit
  • TCarbonCustomControl(CustomControl.Handle).TextFractional := False; // from CarbonPrivate unit
  • TCarbonDeviceContext(Canvas.Handle)..TextFractional := False; // from CarbonCanvas unit

Screenshot taking

The only possible efficient way of taking a screenshot on macOS is using OpenGL. Apple provides a demonstration function which returns a CGImageRef with the screenshot. This function was converted to Pascal and is available on the glgrab.pas unit on the carbon interface directory. This function requires the Apple-specific parts of the Apple OpenGL headers, and those aren't yet on the FPC Packages, so they were translated and are located on lazarus/lcl/interfaces/carbon/opengl.pas until they are released on a stable Free Pascal.

After obtaining a CGImageRef, the next step to implement the RawImage_fromDevice method is obtaining a local copy of it's pixel data. It isn't possible to directly access the bytes of a CGImageRef, so the image needs to be drawn to a CGContextRef which uses a memory area allocated by us as buffer. This method has the great advantage of converting from the internal format of the screenshot bytes to the very convenient ARGB, 32-bits depth, 8-bits per channel format that is default to LCL.

Focusing

macOS has two possible ways of focusing: Full keyboard navigation (enabled with Accessibility options), Text field navigation (only controls that are to receive text input should be focused). Full keyboard navigation is the same as any other widgetset.

There's no way to say if control is text-input or not. Native OS controls will handle focus themselves. The Carbon Widgetset checks if bound LCLObject is SynEdit and will switch the focus to it.

Canvas Clipping

Because Quartz 2D's clipping is decreasing, care must be taken for proper clipping region change. There should be no code, that changes CGContext's clip region directly. Carbon widget API's functions should be used instead.

Compatibility issues

These are things that will probably never be solved.

Mouse.CursorPos changing does not generate mouse (move) events

Release mouse capture is not supported

Command line parameters

Because Carbon applications are executed via Application Bundle, command line parameters are not passed. You have to use OnDropFiles event to detect openning associated files.

Shortcuts indication is not supported

Drawing on Canvas outside OnPaint event is not supported

Drawing on screen device context is not supported

TCustomControl.Color of clBtnFace makes its background transparent

TWinControl.Font fsStrikeOut is not supported

TForm

  • Icon is not supported
  • ShowInTaskbar is not supported
  • TForm.top=0 is not good. Use TForm.top=23

TEdit.PasswordChar different then default is not supported

TMemo.WordWrap when is disabled, does not allow to scroll text horizontally

TListBox.Columns is not supported

TComboBox

  • DroppedDown does not show drop down list when style is csDropDownList
  • DropDownCount is not supported
  • Style: csSimple, csOwnerDrawFixed and csOwnerDrawVariable are not supported

TPanel.Bevelxxx: bvLowered and bvSpace are not supported

TBitBtn.Spacing is not supported

TTrackBar

  • LineSize is not supported
  • ScalePos is not supported
  • TickMarks are not supported

TProgressBar

  • BarShowText is not supported
  • Smooth is not supported
  • Step is not supported

TColorDialog.Title is not supported

macOS System (Windows' and Controls') Handles

It’s some times necessary to access system windows or control handles directly. For example, you wish to use some system features that are not available (not yet implemented?) for LCL. It’s very common for LCL Windows developers (and Delphi developers) to use TControl.Handle property, since Handle is a system window handle for Win32 widgetset. It can be used with any system function. But it’s not so for Carbon widgetset. TControl.Handle would return handle native to widgetset not macOS. TControl.Handle would return TCarbonWidget class (declared at CarbonDef unit). This’s a wrapper class, and you can use it to get system handle.

var
 AHiView: HiViewRef;
begin
...
//this is incorrect way of getting system handle for Carbon widgetset
//AHiView:= HiViewRef(Button1.Handle)

//this is correct way
AHiView := TCarbonWidget(Button1.Handle).Widget;
...
end;

You should also note, that there’s difference in getting WindowRef in LCL versions. If you’re using Lazarus 0.9.26 or earlier you should get WindowRef in the following way:

var
  MacWin: WindowRef;
begin
...
MacWin := TCarbonWidget(Form1.Handle).Widget;
...
end;

If you’re using svn LCL version (latest trunk), then you should use the following way:

uses
    ..CarbonPrivate..
var
  MacWin: WindowRef;
begin
...
MacWin := TCarbonWindow(Form1.Handle).Window;
...
end;

Keep in mind, that LCL is designed to be cross-platform library, and accessing system handles to use with system functions makes you program hardly portable. The way of getting system objects handle might also be changed in future.

TTrayIcon

Checking if the TTrayIcon menu is visible

Unfortunately Apple only added a facility to check menu visibility in Snow Leopard 10.6. To overcome this limitation in a simple way in previous versions one can use the following code, which should work in previous versions using a class method in TCarbonWSCustomTrayIcon:

uses
  CarbonWSExtCtrls;

...

begin
  if TCarbonWSCustomTrayIcon.IsTrayIconMenuVisible(TrayIcon1) then Caption := 'Visible'
  else Caption := 'Not visible';
end;

How to add a new control

For example TButton.

TButton is defined in lcl/buttons.pp. This is the platform independent part of the LCL, which is used by the normal LCL programmer.

Its widgetset class is in lcl/widgetset/wsbuttons.pp. This is the platform independent base for all widgetsets (carbon, gtk, win32, ...).

Its Carbon interface class is in lcl/interfaces/carbon/carbonwsbuttons.pp:

TCarbonWSButton = class(TWSButton)
private
protected
public
  class function  CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
end;

Every WS class that actually implements something must be registered. See the initialization section at the end of the carbonwsXXX.pp unit:

RegisterWSComponent(TCustomButton, TCarbonWSButton);

TCarbonWSButton overrides CreateHandle to create a Carbon button helper class called TCarbonButton in carbonprivate.pp, which really creates the button control in the Carbon and installs event handlers.