API — ICoreEssentials/UI/Backends/AppKit/Widgets
The public contract of 16 header(s) under ICoreEssentials/UI/Backends/AppKit/Widgets — 12 class/struct definition(s), 45 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.
ICoreAppKitEditKeys.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitEditKeys.h
⚠⚠ THE FOUR CLIPBOARD GESTURES ARE NOT FREE ON THIS PLATFORM, AND NOTHING IN AppKit TELLS YOU SO. ⌘X / ⌘C / ⌘V / ⌘A are KEY EQUIVALENTS, not keystrokes: -[NSTextView keyDown:] never sees them, because -[NSWindow sendEvent:] routes a Command-modified key-down through -performKeyEquivalent: instead. What answers that message in a normal Cocoa application is the STANDARD EDIT MENU -- the Cut/Copy/Paste/Select All rows a nib puts in the main menu, whose targets are First Responder -- and an application that builds its own in- window menu bar (ICoreMenuBar, which is a widget here) has none. So every text surface in the product was silently missing the four gestures every user on this platform has in their fingers.
Measured before it was written, on the real seats:
textedit Cmd+A, Cmd+C -> pasteboard unchanged
Declares no class of its own — see the file.
ICoreAppKitItemDelegateAccess.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitItemDelegateAccess.h
ICoreItemDelegate's toolkit half on this backend, as an IMPL-SIDE header.
⚠ This is not part of the public surface and must not be included from one. It exists because TWO files in this zone need the Impl complete: the delegate's own seat defines it, and every item VIEW has to call its three hooks while painting a row. Same precedent and same reasoning as UI/Backends/Qt/Widgets/ICoreStandardItemImpl.h and Values/ICoreAnimationAccess.h -- the access lives in an impl-side header rather than in the zone's shared native-handle header, because nothing outside these files needs it.
A nested class may be DEFINED outside its enclosing class as long as it was DECLARED inside, which is what
class Impl;in ICoreItemDelegate.h does. Being nested is also what makes this file possible at all: the three hooks are PROTECTED, and a nested class has its enclosing class's access -- so the
ICoreItemDelegateHooks#
ICoreAppKitItemDelegateAccess.h:49 · class · 4 declaration(s)
⚠ WHAT A VIEW ACTUALLY HOLDS, AND WHY IT IS THIS RATHER THAN THE Impl.
class ICoreItemDelegateHooks {
public:
virtual ~ICoreItemDelegateHooks() = default;
// The three hooks, forwarded. Non-const because the hooks are: an override
// is allowed to keep a per-paint cache, and the Qt seat had to const_cast
// its way to the same place before the conversion removed the need.
virtual bool paint(ICorePainter& painter, const ICoreItemRenderContext& context) = 0;
virtual ICoreSizeF sizeHint(const ICoreItemRenderContext& context) = 0;
virtual ICoreColor selectedTextColorFor(const ICoreItemRenderContext& context) = 0;
};
};
ICoreItemDelegate#
ICoreAppKitItemDelegateAccess.h:62 · class · bases :Impl : public ICoreItemDelegateHooks · 4 declaration(s)
class ICoreItemDelegate : :Impl : public ICoreItemDelegateHooks {
public:
explicit Impl(ICoreItemDelegate& owner);
bool paint(ICorePainter& painter, const ICoreItemRenderContext& context) override;
ICoreSizeF sizeHint(const ICoreItemRenderContext& context) override;
ICoreColor selectedTextColorFor(const ICoreItemRenderContext& context) override;
ICoreItemDelegate* m_owner;
};
};
ICoreAppKitLayout.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitLayout.h
Where the portable layout engine meets the native views: the engine says what frame each item gets, and these functions put the views there.
⚠ THIS FILE IS DELIBERATELY THIN, AND ITS THINNESS IS THE POINT. Every decision -- how the surplus is split, what a spacer absorbs, where the remainder pixel goes, how a label column is sized -- was made once in the portable engine and is TESTED there with no toolkit at all. If this file grew arithmetic of its own, that arithmetic would be the part no other backend could reuse and the part only an on-screen test could check. So it walks two vectors in step and calls setFrame.
The engine's frames are already in the parent's coordinates, y-down and top-left, and the view base is flipped, so there is no conversion here either. A backend that needed one would put it in ITS applier, not in the
ICoreAppKitLayoutNode#
ICoreAppKitLayout.h:73 · struct · 1 declaration(s)
-- nested layouts -------------------------------------------------------- ⚠ NESTING IS THE COMMON CASE, NOT AN EXTRA.
struct ICoreAppKitLayoutNode {
public:
// How this node is sized by its parent's distribution. For a nested
// layout this is the layout's own share -- stretch, minimum, preferred --
// not its children's.
ICoreLayoutItem item;
// Leaf: the view to position. Null with no children means a spacer.
ICoreAppKitView* view = nullptr;
// Nested: when `children` is non-empty this node is a layout, `view` is
// ignored, and `box` says how its children are arranged inside the frame
// the parent gave it.
ICoreBoxLayoutSpec box;
std::vector<ICoreAppKitLayoutNode> children;
// Nested, the OTHER way: a layout that is not a box. `children`/`box`
// above describes a box inside a box, which is the shape this file could
// express when it was written -- and 35 call sites nest, of which the ones
// putting a GRID or a FORM inside a box have no box spec to give.
//
// ⚠ SO A NODE CAN BE HANDED A RECTANGLE INSTEAD OF BEING DESCRIBED. When
// this is set the node is a layout of unknown kind: it gets a frame like
// anything else and is then asked to fill it, which is the one thing every
// layout can do whatever its kind. `children` wins if both are set, so the
// pure-box path is untouched.
std::function<void(const ICoreLayoutRect&)> nested;
};
};
ICoreAppKitPointerMonitor.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitPointerMonitor.h
ONE process-wide monitor for application-level pointer events, shared by every subscriber.
IMPLEMENTATION SIDE ONLY -- include from a .mm inside UI/Backends/AppKit/.
⚠ WHY THIS EXISTS AT ALL. Two of ICoreWidget's watches are APPLICATION-WIDE rather than per-target: watchOutsidePointerPresses (a popup dismissing itself when a press lands anywhere else) and watchApplicationPointerMoves. Qt implements both by installing a QObject event filter on the application. AppKit has no event filter; the equivalent is +[NSEvent addLocalMonitorForEventsMatchingMask:handler:].
⚠ AND IT IS ONE MONITOR, DELIBERATELY, NOT ONE PER WIDGET. Every popup in the tree wants the outside-press watch, so a monitor per subscriber means N
File-scope declarations#
// `globalPos` is in the wrapper's screen convention: top-left origin, y DOWN.
using ICoreAppKitPointerObserver = std::function<void(double globalX, double globalY)>;
ICoreAppKitScrollView.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitScrollView.h
Backend-internal. Include from a .mm inside UI/Backends/AppKit/ only.
The NSScrollView every scrolling seat in this backend builds, with the two wheel behaviours AppKit does not give one.
⚠⚠ 1. A PANE THAT ONLY SCROLLS SIDEWAYS TAKES AN ORDINARY WHEEL SIDEWAYS. AppKit maps a vertical notch to a horizontal scroll only when Shift is held; a mouse with one wheel over a pane with only a horizontal range therefore does nothing at all, which reads as a pane that is broken rather than as one that wants a modifier. Every other toolkit this tree is measured against forwards the notch to the axis that exists.
⚠⚠ 2. A WHEEL THE PANE CANNOT USE GOES TO WHATEVER ENCLOSES IT -- AND ONLY THEN. NSScrollView swallows the whole gesture: at the top of its range it
Declares no class of its own — see the file.
ICoreAppKitSplitterAccess.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitSplitterAccess.h
The grab bar's seat, for a test that has to click on one.
⚠ IT LIVES HERE AND NOT ON ICoreSplitter, and the reason is the header surface rule read forwards rather than as a formality.
ICoreSplitter.his a PUBLIC header of the platform SDK: everything declared in it is API a consumer sees and the docs generator publishes. A grab bar is not part of that contract on any backend -- the Qt seat has no such object to hand out -- so agrabBarForTest()there would be this backend's implementation detail promoted into the product's surface, on every platform, forever.A free function declared here and DEFINED inside
ICoreSplitter.cpp(whereICoreSplitter::Implis complete) reaches exactly as far as it needs to and no further: the declaration is inside the AppKit zone, so nothing outside the backend can even name it. This is the shapeICoreAppKitNativeHandleAccess.h
Declares no class of its own — see the file.
ICoreAppKitSplitterCore.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitSplitterCore.h
A2.6's arithmetic: where the panes and the grab bars of a splitter go.
⚠ NO TOOLKIT IN THIS FILE OR IN ITS .cpp, and that is the point rather than a tidiness preference. Everything a splitter is hard about is a sum: how a requested set of sizes is normalised onto the space actually available, who absorbs a resize, what a minimum does to both, and where a dragged bar is allowed to land. None of that needs a view, a window or an event, so none of it is tested through one -- the suite beside this file compiles with a bare C++17 compiler and no framework at all (the shape A3.1's ICoreAppKitPrompts proved next door).
⚠ IT IS ONE-DIMENSIONAL AND KNOWS NO ORIENTATION. A horizontal splitter and a vertical one differ only in which of a rectangle's two numbers the answers below are spent on, and that mapping is three lines in the seat. Carrying an
ICoreSplitterPane#
ICoreAppKitSplitterCore.h:34 · struct · 0 declaration(s)
One pane's state.
struct ICoreSplitterPane {
public:
int requested = 0;
int minimum = 0;
// ⚠ ONLY ZERO VS NON-ZERO IS READ, AND THAT IS THE TOOLKIT'S BEHAVIOUR
// RATHER THAN A SHORTCUT. Measured over stretch pairs 0/0, 0/1, 1/0, 1/1,
// 5/1 and 2/3 on a live QSplitter resized 1000 -> 1400 -> 700: 1/1, 5/1 and
// 2/3 all produce identical numbers, and identical to 0/0. What a stretch
// decides here is membership of the set that absorbs a resize, never the
// proportion in which they absorb it -- that stays proportional to the
// sizes the panes already have. A call site that writes setStretchFactor(0,
// 4) and setStretchFactor(1, 1) expecting 4:1 growth is getting proportional
// growth on both toolkits, and has been all along.
int stretch = 0;
// ⚠ CLOSED ON PURPOSE, WHICH IS NOT THE SAME AS "CURRENTLY ZERO PIXELS
// WIDE", and the difference is what stops a squeezed window from
// permanently closing a pane. A pane is collapsed when a caller asked for
// 0 or a drag pushed the bar past it; a pane that a narrow window has
// merely squeezed to nothing is NOT collapsed, keeps its minimum, and
// comes back when the window widens. Reading the size instead of this flag
// is a defect that only appears once a window has been made narrow enough,
// which is to say on someone else's screen.
bool collapsed = false;
// Whether the pane may be closed AT ALL -- the toolkit's per-index
// childrenCollapsible, and the gate on the measured collapse zone below.
//
// ⚠ IT IS NOT THE SAME QUESTION AS `minimum`, AND MODELLING IT AS ONE IS
// THE BUG IT EXISTS TO STOP. A minimum is what a RESIZE may not go below;
// collapsing is the separate move that skips past it, so a pane with a
// minimum of 180 and this left true still closes when the bar is shoved at
// it. `false` is what a navigation pane wants: the collapse zone stops
// applying and the drag halts at the minimum instead.
//
// true is the default and is the toolkit's, so no existing pane changes.
bool collapsible = true;
};
};
ICoreAppKitSplitterCore#
ICoreAppKitSplitterCore.h:73 · class · pImpl · 22 declaration(s)
class ICoreAppKitSplitterCore {
public:
ICoreAppKitSplitterCore();
// Out of line, and it has to be: the header only forward-declares Impl, so
// the destructor could not otherwise see a complete type to destroy.
~ICoreAppKitSplitterCore();
ICoreAppKitSplitterCore(const ICoreAppKitSplitterCore&) = delete;
ICoreAppKitSplitterCore& operator=(const ICoreAppKitSplitterCore&) = delete;
// The grab bar's thickness. 4 is the toolkit's default and is what this
// tree's two splitter call sites get today -- measured, because the
// project's own QSplitter stylesheet sets `width: 1px` and that rule
// applies to the SPLITTER, not to its handles, so it changes nothing.
void setHandleWidth(int width);
[[nodiscard]] int handleWidth() const;
[[nodiscard]] int paneCount() const;
// Insert a pane at `index`, shifting the rest along. An index past the end
// appends; a negative one prepends.
void insertPane(int index);
void removePane(int index);
// A pane may not be sized below this -- except when it is collapsed, which
// is what a request of 0 means and what the toolkit calls childrenCollapsible.
void setPaneMinimum(int index, int minimum);
[[nodiscard]] int paneMinimum(int index) const;
// Whether a drag may close the pane at `index` -- see the field. Turning it
// off RE-OPENS a pane that is already closed, because a caller pinning a
// pane open wants it open now and not merely un-closeable later.
void setPaneCollapsible(int index, bool collapsible);
[[nodiscard]] bool paneCollapsible(int index) const;
void setStretchFactor(int index, int stretch);
[[nodiscard]] int stretchFactor(int index) const;
// The splitter's own length along the axis. Setting it runs the RESIZE
// rule, which is not the same as re-requesting the sizes.
void setExtent(int extent);
[[nodiscard]] int extent() const;
// The peer of QSplitter::setSizes(). The values are a RATIO, not pixels:
// they are normalised onto whatever space is available, so {3, 1} and
// {750, 250} mean the same thing and {640, 180} does not mean 640 pixels.
// Extra values are ignored; missing ones leave those panes' requests alone.
void setRequestedSizes(const std::vector<int>& sizes);
// The answer: one size per pane, always summing to exactly the available
// space unless the minimums cannot fit in it.
[[nodiscard]] const std::vector<int>& sizes() const;
// Where pane `index` starts, and where grab bar `index` starts. Bar 0 sits
// before pane 0 and is ALWAYS ZERO-WIDTH -- the toolkit keeps a leading
// handle too, and a seat that draws it puts a divider against the edge of
// the splitter where there is nothing to divide.
[[nodiscard]] int paneOffset(int index) const;
[[nodiscard]] int handleOffset(int handleIndex) const;
// Drag: put grab bar `handleIndex` so its leading edge sits at `position`,
// clamped to what the neighbours' minimums allow. Returns true when a size
// actually changed, which is what decides whether the moved hook fires --
// a drag held against a limit must not emit on every mouse move.
bool moveHandle(int handleIndex, int position);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreAppKitStandardItemAccess.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitStandardItemAccess.h
ICoreStandardItem's toolkit half on this backend, as an IMPL-SIDE header.
⚠ This is not part of the public surface and must not be included from one. It exists for the same reason UI/Backends/Qt/Widgets/ICoreStandardItemImpl.h exists on the other backend: TWO files need the Impl complete -- the item's own seat defines it, and the model has to adopt a released one when appendRootRow() takes ownership. A private nested class defined inside a single .cpp cannot be named from another translation unit, and that shows up as "no matching member function", which reads like a signature problem rather than a visibility one.
⚠ THE OTHER BACKEND'S Impl IS A
QStandardItem; THIS ONE IS A NODE. There the model is a real QStandardItemModel and the item IS a toolkit object, so display text, icon, editability and every caller role live in the toolkit's
ICoreStandardItem#
ICoreAppKitStandardItemAccess.h:41 · class · bases :Impl · 10 declaration(s)
class ICoreStandardItem : :Impl {
public:
explicit Impl(ICoreStandardItem& owner);
Impl(ICoreStandardItem& owner, const ICoreString& text);
~Impl();
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
// Called from ~ICoreStandardItem so this destructor does not delete a
// wrapper that is already destroying itself.
void detachOwner();
ICoreStandardItem* owner() const;
// ⚠ setData REPLACES a role whatever type it held before, which is what a
// single variant-valued role store does on the other backend. Two maps
// would quietly keep both and answer with whichever was consulted first,
// so each setter erases from the other -- see the .cpp.
void setRoleText(int role, const ICoreString& value);
void setRoleInt(int role, int value);
// The role as TEXT, which is what ICoreTreeView::rowData publishes. An int
// role reads back as its decimal spelling: the other backend gets that
// from QVariant::toString(), and the header's own note ("Numbers written
// by setData(int, role) read back as their decimal spelling") is the
// contract this has to meet rather than a description of Qt.
ICoreString roleAsText(int role) const;
// The row this item heads, one column per cell. cells is columns 1..n --
// column 0 is this record itself, which is what makes a row handle and a
// column-0 item the same thing.
ICoreString label;
ICoreIcon icon;
bool hasIcon = false;
bool editable = true;
std::map<int, ICoreString> textRoles;
std::map<int, int> intRoles;
std::vector<std::shared_ptr<Impl>> children;
std::vector<std::shared_ptr<Impl>> cells;
Impl* parentNode = nullptr;
// ⚠ A NODE'S WEAK REFERENCE TO ITSELF, SET AT INSERTION, AND IT EXISTS FOR
// ONE CALLER: ICoreTreeRow::parent(). A row handle holds a weak_ptr (it
// must not keep its row alive -- a QModelIndex does not), so building a
// handle for the PARENT needs the parent's shared_ptr. Reaching it any
// other way means searching the grandparent's children, and for a
// top-level row it means reaching the model, which a bare handle cannot
// do. enable_shared_from_this is the shorter route and is unavailable:
// these records are ALSO owned by unique_ptr before insertion, so they are
// not always in a shared_ptr at all. Empty until the record is inserted,
// which is exactly when a row handle can first name it.
std::weak_ptr<Impl> selfWeak;
ICoreStandardItem* m_owner = nullptr;
};
};
ICoreAppKitTextField.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitTextField.h
Declares no class of its own — see the file.
ICoreAppKitTextView.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitTextView.h
Declares no class of its own — see the file.
ICoreAppKitThemedScroller.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitThemedScroller.h
Backend-internal. Include from a .mm inside UI/Backends/AppKit/ only.
⚠⚠ THE SCROLLER macOS DRAWS ANSWERS THE SYSTEM'S APPEARANCE, NOT THIS TREE'S, AND THAT IS THE WHOLE REASON THIS EXISTS. An overlay NSScroller's knob is a near-black translucent capsule on a light system and a near-white one on a dark system -- so a pane wearing this tree's LIGHT theme on a Mac set to Dark got a pale bar over white content, and one wearing the dark theme on a light Mac got the opposite. Neither followed the surface it was scrolling, and neither answered the pointer with anything this tree chose.
⚠ IT IS ONE OBJECT FOR ALL FIVE SCROLLING SEATS, and that is the point rather than a convenience. ICoreScrollPane, ICoreListBox, ICoreTree, ICoreTreeView and ICoreAppKitTextView each build their own NSScrollView; five copies of a knob colour is five chances for one window to show two kinds of scroll bar,
Declares no class of its own — see the file.
ICoreAppKitTreeModelAccess.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitTreeModelAccess.h
ICoreTreeViewModel's half on this backend, as an IMPL-SIDE header.
⚠ This is not part of the public surface and must not be included from one. It exists because TWO files need it complete: the model's own seat defines it, and ICoreTreeView has to READ the rows out of it -- on this backend the model is not a toolkit object the view can be handed, it is a plain record the view has to walk. Same precedent as ICoreAppKitStandardItemAccess.h and UI/Backends/Qt/Widgets/ICoreStandardItemImpl.h.
⚠ NAMING IT IS LEGAL ONLY INSIDE ICoreTreeView'S OWN NESTED CLASS, and that is not a detail to discover later:
Implis private, and the public header grantsfriend class ICoreTreeView. A nested class has its enclosing class's access, so ICoreTreeView::Impl may spell these types; an @interface, a namespace-scope helper or a free function may not. The view seat therefore
ICoreTreeViewModel#
ICoreAppKitTreeModelAccess.h:37 · class · bases :State · 0 declaration(s)
The wrapper's own state -- see the header.
class ICoreTreeViewModel : :State {
public:
bool alive = true;
};
};
ICoreTreeViewModel#
ICoreAppKitTreeModelAccess.h:42 · class · bases :Impl · 4 declaration(s)
class ICoreTreeViewModel : :Impl {
public:
explicit Impl(ICoreTreeViewModel& owner);
Impl(const Impl&) = delete;
Impl& operator=(const Impl&) = delete;
// ⚠ NO R3 GUARD AND NO setSelfDeleting(), AND THAT DIVERGES FROM THE Qt
// SEAT ON PURPOSE -- the same divergence every seat in this zone records.
// The Qt Impl self-deletes because a QObject parent is a SECOND owner that
// reaps the model; this record has exactly one owner, the unique_ptr on
// the wrapper, so `delete m_owner` here would delete a wrapper nobody had
// transferred. The death path is one-directional.
void detachOwner();
std::vector<std::shared_ptr<ICoreStandardItem::Impl>> rows;
std::vector<ICoreString> headers;
ICoreNativeWidget* parent = nullptr;
ICoreTreeViewModel* m_owner = nullptr;
};
};
ICoreAppKitView.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitView.h
The view every painted wrapper control sits on in this backend: a FLIPPED native view whose redraw is routed into the painter core beside this file.
NO OBJECTIVE-C IN THIS HEADER, the rule this zone follows throughout. The native view is handed out as an opaque pointer for the one caller that needs it (the window, when it installs a content view); everything else here is plain C++ and standard library.
⚠ FLIPPED IS NOT A DETAIL, IT IS THE CONTRACT. The native toolkit puts the origin at the BOTTOM-left and grows y upwards; every geometry type, layout and paint hook in this tree assumes top-left and y-down. A view that forgets to say it is flipped still draws, still lays out, and puts everything in the wrong half of itself -- so the flag is asserted by the test rather than trusted, and the frame arithmetic below never compensates for it anywhere.
ICoreAppKitMouseInput#
ICoreAppKitView.h:34 · struct · 0 declaration(s)
What a mouse hook is told.
struct ICoreAppKitMouseInput {
public:
double x = 0.0;
double y = 0.0;
ICoreMouseButton button = ICoreMouseButton::None;
// ⚠⚠ EVERY BUTTON HELD AT THE TIME OF THE EVENT, WHICH IS NOT `button` AND
// WAS MISSING FROM THIS STRUCT ENTIRELY. `button` is what CAUSED the event
// and is None for a plain move; this is the mask a DRAG reads to find out
// which button is dragging. The other two native seats have carried it
// since they were written (icoreGtk4MouseButtons(in.state), WinUI's
// `in.buttons`), and every portable consumer is written against it:
//
// ICoreLinkBranchSegment::mouseMoved `event.buttons & Left` -- moves a wire
// ICoreLibraryNavigatorEntry `event.buttons & Left` -- starts a drag
// ICoreLibraryUserBlockEntry / …Template ditto
// ICoreCanvasAreaViewTitleBar `event.buttons & Left` -- drags the frame
//
// With nothing filling it the mask was 0 on every event, so each of those
// tests failed and each gesture silently did nothing -- a link segment that
// hovers and selects but cannot be dragged, which is exactly the report.
// Filled from +[NSEvent pressedMouseButtons], which is valid for every
// event type (unlike buttonNumber, below).
ICoreMouseButtons buttons = 0;
ICoreKeyModifiers modifiers = 0;
int clickCount = 1;
// Wheel deltas, in the same units the toolkit reports. Zero for every
// non-wheel event.
double scrollX = 0.0;
double scrollY = 0.0;
};
};
ICoreAppKitDropInput#
ICoreAppKitView.h:84 · struct · 0 declaration(s)
What a DROP hook is told.
struct ICoreAppKitDropInput {
public:
double x = 0.0;
double y = 0.0;
void* pasteboard = nullptr;
};
};
ICoreAppKitKeyInput#
ICoreAppKitView.h:90 · struct · 0 declaration(s)
struct ICoreAppKitKeyInput {
public:
// ⚠ ICoreKey HAS NO "unknown" ENUMERATOR -- its numbering is pinned to the
// other toolkit's and starts at 0x20, so zero is not a key and is used
// here as "nothing recognised". `recognised` says so explicitly rather
// than leaving a caller to know that, because a hook that acts on an
// unrecognised key acts on Space.
ICoreKey key = static_cast<ICoreKey>(0);
bool recognised = false;
// ⚠⚠ WHAT THE KEY WOULD INSERT, AND ITS ABSENCE MADE ONE PANEL UNTYPEABLE.
// ICoreKeyEvent has carried a `text` field since it existed -- "the text
// this key would insert" -- and this seat filled everything BUT it, so
// every consumer on this backend read an empty string. The terminal is the
// one that cannot work around it: ICoreTerminalGridView::keyPressed puts
// `event.text` straight into the stroke it encodes, so with no text a
// letter encoded to no bytes at all, the hook returned false and nothing
// reached the pty. The panel opened, drew, took the focus and swallowed
// every character -- the owner's "I can't type anything in the Terminal".
//
// ⚠ std::string RATHER THAN ICoreString, because this header is plain C++
// by its zone's rule and ICoreString.h reaches a toolkit type (the drop
// input's own banner records eleven lab recipes that stopped compiling the
// last time a value type was put in here). The wrapper converts.
//
// ⚠ AND IT IS -characters, NOT -charactersIgnoringModifiers. The KEY is
// resolved from the layout-independent code and the unmodified character
// -- that is A1.4's rule and it is unchanged -- but the TEXT is what the
// keyboard actually produced, which is where Shift, Option and a dead-key
// composition have already been applied. A field that inserted the
// unmodified character would type lower case with Shift held.
std::string text;
ICoreKeyModifiers modifiers = 0;
bool isRepeat = false;
};
};
ICoreAppKitSizeConstraints#
ICoreAppKitView.h:140 · struct · 0 declaration(s)
What the layout tier needs to know before it can size this view.
struct ICoreAppKitSizeConstraints {
public:
int minimumWidth = 0;
int minimumHeight = 0;
// The size the widget would like. 0 means it has no opinion and the
// layout should give it whatever the distribution leaves.
int preferredWidth = 0;
int preferredHeight = 0;
// 0 is UNBOUNDED, not "may not grow" -- the engine's own convention
// (ICoreLayoutItem::maximumPrimary says the same thing in the same words).
int maximumWidth = 0;
int maximumHeight = 0;
// ⚠⚠ "PINNED TO EXACTLY maximumWidth/Height", AND IT EXISTS BECAUSE ZERO IS
// ALREADY SPOKEN FOR TWICE ABOVE. `maximumWidth == 0` means UNBOUNDED and
// `preferredWidth == 0` means NO OPINION, so a widget pinned to a width of
// ZERO -- which is the last frame of every closing animation in this tree --
// could not be expressed at all: it published "no floor, no ceiling, no
// opinion" and the tier answered with the widget's own size hint. One frame,
// at the end, springing back to full size. See ICoreWidget::pushConstraints
// for the measurement.
//
// ⚠ SET ONLY BY setFixedWidth/setFixedHeight/setFixedSize -- a maximum that
// merely happens to equal the minimum has not asked to be pinned.
bool fixedWidth = false;
bool fixedHeight = false;
// Share of the surplus, per axis. A widget whose size behaviour says it
// wants room gets a stretch here even when the layout gave it none, which
// is how the other toolkit's Expanding policy behaves.
int horizontalStretch = 0;
int verticalStretch = 0;
};
};
ICoreAppKitViewLiveness.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitViewLiveness.h
Declares no class of its own — see the file.
ICoreAppKitWatchRegistry.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitWatchRegistry.h
THE WIDGET TIER'S WATCH REGISTRY, FOR A HOLDER THAT IS NOT A WIDGET. Row A1.3 of the AppKit port board. Backend-private: include this from a .cpp/.mm inside UI/Backends/AppKit/ and nowhere else.
⚠ The board's FILENAME is deliberately not written here: gen_api.py publishes a header's doc-comments to docs/generated/, so a board filename in a header trips D15 (audience-leak) for whoever next rebuilds the docs, never for the author -- the rule ICoreStyleSpecQss.cpp records. Name it in a .cpp.
Qt does every watch with one QObject event filter installed on the TARGET. AppKit has no event filter, so A1.3 inverted it: the target's seat holds a registry of who is interested, and the target's own hooks look them up. That registry lives in an anonymous namespace in ICoreWidget.mm and its watcher used to be an
ICoreWidget*-- which is why the scene tier could not hold a
Declares no class of its own — see the file.
ICoreAppKitWidgetLiveness.h#
ICoreEssentials/UI/Backends/AppKit/Widgets/ICoreAppKitWidgetLiveness.h
Declares no class of its own — see the file.