Sign in Join
Wiki copytemporary

Cocoa Internals/Widgetset: what changed

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

OldNewLine
11## Handles
22
33THANDLE - an opaque reference value that's being generated during the .CreateHandle() call of a particular Widgetset class. THANDLE is the value that's used to interface with a control. Using the value a widgetset recognizes a particular control.
44
55Most of the Widget interface methods accept TWinControl as a parameter. It's assumed that the Handle property of the control would be used to back reference the actual control. The property stores the value received from the CreateHandle() call made earlier. The HandleAllocated property can be checked in order to know if handle has been previously created or not. If handle has not been created it's expected that the method can fail (returning the proper failure information. Exceptions are not expected?).
66
77Overall LCL Handles refer to complex controls. For example, HANDLE can refer to a Memo control that's capable of editing AND scrolling text as needed.
88
99Cocoa's composite engine operates controls on a lower level scope. With the Memo example, there's not a single control that does both: text editing and scrolling. Instead there are two separate controls: NSTextView and NSScrollView (both are descendants of NSView). But LCL expects only one value to be returned as a handle.
1010
1111The common rule is the following: the outermost bounds (aka container) control is returned as the handle. Thus in case of Memo, two NSViews are allocated: NSTextView and NSScrollView. But the outermost NSScrollView is returned as theHANDLE. All TCustomMemoWSControl methods are aware of that and treat the handle as such. For example:
1212
1313- if paste action is required, the handle would be used as **NSScrollView** and then it's **documentview** would be used to get **NSTextView to call for**paste'''.
1414- if bounds changes are required (moving, resizing) then the sizes are changed directly for the NSView referenced by HANDLE. (It's assumed that the view would automatically resize its controls. In case of TMemo, NSScrollView would adjust size of NSTextView, if wordwrapping is off).
1515- Forms (TForm), that generally correspond to NSWindow, also return their handle as NSView. That view represents the root NSView of a form. However, CocoaWS API's know that and call the necessary NSWindow methods where applicable.
1616
1717HandleViews are stored within Callback object that's being created for each CreateHandle() method.
1818
1919### Handles Reference
2020
2121- Window handle (HWND) is always NSView.
2222 - TCustomWSForm it is content NSView.
2323 - Any control that has scroll bars (i.e. TCustomWSList) the it its the embedding NSScrollView (TCocoaScrollView)
2424
2525The table below gives a reference of LCL controls and their implementing classes. Note that the LCL handle returned is not always the same as the implementing class. This applies to controls that have to embedded in a scrollbox.
2626
27-<table>
28-<thead>
29-<tr>
30-<th><p>LCL Control</p></th>
31-<th><p>WS Part</p></th>
32-<th><p>Cocoa Class (NS class)</p></th>
33-<th><p>View Returned as LCL Handle</p></th>
34-<th><p>Notes</p></th>
35-</tr>
36-</thead>
37-<tbody>
38-<tr>
39-<td><p>TScrollBar</p></td>
40-<td><p>Std</p></td>
41-<td><p>TCocoaScrollBar (NSScrollBar)</p></td>
42-<td><p><em>self</em></p></td>
43-<td></td>
44-</tr>
45-<tr>
46-<td><p>TGroupBox</p></td>
47-<td><p>Std</p></td>
48-<td><p>TCocoaGroupBox (NSBox)</p></td>
49-<td><p><em>self</em></p></td>
50-<td><p>There's also a content view created to hold all the child controls within the box</p></td>
51-</tr>
52-<tr>
53-<td><p>TComboBox</p></td>
54-<td><p>Std</p></td>
55-<td><p>TCocoaComboBox (NSComboBox)</p>
56-<p>or</p>
57-<p>TCocoaReadOnlyComboBox (NSPopUpButton)</p></td>
58-<td><p><em>self</em></p></td>
59-<td><p>The actual type is defined by the style of LCL combobox (readonly vs editable)</p></td>
60-</tr>
61-<tr>
62-<td><p>TListBox</p></td>
63-<td><p>Std</p></td>
64-<td><p>TCocoaTableView (NSTableView)</p></td>
65-<td><p>NSScrollView</p></td>
66-<td><p>The behavior of TListbox is defined by the callback object TLCLListBoxCallback assigned to TCocoaTableView.</p></td>
67-</tr>
68-<tr>
69-<td><p>TEdit</p></td>
70-<td><p>Std</p></td>
71-<td><p>TCocoaTextField (NSTextField)</p></td>
72-<td><p><em>self</em></p></td>
73-<td><p>TCocoaTextField itself is readonly static field. The editing capabilities are implemented by TCocoaFieldEditor, which is driven by AppKit "editing" schema</p></td>
74-</tr>
75-<tr>
76-<td><p>TMemo</p></td>
77-<td><p>Std</p></td>
78-<td><p>TCocoaTextView (NSTextView)</p></td>
79-<td><p>NSScrollView</p></td>
80-<td><p>Lines property is implemented via TCocoaMemoStrings</p></td>
81-</tr>
82-<tr>
83-<td><p>TButton</p></td>
84-<td><p>Std</p></td>
85-<td><p>TCocoaButton (NSButton)</p></td>
86-<td><p><em>self</em></p></td>
87-<td></td>
88-</tr>
89-<tr>
90-<td><p>TCheckBox</p></td>
91-<td><p>Std</p></td>
92-<td><p>TCocoaButton (NSButton)</p></td>
93-<td><p><em>self</em></p></td>
94-<td><p>Checkbox is still a button but with a different Bezel</p></td>
95-</tr>
96-<tr>
97-<td><p>TToggleBox</p></td>
98-<td><p>Std</p></td>
99-<td><p>TCocoaButton (NSButton)</p></td>
100-<td><p><em>self</em></p></td>
101-<td></td>
102-</tr>
103-<tr>
104-<td><p>TRadioButton</p></td>
105-<td><p>Std</p></td>
106-<td><p>TCocoaButton (NSButton)</p></td>
107-<td><p><em>self</em></p></td>
108-<td><p>Radiobutton is still a button but with a different Bezel</p></td>
109-</tr>
110-<tr>
111-<td><p>TStaticText</p></td>
112-<td><p>Std</p></td>
113-<td><p>TCocoaTextField (NSTextField)</p></td>
114-<td><p><em>self</em></p></td>
115-<td><p>This field doesn't allow editor to be enabled</p></td>
116-</tr>
117-<tr>
118-<td><p>[[TTrackBar]]</p></td>
119-<td><p>Com</p></td>
120-<td><p>[[Cocoa Internals/Buttons|TCocoaSlider]] (NSSlider)</p></td>
121-<td><p><em>self</em></p></td>
122-<td></td>
123-</tr>
124-<tr>
125-<td></td>
126-<td></td>
127-<td></td>
128-<td></td>
129-<td></td>
130-</tr>
131-</tbody>
132-</table>
27+**LCL Control**
28+
29+**WS Part**
30+
31+**Cocoa Class (NS class)**
32+
33+**View Returned as LCL Handle**
34+
35+**Notes**
36+
37+TScrollBar
38+
39+Std
40+
41+TCocoaScrollBar (NSScrollBar)
42+
43+*self*
44+
45+TGroupBox
46+
47+Std
48+
49+TCocoaGroupBox (NSBox)
50+
51+*self*
52+
53+There's also a content view created to hold all the child controls within the box
54+
55+TComboBox
56+
57+Std
58+
59+TCocoaComboBox (NSComboBox)
60+
61+or
62+
63+TCocoaReadOnlyComboBox (NSPopUpButton)
64+
65+*self*
66+
67+The actual type is defined by the style of LCL combobox (readonly vs editable)
68+
69+TListBox
70+
71+Std
72+
73+TCocoaTableView (NSTableView)
74+
75+NSScrollView
76+
77+The behavior of TListbox is defined by the callback object TLCLListBoxCallback assigned to TCocoaTableView.
78+
79+TEdit
80+
81+Std
82+
83+TCocoaTextField (NSTextField)
84+
85+*self*
86+
87+TCocoaTextField itself is readonly static field. The editing capabilities are implemented by TCocoaFieldEditor, which is driven by AppKit "editing" schema
88+
89+TMemo
90+
91+Std
92+
93+TCocoaTextView (NSTextView)
94+
95+NSScrollView
96+
97+Lines property is implemented via TCocoaMemoStrings
98+
99+TButton
100+
101+Std
102+
103+TCocoaButton (NSButton)
104+
105+*self*
106+
107+TCheckBox
108+
109+Std
110+
111+TCocoaButton (NSButton)
112+
113+*self*
114+
115+Checkbox is still a button but with a different Bezel
116+
117+TToggleBox
118+
119+Std
120+
121+TCocoaButton (NSButton)
122+
123+*self*
124+
125+TRadioButton
126+
127+Std
128+
129+TCocoaButton (NSButton)
130+
131+*self*
132+
133+Radiobutton is still a button but with a different Bezel
134+
135+TStaticText
136+
137+Std
138+
139+TCocoaTextField (NSTextField)
140+
141+*self*
142+
143+This field doesn't allow editor to be enabled
144+
145+[[TTrackBar]]
146+
147+Com
148+
149+[[Cocoa Internals/Buttons|TCocoaSlider]] (NSSlider)
150+
151+*self*
133152
134153## Focusing
135154
136155That has important impact of FOCUS-ing. Cocoa doesn't operate the term "focused" instead it's using terms "firstRepsonder" and "key" view/window. Generally focused control corresponds to Cocoa's "firstResponder". The NSResponder object (typically NSView) is the first object that would handle key or mouse events. However, this is not the case for composed controls. TMemo is a combination of NSScrollView and NSTextField. NSScrollView is used as a handle. If, NSTextField would be the firstRepsonder, CocoaWS needs to return NSScrollView as focused HANDLE.
137156
138157The same approach is applicable in reverse. If SetFocus is made for the HANDLE that represents NSScrollView with NSTextField inside. NSTextField should actually become Cocoa's firstResponder.
139158
140159The expected order of events is:
141160
142161- LM_KILLFOCUS
143162- LM_SETFOCUS
144163
145164Note that unlike WinAPI WM_KILLFOCUS, LM_KILLFOCUS doesn't provide the information about "the next suggested" control to be focused. For controls that have some sort of editors (i.e. TTreeView with a node editor (TEdit) active) such approach is causing to switch focus to TForm (the hosting form), for the next focus control selection.
146165
147166The focus switch notification is handled in TCocoaWindow makeFirstResponder call. Due to problems with the recursive calls of changing the focus, the current order of events is:
148167
149168- LM_SETFOCUS
150169- LM_KILLFOCUS
151170
152171(for Cocoa WS)
153172
154173#### Need of Window
155174
156175The "firstResponder" is a property of a window. Thus a view can become a "firstResponder" only if it's within NSWindow's view hierarchy. This is important for complex controls, such as a TabControl. It manages multiple child views (each view for a tab). Only one view is visible at a time. All over views are actually DETACHED from NSWindow hierarchy. (while from LCL perspective they are still children of TForm). When switching between tabs a notification about a successful switch should only be delivered when a new view is in the Window hierarchy.
157176
158177#### Ignoring System Setting
159178
160179LCL basic logic is to focus every control that is a tab stoppable (which is every TWinControl by default) user. Where in macOS there's a system setting of **Full Keyboard Access** (which is off by default). If the setting is off then macOS acts similar to what LCL does. If it's on only "keyboard input" controls are "tab-reachable" text fields (including editable combo-boxes) and lists. Buttons, scrollers are skipped from tabbing. LCL doesn't currently support limited tabbing.
161180
162181#### Focus Ring
163182
164183Focus Ring is not drawn for controls with **BorderStyle** set to **bsNone**. (that allows to visually "hide" controls)
165184
166185If global variable **CocoaHideFocusNoBorder** is set to false, then the focus remains unchanged.
167186
168187## Cursors
169188
170189Widgetset cursors are based on **NSCursor** class. Which very nice and convenient to use. Cocoa however, doesn't provide some of the cursors that do exist in windows/LCL. For example: diagonal resize. Diagonal cursors are generated by rotation of the horizontal cursors.
171190
172191## User Prompts and Modal Dialogs
173192
174193Most of the dialogs are based on **NSModal** class.
175194
176195With the switch of rendering engine to layered drawing (effective macOS 10.14), an attempt to show a modal dialog during rendering (or any other stage of animation. I.e. "Activation") would cause an exception:
177196
178197`Application Specific Information:`\
179198`*** Terminating app due to uncaught exception 'NSGenericException', reason: '-[NSAlert runModal]`\
180199`may not be  invoked inside of transaction begin/commit pair, or inside of transaction commit `\
181200`(usually this means it was invoked inside of a view's -drawRect: method.)'`
182201
183202However, if the error dialog is shown as a "sheet" then the error doesn't occur.
184203
185204## See Also
186205
187206- [[Cocoa Internals]]
188207
189208---
190209*From the Free Pascal wiki, page "Cocoa Internals/Widgetset", as it stood on 2020-10-05 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).*
191210Category: Cocoa
192211Category: macOS

Back to history