Sign in Join
Wiki copytemporary

Carbon interface internals: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Carbon interface internals

OldNewLine
1+## Introduction
2+
3+> **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.
4+
5+This page gives an overview of the LCL Carbon interface for macOS and will help new developers.
6+
7+For installation and creating a first Carbon application refer to [[Carbon Interface]].
8+
9+## Documentation about Carbon
10+
11+- [Apple Carbon docs](http://developer.apple.com/documentation/Carbon)
12+
13+- [Apple Mailing List search](http://search.lists.apple.com)
14+
15+- [Carbon Book for download](http://www.mactech.com/macintosh-c/downloads.html)
16+
17+- [Carbon Dev](http://www.carbondev.com/site/)
18+
19+- ["Learning Carbon" sample book chapter](http://www.oreilly.com/catalog/learncarbon)
20+
21+- Free Pascal's Carbon API unit is FPCMacOSAll.pas in /usr/local/share/fpcsrc/packages/extra/univint.
22+
23+## Carbon interface development basics
24+
25+- Target Mac Tiger version is 10.4
26+- Avoid using obsolete or deprecated APIs and functions (e. g. QuickDraw vs. *Quartz 2D*)
27+- Use object approach
28+- Check Carbon calls result with OSError function
29+- Assume UTF-8 encoded strings between LCL and Carbon widgetset (for future Lazarus Unicode support)
30+
31+## What is already working ?
32+
33+- Features - see [[Roadmap|Roadmap#Status_of_features_on_each_widgetset]]
34+- Forms and controls - see [[Roadmap|Roadmap#Status_of_components_on_each_widgetset]]
35+- Creating TOpenGLControl with AGL context (see components/opengl/)
36+- Mouse events
37+- Keyboard events
38+
39+<figure>
40+<img src="Carbon_interface_show_case.png" title="Working components in the Carbon interface" width="640" />
41+<figcaption>Working components in the Carbon interface</figcaption>
42+</figure>
43+
44+## What needs to be done next?
45+
46+See [Bug Tracker Carbon open issues](http://www.freepascal.org/mantis/view_all_set.php?type=3&source_query_id=1017)
47+
48+## Carbon IDE Bugs
49+
50+<table>
51+<thead>
52+<tr>
53+<th>Item</th>
54+<th>Note</th>
55+<th>Dependencies</th>
56+<th>Responsible</th>
57+</tr>
58+</thead>
59+<tbody>
60+<tr>
61+<td>'...' buttons in dialogs</td>
62+<td>Now they are too large I think</td>
63+<td></td>
64+<td></td>
65+</tr>
66+<tr>
67+<td>OK/Cancel</td>
68+<td>Many dialogs have non-Mac check-X glyphs</td>
69+<td></td>
70+<td></td>
71+</tr>
72+<tr>
73+<td>|Menu bar</td>
74+<td>Too wide for 1024x768 display resolution</td>
75+<td></td>
76+<td></td>
77+</tr>
78+<tr>
79+<td>|Lazarus menu</td>
80+<td>Help About and app prefs (Environment options) should be accessible here</td>
81+<td></td>
82+<td></td>
83+</tr>
84+<tr>
85+<td>|Menus</td>
86+<td>Many missing or non-standard menu shortcuts:<br />
87+File New should be Cmd+N<br />
88+File Save As should be Shift+Cmd+S<br />
89+File Quit should be Cmd+Q<br />
90+Search Find should be Cmd+F<br />
91+Search Find Next should be Cmd+G<br />
92+Search Find Previous should be Shift+Cmd+G<br />
93+(Goto line and Procedure List need to be reassigned)<br />
94+Option+Cmd+F does not bring up Search Results<br />
95+F11 behaves weird!</td>
96+<td>|</td>
97+<td></td>
98+</tr>
99+</tbody>
100+</table>
101+
102+See [Bug Tracker Carbon IDE open issues](http://www.freepascal.org/mantis/view_all_set.php?type=3&source_query_id=1018)
103+
104+## Implementation Details
105+
106+### Keyboard
107+
108+- Apple Command key is mapped to ssMeta
109+- Apple Control key is mapped to ssCtrl
110+- Apple Option key is mapped to its inscription, i.e. ssAlt
111+- Virtual key codes mapping is not reliable (depends on keyboard language layout!)
112+
113+### Application
114+
115+- Title: You cannot change it at runtime. You have to set it in Application Bundle.
116+- 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.
117+
118+### Drawing and measuring text precisely in parts
119+
120+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:
121+
122+- CarbonWidgetSet.SetTextFractional(Canvas, False); // from CarbonInt unit
123+- TCarbonCustomControl(CustomControl.Handle).TextFractional := False; // from CarbonPrivate unit
124+- TCarbonDeviceContext(Canvas.Handle)..TextFractional := False; // from CarbonCanvas unit
125+
126+### Screenshot taking
127+
128+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.
129+
130+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.
131+
132+### Focusing
133+
134+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.
135+
136+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.
137+
138+### Canvas Clipping
139+
140+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.
141+
142+## Compatibility issues
143+
144+These are things that will probably never be solved.
145+
146+### Mouse.CursorPos changing does not generate mouse (move) events
147+
148+### Release mouse capture is not supported
149+
150+### Command line parameters
151+
152+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.
153+
154+### Shortcuts indication is not supported
155+
156+### Drawing on Canvas outside OnPaint event is not supported
157+
158+### Drawing on screen device context is not supported
159+
160+### TCustomControl.Color of clBtnFace makes its background transparent
161+
162+### TWinControl.Font fsStrikeOut is not supported
163+
164+### TForm
165+
166+- Icon is not supported
167+- ShowInTaskbar is not supported
168+- TForm.top=0 is not good. Use TForm.top=23
169+
170+### TEdit.PasswordChar different then default is not supported
171+
172+### TMemo.WordWrap when is disabled, does not allow to scroll text horizontally
173+
174+### TListBox.Columns is not supported
175+
176+### TComboBox
177+
178+- DroppedDown does not show drop down list when style is csDropDownList
179+- DropDownCount is not supported
180+- Style: csSimple, csOwnerDrawFixed and csOwnerDrawVariable are not supported
181+
182+### TPanel.Bevelxxx: bvLowered and bvSpace are not supported
183+
184+### TBitBtn.Spacing is not supported
185+
186+### TTrackBar
187+
188+- LineSize is not supported
189+- ScalePos is not supported
190+- TickMarks are not supported
191+
192+### TProgressBar
193+
194+- BarShowText is not supported
195+- Smooth is not supported
196+- Step is not supported
197+
198+### TColorDialog.Title is not supported
199+
200+### macOS System (Windows' and Controls') Handles
201+
202+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.
203+
204+``` pascal
205+var
206+ AHiView: HiViewRef;
207+begin
208+...
209+//this is incorrect way of getting system handle for Carbon widgetset
210+//AHiView:= HiViewRef(Button1.Handle)
211+
212+//this is correct way
213+AHiView := TCarbonWidget(Button1.Handle).Widget;
214+...
215+end;
216+```
217+
218+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:
219+
220+``` pascal
221+var
222+ MacWin: WindowRef;
223+begin
224+...
225+MacWin := TCarbonWidget(Form1.Handle).Widget;
226+...
227+end;
228+```
229+
230+If you’re using svn LCL version (latest trunk), then you should use the following way:
231+
232+``` pascal
233+uses
234+ ..CarbonPrivate..
235+var
236+ MacWin: WindowRef;
237+begin
238+...
239+MacWin := TCarbonWindow(Form1.Handle).Window;
240+...
241+end;
242+```
243+
244+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.
245+
246+### TTrayIcon
247+
248+#### Checking if the TTrayIcon menu is visible
249+
250+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:
251+
252+``` pascal
253+uses
254+ CarbonWSExtCtrls;
255+
256+...
257+
258+begin
259+ if TCarbonWSCustomTrayIcon.IsTrayIconMenuVisible(TrayIcon1) then Caption := 'Visible'
260+ else Caption := 'Not visible';
261+end;
262+```
263+
264+## How to add a new control
265+
266+For example TButton.
267+
268+TButton is defined in lcl/buttons.pp. This is the platform independent part of the LCL, which is used by the normal LCL programmer.
269+
270+Its widgetset class is in lcl/widgetset/wsbuttons.pp. This is the platform independent base for all widgetsets (carbon, gtk, win32, ...).
271+
272+Its Carbon interface class is in lcl/interfaces/carbon/carbonwsbuttons.pp:
273+
274+``` pascal
275+TCarbonWSButton = class(TWSButton)
276+private
277+protected
278+public
279+ class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
280+end;
281+```
282+
283+Every WS class that actually implements something must be registered. See the initialization section at the end of the carbonwsXXX.pp unit:
284+
285+``` pascal
286+RegisterWSComponent(TCustomButton, TCarbonWSButton);
287+```
288+
289+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.
290+
291+---
292+*From the Free Pascal wiki, page "Carbon interface internals", as it stood on 2021-08-04 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history