API — ICoreEssentials/UI/Windows
The public contract of 11 header(s) under ICoreEssentials/UI/Windows — 14 class/struct definition(s), 148 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.
| Header | Defines | Declarations | Bases |
|---|---|---|---|
ICoreDialog.h | ICoreDialog | 27 | public ICoreNativeWidget |
ICoreFloatingElementsWindow.h | — | 0 | — |
ICoreInputDialog.h | ICoreInputDialog | 3 | — |
ICoreMessageBox.h | ICoreMessageBox | 8 | — |
ICoreNativeDialogs.h | ICoreFileDialog, ICoreColorDialog, ICoreFontDialog, ICoreDesktopReveal | 17 | — |
ICoreShortcut.h | ICoreShortcut | 5 | — |
ICoreTitleBar.h | ICoreTitleBarColors, ICoreTitleBar | 31 | public ICoreWidget |
ICoreTitleBarHost.h | ICoreTitleBarHost | 8 | — |
ICoreTitleBarProvider.h | ICoreTitleBarProvider | 5 | — |
ICoreWindow.h | ICoreWindow | 44 | public ICoreNativeWidget |
ICoreWindowGeometryRecord.h | ICoreWindowGeometryRecord | 0 | — |
ICoreDialog.h#
ICoreEssentials/UI/Windows/ICoreDialog.h
⚠
class QDialog;RETIRED BY A9.4 (2026-08-21) -- dead. The note below still describes where the QDialog lives (the Impl, in the .cpp) and that is still true; what is gone is this header naming the type to say so. Q1.3: the ctor's QWidget* parent became ICoreNativeWidget*, which was the last QWidget on this header. <QWidget> is gone rather than forward-declared -- nothing here names the type at all any more.
ICoreDialog#
ICoreDialog.h:29 · class · bases public ICoreNativeWidget · pImpl · 27 declaration(s)
P5.11: converted.
class ICoreDialog : public ICoreNativeWidget {
public:
ICoreNativeHandle nativeWidgetHandle() const override;
// E1b: this parameter was named `contentToPopulate`, was never passed
// anything by its one call site and was dropped on the floor -- the body
// passed a literal nullptr to QDialog. It is the parent now, and it is
// forwarded.
//
// That is what makes ICoreDialog adoptable as a BASE. A QDialog subclass
// outside StudioObjects passes its parent up (ICoreSubsystemPickerDialog is
// the first), and a base that silently discarded it would have changed
// modality, stacking and ownership at every such site while compiling
// cleanly -- the kind of adoption that looks like a rename and is not one.
explicit ICoreDialog(ICoreNativeWidget* parent = nullptr);
// Mirrors of the QDialog outcome signals.
ICoreSignal<> onAccepted;
ICoreSignal<> onRejected;
void moveToScreenBottomRightCorner(const double& padding_x = 20, const double& padding_y = 20);
// Runs from the destructor, whichever way this dialog dies -- an explicit
// delete, or destruction by its parent widget.
//
// A bare callback, not a call to any particular tracker. This destructor
// used to name ICoreStudioRegistry, which put an ICoreEssentials class in
// debt to a studio-level singleton one layer up; it compiled only because
// the precompiled header happened to pull that declaration in, so the
// dependency was invisible at this file and would have broken the moment
// this file was built without the PCH. Whoever owns the dialog's lifetime
// installs this instead -- today that is
// ICoreStudioRegistry::requestNewDialog, which this file no longer knows.
//
// ONE slot, not a subscription list: a second call REPLACES the first, and
// on a registry-issued dialog that silently unhooks the registry. See the
// same note on ICoreWindow::setDestroyedHook.
void setDestroyedHook(std::function<void()> hook);
// W10.125. The same contract as ICoreWindow::setTitleBar: the dialog owns
// `bar`, nullptr keeps the system caption and opts out of
// ICoreTitleBarProvider, and the content keeps its size.
void setTitleBar(ICoreTitleBar* bar);
[[nodiscard]] ICoreTitleBar* titleBar() const;
// ------------------------------------------------------------------
// Facade members now that the QDialog base is gone; the flip's harvest
// enumerated them.
// ------------------------------------------------------------------
// Unscoped so `ICoreDialog::Accepted` call sites read unchanged; pinned
// to the toolkit's values in the .cpp.
enum DialogCode { Rejected = 0, Accepted = 1 };
int exec();
void accept();
void reject();
void open();
void close();
void show();
void hide();
void resize(int width, int height);
void setWindowTitle(const ICoreString& title);
void setFixedSize(int width, int height);
void setMinimumSize(int width, int height);
void setMinimumWidth(int width);
void raise();
void activateWindow();
void setModal(bool modal);
[[nodiscard]] int width() const;
[[nodiscard]] int height() const;
void setStyleSheet(const ICoreString& styleSheet);
void setAttribute(ICoreWidgetAttribute attribute, bool on = true);
virtual ~ICoreDialog();
protected:
// The dialog is on screen. Same hook, and the same timing, as
// ICoreWidget::shown() -- which a dialog cannot inherit, since it is a
// parallel wrapper.
//
// It is where work that needs a laid-out window goes: a view filled in the
// constructor of a dialog has no item layout yet and comes up blank. Note
// that it runs on EVERY show, not only the first, so a subclass that must
// do its work once says so itself.
virtual void shown();
// ⚠ nativeDialog() WAS HERE AND IS GONE (H4.25), for the reason
// ICoreWindow::nativeWindow() is: a protected non-virtual helper is what
// the header surface rule removes, and this one had no callers in the tree
// at all. See that header's note before re-adding anything like it.
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreFloatingElementsWindow.h#
ICoreEssentials/UI/Windows/ICoreFloatingElementsWindow.h
⚠ THREE DEAD Qt INCLUDES RETIRED BY A9.4 (2026-08-21): <QObject>, <QResizeEvent> and <QShowEvent>. None of the three types is named anywhere in this header -- the class below takes an ICoreNativeWidget, overrides two ICoreWindow hooks with ICore types, and holds a pImpl.
The note that stood here said the two event headers were "dead already and belong to Q5.3's sweep, not here", which was the right call for a row about parameters. A9.4 IS that sweep, one plan later: an include a header does not need is a Qt header dragged into every translation unit that reaches this one, and on a Qt-free macOS build it is a file that does not exist.
Q1.3 took <QWidget> with populateWithWidgetSnapshot's parameter and H4.26 took <QPixmap> with the private
snapshotmember; this is the remainder.
Declares no class of its own — see the file.
ICoreInputDialog.h#
ICoreEssentials/UI/Windows/ICoreInputDialog.h
ICoreInputDialog#
ICoreInputDialog.h:13 · class · 3 declaration(s)
Quick modal prompts, in the ICoreNativeDialogs static-facade shape.
class ICoreInputDialog {
public:
ICoreInputDialog() = delete;
static std::optional<ICoreString> getText(ICoreNativeWidget* parent,
const ICoreString& title,
const ICoreString& label,
const ICoreString& initial = ICoreString());
static std::optional<ICoreString> getItem(ICoreNativeWidget* parent,
const ICoreString& title,
const ICoreString& label,
const ICoreStringList& items,
int currentIndex = 0,
bool editable = false);
// The same two, answered through a callback (WB3.1) -- ICoreMessageBox.h
// has the full contract: inside the call on a desktop, later in a browser,
// where the blocking forms return an empty optional at once instead of
// waiting. Empty optional = cancelled, as above.
using Answered = std::function<void(std::optional<ICoreString>)>;
static void getTextAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& label, Answered answered,
const ICoreString& initial = ICoreString());
static void getItemAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& label, const ICoreStringList& items,
Answered answered, int currentIndex = 0, bool editable = false);
};
};
ICoreMessageBox.h#
ICoreEssentials/UI/Windows/ICoreMessageBox.h
ICoreMessageBox#
ICoreMessageBox.h:44 · class · final · pImpl · 8 declaration(s)
ICoreMessageBox — the app's modal alert.
class ICoreMessageBox final {
public:
ICoreMessageBox() = delete;
// What a three-way "you have unsaved work" prompt came back with.
enum class SaveAnswer { Save, Discard, Cancel };
// The prompt itself, with Save as the default button. A named method
// rather than a generic button-set builder: this exact three-way question
// is the only one the app asks, and spelling it once keeps the button
// order and the default from drifting between call sites.
//
// ⚠ Preserve, do not tidy: this one raises the TOOLKIT's static box, not
// the themed Impl the other five use, so it has always come up in the
// platform's own colours. That is a real divergence and predates the
// conversion; routing it through the themed path here would be a visual
// change smuggled in under a refactor.
static SaveAnswer askSaveDiscardCancel(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& text);
// ---- the three notifications ------------------------------------------
static void critical(ICoreNativeWidget* parent, const ICoreString& title, const ICoreString& text);
static void warning(ICoreNativeWidget* parent, const ICoreString& title, const ICoreString& text);
static void information(ICoreNativeWidget* parent, const ICoreString& title, const ICoreString& text);
// ---- the two questions -------------------------------------------------
// Yes / No. True for Yes; false for No, Escape and a closed window.
// `defaultToYes` picks which of the two starts focused — pass false for a
// destructive action, so a stray Return does not confirm it.
static bool question(ICoreNativeWidget* parent, const ICoreString& title, const ICoreString& text,
bool defaultToYes = true);
// Same, but the affirmative carries its own label and the dismissive is
// Cancel. True only if the labelled button was the one clicked.
//
// The two widths are opt-in, and both default to "leave it to the toolkit"
// so the five other call sites are unchanged:
//
// * `minimumWidth` widens the BOX. An alert sizes itself to its text, so a
// long body -- a how-to with a bulleted command list, say -- comes up in
// a tall narrow column with every line wrapped. There is no setter for
// this on the toolkit's box; see the .cpp for what it takes.
// * `acceptButtonMinimumWidth` widens the AFFIRMATIVE only, for a label
// that says what it will do ("Choose Recipe File...") rather than "OK".
// Cancel keeps the shared minimum -- buttons carrying different labels
// are not obliged to be the same width.
//
// Both are in unscaled pixels, like every other size in this tree.
static bool confirm(ICoreNativeWidget* parent, const ICoreString& title, const ICoreString& text,
const ICoreString& acceptText,
int minimumWidth = 0, int acceptButtonMinimumWidth = 0);
// ---- the same six, answered through a callback (WB3.1) -------------------
//
// A browser cannot block while a prompt waits for a click (web backend plan
// §6.1), so every form above that RETURNS its answer has an `...Async` twin
// that hands it over instead. Code that must run in a browser uses these;
// ICoreCapabilities::has(BlockingModal) says whether the blocking forms can.
//
// ⚠ ON A DESKTOP THE CALLBACK RUNS INSIDE THE CALL: each twin is the
// blocking form with its answer passed on, so a call site moved to it keeps
// the order of effects it had. In a browser it runs LATER, when the user
// answers. Write the continuation so it is right both ways -- it must not
// assume the prompt is still up, or that the caller's locals still exist
// (capture by value). The answers are the blocking forms' answers:
// Escape and a closed prompt are No / Cancel / not-accepted.
//
// ⚠ IN A BROWSER THE BLOCKING FORMS DO NOT HANG AND DO NOT ASK. The three
// notifications show and return at once; the three questions return the
// CANCEL answer at once (false, SaveAnswer::Cancel) and print which Async
// form to use. A question nobody could answer is a cancelled one.
static void askSaveDiscardCancelAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& text,
std::function<void(SaveAnswer)> answered);
// `dismissed` may be empty.
static void criticalAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& text, std::function<void()> dismissed = {});
static void warningAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& text, std::function<void()> dismissed = {});
static void informationAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& text, std::function<void()> dismissed = {});
static void questionAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& text, std::function<void(bool yes)> answered,
bool defaultToYes = true);
static void confirmAsync(ICoreNativeWidget* parent, const ICoreString& title,
const ICoreString& text, const ICoreString& acceptText,
std::function<void(bool accepted)> answered,
int minimumWidth = 0, int acceptButtonMinimumWidth = 0);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreNativeDialogs.h#
ICoreEssentials/UI/Windows/ICoreNativeDialogs.h
LQ.4, 2026-08-31: this header uses std::optional and never included <optional>. It compiled anyway because Qt's umbrella reached it transitively; the moment the rigs came off the Qt text seat the include path lost Qt and this stopped parsing. §L74.1 is the same defect pointing the other way -- there a QT name arrived with no include of its own, here a STANDARD one did.
ICoreFileDialog#
ICoreNativeDialogs.h:52 · class · 7 declaration(s)
ICoreFileDialog / ICoreColorDialog / ICoreFontDialog — the three pickers the app hands to the operating system.
class ICoreFileDialog {
public:
ICoreFileDialog() = delete;
// Empty return means cancelled — the platform gives no other answer, and
// every call site already reads it that way.
static ICoreString getOpenFileName(ICoreNativeWidget* parent, const ICoreString& caption,
const ICoreString& directory = ICoreString(),
const ICoreString& filter = ICoreString());
static ICoreString getSaveFileName(ICoreNativeWidget* parent, const ICoreString& caption,
const ICoreString& directory = ICoreString(),
const ICoreString& filter = ICoreString());
// The overload that reports which filter the user picked, for callers that
// append an extension the typed name is missing.
static ICoreString getSaveFileName(ICoreNativeWidget* parent, const ICoreString& caption,
const ICoreString& directory,
const ICoreString& filter,
ICoreString* selectedFilter);
// Picks a FOLDER rather than a file — an export destination, a project
// root. No filter parameter, because a directory picker has nothing to
// filter. Empty return means cancelled, as above.
static ICoreString getExistingDirectory(ICoreNativeWidget* parent, const ICoreString& caption,
const ICoreString& directory = ICoreString());
// ---- the same pickers, answered through a callback (WB3.2) ---------------
//
// ICoreMessageBox.h states the Async contract: the callback runs INSIDE the
// call on a desktop, LATER in a browser; an empty path means cancelled. In a
// browser the blocking forms above return empty at once and say which Async
// form to use. What a browser adds, and a caller must know:
//
// * A PICKER OPENS ONLY IN RESPONSE TO A CLICK OR KEY PRESS (the browser's
// rule, about 5 s of it). Called outside one, the answer is "cancelled",
// with the reason printed.
// * OPEN: the path is a COPY of the chosen file in the page's own file
// system (under /picked/). Read it with any file API. It is the user's
// file's content, not the user's file: writing to it changes nothing on
// their disk.
// * FOLDER: the same, for a whole folder, copied under /picked/<name>/.
// Read-only in the same sense.
// * SAVE: `written` receives the path to WRITE, and must write the file
// BEFORE IT RETURNS. On a desktop that is the file the user chose. In a
// browser it is a scratch file, and when `written` returns its bytes are
// handed to the browser as a DOWNLOAD under the name the user typed. A
// file not written by then is not delivered.
using PathAnswered = std::function<void(const ICoreString& path)>;
using SavePathAnswered = std::function<void(const ICoreString& path, const ICoreString& selectedFilter)>;
static void getOpenFileNameAsync(ICoreNativeWidget* parent, const ICoreString& caption,
PathAnswered answered,
const ICoreString& directory = ICoreString(),
const ICoreString& filter = ICoreString());
static void getSaveFileNameAsync(ICoreNativeWidget* parent, const ICoreString& caption,
SavePathAnswered written,
const ICoreString& directory = ICoreString(),
const ICoreString& filter = ICoreString());
static void getExistingDirectoryAsync(ICoreNativeWidget* parent, const ICoreString& caption,
PathAnswered answered,
const ICoreString& directory = ICoreString());
};
};
ICoreColorDialog#
ICoreNativeDialogs.h:116 · class · 3 declaration(s)
class ICoreColorDialog {
public:
ICoreColorDialog() = delete;
// Empty optional means cancelled.
static std::optional<ICoreColor> getColor(const ICoreColor& initial, ICoreNativeWidget* parent,
const ICoreString& title = ICoreString());
// WB3.2 -- the Async contract of ICoreFileDialog above. ⚠ In a browser the
// colour input has no alpha channel, so the answer keeps `initial`'s alpha.
static void getColorAsync(const ICoreColor& initial, ICoreNativeWidget* parent,
std::function<void(std::optional<ICoreColor>)> answered,
const ICoreString& title = ICoreString());
};
};
ICoreFontDialog#
ICoreNativeDialogs.h:132 · class · 3 declaration(s)
class ICoreFontDialog {
public:
ICoreFontDialog() = delete;
// Empty optional means cancelled.
static std::optional<ICoreFont> getFont(const ICoreFont& initial, ICoreNativeWidget* parent);
// WB3.2 -- the Async contract of ICoreFileDialog above. In a browser the
// prompt offers family, point size, bold and italic, and the answer is
// `initial` with those four replaced.
static void getFontAsync(const ICoreFont& initial, ICoreNativeWidget* parent,
std::function<void(std::optional<ICoreFont>)> answered);
};
};
ICoreDesktopReveal#
ICoreNativeDialogs.h:151 · class · 4 declaration(s)
The fourth thing this file hands to the operating system: the platform's own file browser.
class ICoreDesktopReveal {
public:
ICoreDesktopReveal() = delete;
// Show `folderPath` in the platform's file manager (Finder / Explorer /
// the desktop's default). A path that does not exist opens nothing; the
// platform gives no answer either way, so neither does this.
static void openFolder(const ICoreString& folderPath);
// Open `filePath` with the application the platform has registered for it
// -- a .csv in the spreadsheet, a .png in the viewer (what the ICore Script
// IDE's project navigator does on a double-click). A folder or a path that
// does not exist opens nothing, and the platform gives no answer, so
// neither does this.
static void openFile(const ICoreString& filePath);
// Open a web page in the user's browser -- the account panel's link to the
// portal, and the first caller that needed a URL rather than a path
// (ACCOUNT_MANAGER A5.2). The capability goes INTO the wrapper rather than
// a Studio panel naming QDesktopServices, which R2 forbids outright.
//
// ⚠ https ONLY, and it is checked here rather than at the call sites. This
// function hands a string to the operating system and asks it to act on it;
// `file://` would make a link into a local-file open and `javascript:` is
// executable in some browsers. A URL with any other scheme opens nothing
// and says nothing, exactly as a missing folder does above.
static void openWebPage(const ICoreString& url);
};
};
ICoreShortcut.h#
ICoreEssentials/UI/Windows/ICoreShortcut.h
ICoreShortcut#
ICoreShortcut.h:17 · class · pImpl · 5 declaration(s)
A standalone keyboard shortcut scoped to a host widget (the ICoreMenu rows register their own; this is for shortcuts with no menu row, like copy in the diagnosis panel).
class ICoreShortcut {
public:
// `scope` is how wide the key listens. It defaults to Window, which is
// what every call site got before the parameter existed, so adding it
// changed nothing that was already here. A panel whose key means something
// only inside itself -- Ctrl+C copying THAT panel's log rather than the
// window's -- asks for WidgetWithChildren.
// ⚠ `host` is an ICoreNativeWidget*, REPLACING the QWidget* it used to be
// rather than overloading beside it. P4.3's task line asked for an overload
// and that would not compile at the call sites it exists to serve: every
// unconverted wrapper is BOTH a QWidget and an ICoreNativeWidget, so the
// two candidates are ambiguous for an ICoreLabel*, ICoreButton*,
// ICoreWidget* and 15 more (§2 R4). P0.1 escaped that by renaming
// subscribe -> subscribeNative; a CONSTRUCTOR cannot be renamed, which
// P2.5 and P3.1 both recorded hitting. Replacing costs nothing here --
// there is exactly one construction site in the tree -- and it is
// unambiguous permanently rather than until Phase 8 tidies a second name.
ICoreShortcut(const ICoreKeySequence& sequence, ICoreNativeWidget* host,
std::function<void()> onActivated,
ICoreShortcutScope scope = ICoreShortcutScope::Window);
~ICoreShortcut();
ICoreShortcut(const ICoreShortcut&) = delete;
ICoreShortcut& operator=(const ICoreShortcut&) = delete;
void setEnabled(bool enabled);
// ⚠⚠ "SHOULD THIS CHORD BE CLAIMED AT ALL, RIGHT NOW" -- ASKED BEFORE THE
// KEYSTROKE IS TAKEN, WHICH IS A DIFFERENT QUESTION FROM setEnabled() AND
// FROM ANYTHING THE CALLBACK CAN ANSWER.
//
// A shortcut that matches CONSUMES its key. So a shortcut whose callback
// decides for itself that it should do nothing has still eaten the
// keystroke, and the widget that has the focus never sees it. `ICoreMenu`
// registers exactly that shape for every row it cannot hand to the platform:
// the Edit menu's Delete row carries Backspace as an alternate, and both are
// meant to "stand down while something is being typed".
//
// Measured consequence before this existed, on the AppKit seat: Delete and
// Backspace matched the menu's application-scope entries on every keystroke,
// ran a guard that correctly did nothing, and were swallowed -- so no text
// field, code editor or in-place rename in the product could delete a
// character. The guard was in the right place to stop the ACTION and the
// wrong place to stop the CLAIM.
//
// A predicate answering false means the shortcut is not eligible for this
// keystroke: it does not fire, and it does not consume. Unset means always
// eligible, which is what every call site got before this existed.
void setEligibility(std::function<bool()> isEligible);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreTitleBar.h#
ICoreEssentials/UI/Windows/ICoreTitleBar.h
ICoreTitleBar -- a window's caption strip, drawn by the application.
The platform keeps what users expect to find where they always are -- the caption BUTTONS (Windows' minimise/maximise/close with snap layouts, macOS' traffic lights, GTK's window controls in the desktop's own layout) -- and the application draws everything else in the strip: background, icon, title, and any controls it wants there.
auto* bar = new ICoreTitleBar(ICoreTitleBarRole::Window); // ... lay out an icon and a title label inside
bar... bar->addInteractiveWidget(searchField); // clicks, not drags window->setTitleBar(bar); // the window owns it nowOr, for EVERY window and dialog at once, register a design per platform
ICoreTitleBarColors#
ICoreTitleBar.h:87 · struct · 0 declaration(s)
The colours the PLATFORM draws with, where the platform takes any.
struct ICoreTitleBarColors {
public:
ICoreColor background;
ICoreColor foreground;
ICoreColor hoverBackground;
ICoreColor pressedBackground;
ICoreColor inactiveForeground;
};
};
ICoreTitleBar#
ICoreTitleBar.h:95 · class · bases public ICoreWidget · pImpl · 31 declaration(s)
class ICoreTitleBar : public ICoreWidget {
public:
explicit ICoreTitleBar(ICoreTitleBarRole role = ICoreTitleBarRole::Window);
~ICoreTitleBar() override;
[[nodiscard]] ICoreTitleBarRole role() const;
[[nodiscard]] static ICoreTitleBarPlatform platform();
// The height the bar asks for, in logical pixels. A seat may round it to
// one the platform draws natively -- macOS lays its traffic lights out for
// a compact (38) or a unified (52) titlebar and nothing between -- so the
// height the bar actually GETS is its own height(), as for any widget.
void setPreferredHeight(int height);
[[nodiscard]] int preferredHeight() const;
// ------------------------------------------------------------------
// The window, as the bar sees it. Kept current by the seat.
// ------------------------------------------------------------------
[[nodiscard]] ICoreString windowTitle() const;
[[nodiscard]] bool isWindowActive() const;
[[nodiscard]] bool isWindowMaximized() const;
// The strips the platform's own buttons occupy, in the bar's logical
// pixels. left() and right() are the ones that matter; top and bottom
// are zero on every platform today.
[[nodiscard]] ICoreMargins systemInsets() const;
// Fires after any of the four above changed. The override below is the
// same edge for a subclass.
ICoreSignal<> onWindowStateChanged;
// ------------------------------------------------------------------
// What the bar tells the platform.
// ------------------------------------------------------------------
// A child that takes clicks rather than dragging the window -- a button, a
// search field, a menu. Must be a descendant of this bar. The bar does NOT
// own it and does not watch it die: a caller deleting an interactive child
// removes it first.
void addInteractiveWidget(ICoreWidget* child);
void removeInteractiveWidget(ICoreWidget* child);
// The interactive children's rectangles in the bar's own coordinates,
// skipping hidden ones. What a seat turns into passthrough regions.
[[nodiscard]] std::vector<ICoreRect> interactiveRects() const;
// Re-send the interactive rects. The bar does this itself whenever it is
// resized; a caller that moves or shows an interactive child WITHOUT
// resizing the bar calls it.
void refreshInteractiveRegions();
void setCaptionColors(const ICoreTitleBarColors& colors);
[[nodiscard]] ICoreTitleBarColors captionColors() const;
// ------------------------------------------------------------------
// Window actions, for a bar that draws controls of its own.
// ------------------------------------------------------------------
void beginWindowMove();
void minimizeWindow();
void toggleMaximizeWindow();
void closeWindow();
// ------------------------------------------------------------------
// The seat's side. An application does not call these.
// ------------------------------------------------------------------
void attachHost(ICoreTitleBarHost* host);
[[nodiscard]] ICoreTitleBarHost* host() const;
void noteWindowTitle(const ICoreString& title);
void noteWindowActive(bool active);
void noteWindowMaximized(bool maximized);
void noteSystemInsets(const ICoreMargins& insets);
// ⚠ THE HEIGHT THE PLATFORM ACTUALLY GAVE, WHICH IS NOT ALWAYS THE ONE
// ASKED FOR. setPreferredHeight() is a REQUEST; a seat whose platform
// decides the caption height for itself reports the answer here, and the
// bar resizes to it so every pixel of the strip is painted by the bar.
//
// A10.72: on macOS the answer MOVES. An empty unified toolbar measures 66
// between -orderFront: and the first pass of the run loop and 52 after it,
// so a bar sized once at its preference was left bottom-anchored in a
// taller titlebar -- and the uncovered band at the top, which AppKit no
// longer draws (NSTitlebarBackgroundView is hidden under a transparent
// titlebar), read as a dead native title bar above the custom one.
//
// This does NOT change preferredHeight(), so it does not go back to the
// seat as titleBarChanged() -- that would re-enter the install.
void noteSeatHeight(int height);
protected:
// The window's title, activation, maximised state or system insets
// changed. Runs before onWindowStateChanged fires.
virtual void windowStateChanged();
// The drag and the double-click, for the platforms that deliver them to
// the bar rather than handling a caption region themselves. A press on an
// interactive child never gets here: the child takes it.
bool mousePressed(const ICoreMouseEvent& event) override;
bool mouseDoubleClicked(const ICoreMouseEvent& event) override;
void resized(const ICoreSizeF& newSize, const ICoreSizeF& oldSize) override;
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
File-scope declarations#
// Which kind of top level a bar is being made for. A provider's factory is
// told this so it can give a dialog a smaller bar than an editor window.
enum class ICoreTitleBarRole {
Window,
Dialog,
};
// The platform this build draws on, as a value a factory can switch on. The
// same fact as ICORE_OS_* in ICorePlatform.h, for callers that are not
// choosing between whole blocks of code.
enum class ICoreTitleBarPlatform {
Windows,
MacOS,
Linux,
};
ICoreTitleBarHost.h#
ICoreEssentials/UI/Windows/ICoreTitleBarHost.h
ICoreTitleBarHost#
ICoreTitleBarHost.h:20 · class · 8 declaration(s)
ICoreTitleBarHost -- what an ICoreTitleBar asks of the window it sits in.
class ICoreTitleBarHost {
public:
virtual ~ICoreTitleBarHost();
// Start an interactive move of the window, from the press that is being
// delivered right now. A no-op where the platform already moves the window
// from its own caption region (Windows).
virtual void titleBarBeginMove() = 0;
// The empty part of the bar was double-clicked. Each platform does its own
// thing: Windows maximises or restores, macOS reads the user's
// "double-click a window's title bar to" preference, GTK reads
// gtk-titlebar-double-click.
virtual void titleBarDoubleClicked() = 0;
virtual void titleBarMinimize() = 0;
virtual void titleBarToggleMaximize() = 0;
virtual void titleBarClose() = 0;
// Whether the PLATFORM moves the window from its own caption region, so the
// bar must not start a move of its own.
//
// ⚠⚠ TRUE ON WINDOWS, AND THE FIRST VERSION'S BUG IS WHY IT EXISTS. There a
// press that reached the bar's widget -- which, with passthrough regions in
// place, can only be a press ON A CONTROL that the control did not consume
// -- started a window drag. The owner: *"Clicking the stuff on the title
// bar passes the mouse click events to the title bar. Title bar should only
// respond if clicked at an empty area!"* Where the platform drags the
// caption itself, an empty area never reaches XAML at all, so a press that
// does is by definition not one.
[[nodiscard]] virtual bool titleBarDragsItself() const;
// Something the seat hands to the platform changed: the interactive rects,
// the caption colours or the preferred height. The seat re-reads them from
// the bar.
virtual void titleBarChanged() = 0;
};
};
ICoreTitleBarProvider.h#
ICoreEssentials/UI/Windows/ICoreTitleBarProvider.h
ICoreTitleBarProvider#
ICoreTitleBarProvider.h:33 · class · 5 declaration(s)
ICoreTitleBarProvider -- one title bar design per platform, for every decorated window and dialog in the process.
class ICoreTitleBarProvider {
public:
ICoreTitleBarProvider() = delete;
// Returns a NEW bar; the window that asked takes ownership. Answering
// nullptr keeps the system caption for that window.
using Factory = std::function<ICoreTitleBar*(ICoreTitleBarRole role)>;
// Replace the design for one platform. An empty factory clears it.
static void setFactory(ICoreTitleBarPlatform platform, Factory factory);
// Whether the RUNNING platform has a design registered.
[[nodiscard]] static bool hasFactory();
// A new bar from the running platform's design, or nullptr when there is
// none. What the window seats call.
[[nodiscard]] static ICoreTitleBar* create(ICoreTitleBarRole role);
// Whether this build's window seats can host a custom bar at all. True on
// the WinUI, AppKit, GTK4 and UIKit seats; the call exists so a host never
// needs a platform test of its own.
[[nodiscard]] static bool isSupported();
};
};
ICoreWindow.h#
ICoreEssentials/UI/Windows/ICoreWindow.h
⚠
class QMainWindow;,class QSize;andclass QObject;RETIRED BY A9.4 (2026-08-21) -- all three dead, none named anywhere else in this header. The Q1.3 account below explains why the LAST of them stopped being needed and then left the declaration in place; that is the shape A9.4 exists to sweep. Q1.3 forward-declared QWidget here because centralWidget() RETURNED one. It no longer does: the getter is now the exact counterpart of the ICoreNativeWidget*-taking setter, so NO QWidget appears on this class's surface at all and the declaration has nothing left to serve. A backend that is not Qt could not have DEFINED the old getter -- its zone may not name a Qt type -- which is what turned a "separate catalog" note into a link blocker.
ICoreWindow#
ICoreWindow.h:39 · class · bases public ICoreNativeWidget · pImpl · 44 declaration(s)
P5.11: converted.
class ICoreWindow : public ICoreNativeWidget {
public:
ICoreNativeHandle nativeWidgetHandle() const override;
// Takes the widget INTERFACE rather than QMainWindow*, for the reason the
// QWidget* form used to give: a top-level window can be parented to any
// widget, and a narrower type turned away subclasses parented to a plain
// one. Q1.3 swapped the Qt spelling out; a sanctioned-zone caller holding a
// raw QWidget* reaches the toolkit form through ICoreWindowAccess.h.
explicit ICoreWindow(ICoreNativeWidget* parent = nullptr);
void populate(ICoreNativeWidget* widget);
// The two things this window used to do to its content by recognising what
// the content WAS. It no longer recognises anything: whoever populates the
// window teaches it what to do, which is what lets this class live in
// ICoreEssentials without dragging the studio in behind it.
//
// Teardown runs from closeEvent once closing() has agreed. Answer true if
// the content has been disposed of, and the window will delete itself as it
// closes. Answer false, or install nothing, and the window simply closes.
void setContentTeardownHook(std::function<bool()> hook);
// Runs when this window becomes the active window.
void setActivatedHook(std::function<void()> hook);
// Runs when the window is ASKED to close -- before closing() is consulted,
// and so before any teardown the subclass does there. An observer, not a
// veto: it fires whether the close is honoured or refused, and answering
// nothing cannot stop it. A subclass that wants to refuse still overrides
// closing().
//
// This is what an owner outside the wrapper zone uses to hear about a
// close without subclassing the window and without an event filter --
// icore::EditorWindow::Impl is the caller, and it is why that file needs no
// Qt at all. ONE slot, replaced rather than accumulated, matching the three
// hooks above; an owner needing to fan out multiplexes on its own side.
void setCloseRequestedHook(std::function<void()> hook);
void moveToScreenBottomRightCorner(const double& padding_x = 20, const double& padding_y = 20);
// Centres the window in the available area of the screen it is on -- the
// work area, so it clears the menu bar and the dock rather than centring in
// the raw display and sitting under them. Call it AFTER the window is at
// its final size; it centres what the window measures right now.
void moveToScreenCenter();
// Opens `window` if it is closed, and — when it is already open but minimized
// or buried behind other windows — restores it and pulls it to the front of
// the screen. Every button that "opens" a reused top-level window (Script
// Runner, Code Export Verification, ...) goes through here so a second click
// never looks like it did nothing.
static void bringToFront(ICoreNativeWidget* window);
// The shell hosting `topLevel`, or null if that window is not an
// ICoreWindow's Impl. The Impl carries the shell as a dynamic property --
// P6.5's record-what-you-own doctrine, per class, because a converted
// wrapper is invisible to qobject_cast walks (ICoreStudioSurface's
// spawned-window walk is the consumer). Test a specific shell type with
// plain dynamic_cast on the result; the shells are polymorphic.
//
// ⚠ Q1.3: the interesting lookups start from a raw toolkit widget -- the
// result of QWidget::window() -- which by definition has no wrapper to hand
// in here. That form is icoreWindowOfNative() in ICoreWindowAccess.h, and it
// is where ICoreStudioSurface's walk went. This overload stays for a caller
// that already holds a wrapper and would otherwise unwrap it just to ask.
static ICoreWindow* windowOf(ICoreNativeWidget* topLevel);
// One spelling now that the `using QMainWindow::…` re-export died with the
// base and Q1.3 deleted the QWidget* twin.
void setCentralWidget(ICoreNativeWidget* widget);
// Runs from the destructor, whichever way this window dies: an explicit
// delete, destruction by a parent widget, or WA_DeleteOnClose.
//
// This is deliberately a bare callback and not a call to any particular
// tracker. The window used to reach into ICoreStudioRegistry from its own
// constructor and destructor, which meant a class in the wrapper zone knew
// the name of a studio-level singleton and no caller could opt out of it.
// Now whoever owns the window's lifetime installs this, and the window
// neither knows nor cares who that is -- see
// ICoreStudioRegistry::requestNewWindow, which is the only caller today.
//
// ONE slot, not a subscription list: a second call REPLACES the first.
// The registry installs its own here as it hands the window out, so a
// caller that sets this on a registry-issued window silently unhooks the
// registry and leaves a dangling entry behind on destruction. If a second
// observer is ever genuinely needed, this becomes a list -- do not solve
// it by chaining onto whatever is already installed.
void setDestroyedHook(std::function<void()> hook);
// W10.125. Replace the platform's caption with `bar`, which this window
// then OWNS and deletes. The platform's caption buttons stay; the bar draws
// the rest of the strip (see ICoreTitleBar.h). nullptr puts the system
// caption back AND opts this window out of ICoreTitleBarProvider, which is
// otherwise asked for a bar on this window's first show().
//
// Content geometry does not move: resize(), width() and height() go on
// meaning the area BELOW the bar, exactly as they meant the area below the
// system caption.
void setTitleBar(ICoreTitleBar* bar);
[[nodiscard]] ICoreTitleBar* titleBar() const;
// ------------------------------------------------------------------
// Facade members now that the QMainWindow base is gone; the flip's
// harvest enumerated them.
// ------------------------------------------------------------------
void resize(int width, int height);
void show();
void raise();
void activateWindow();
void close();
void setWindowTitle(const ICoreString& title);
void setAttribute(ICoreWidgetAttribute attribute, bool on = true);
[[nodiscard]] int width() const;
[[nodiscard]] int height() const;
void move(int x, int y);
[[nodiscard]] bool isVisible() const;
[[nodiscard]] bool isMinimized() const;
[[nodiscard]] bool isActiveWindow() const;
// Q5.1. The opaque blob the toolkit uses to remember where a window was:
// size, position, screen, maximised state. Deliberately NOT interpreted
// here -- ICoreUserPreferences stores it and hands it straight back, and
// the one consumer (ICorePrimaryWindowBackend) never looks inside it.
[[nodiscard]] ICoreByteArray saveGeometry() const;
bool restoreGeometry(const ICoreByteArray& geometry);
void hide();
// Q2.4: ICoreSizeF per Q0.2's one-size-story decision. Call sites that
// write resize(QSize(w, h)) compile untouched — ICoreSizeF converts
// implicitly from QSize — and the toolkit sink takes it back via
// toQSize(), so the integer rounding is unchanged.
void resize(const ICoreSizeF& size);
// Q3.2: Q0.1's value-pinned flag set. ICoreWindowFlags is `unsigned int`
// (ICoreMouseButtons' shape), so an or-ed expression of ICoreWindowFlag
// enumerators arrives here as a plain integer, exactly as Qt::WindowFlags did.
void setWindowFlags(ICoreWindowFlags flags);
void setWindowOpacity(double opacity);
void setStyleSheet(const ICoreString& styleSheet);
// ⚠ installEventFilter(ICoreNativeObject*) WAS HERE AND IS GONE (2026-08-14).
// Q1.3 gave it an ICoreNativeObject parameter so a filter could hand over
// the QObject it also derived from; EditorWindow's CloseWatcher was the only
// caller in the tree, and being a filter is precisely what forced a QObject
// into a file that now names no Qt. The window says when it is closing
// (setCloseRequestedHook), when it is activated, and when it dies -- ask for
// a hook for whatever else is needed rather than restoring this. Watching a
// window's raw toolkit events from outside is not a capability this class
// means to offer.
void setMinimumSize(int width, int height);
[[nodiscard]] int minimumWidth() const;
[[nodiscard]] int minimumHeight() const;
// The widget handed to setCentralWidget()/populate(), or nullptr if
// neither ran. It is the WRAPPER that was passed in, remembered -- not a
// downcast of whatever the toolkit has in that slot, which could not be
// honest about a plain toolkit widget put there some other way.
[[nodiscard]] ICoreNativeWidget* centralWidget() const;
[[nodiscard]] double devicePixelRatio() const;
virtual ~ICoreWindow();
protected:
// Qt-boundary hooks, the same shape ICoreWidget carries: a subclass
// overrides these instead of the toolkit handlers (it cannot even spell
// them now). Returning true consumes the event.
virtual bool keyPressed(const ICoreKeyEvent& event);
// Return false to veto the close.
virtual bool closing();
// The window is on screen; runs on EVERY show. Same contract as
// ICoreWidget::shown().
virtual void shown();
// Same contract as ICoreWidget::resized().
virtual void resized(const ICoreSizeF& newSize, const ICoreSizeF& oldSize);
// ⚠ nativeWindow() WAS HERE AND IS GONE (H4.24). It handed the Impl
// QMainWindow to wrapper-zone subclasses, and the header surface rule bans
// a protected non-virtual helper. It had NO callers in the tree -- only its
// own declaration and definition -- so this deletes a seam nobody had taken
// up rather than a capability anybody was using. A subclass that needs
// toolkit API the facade lacks should have the facade grow it, or ask for a
// deliberate public accessor; do not re-add a protected one.
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreWindowGeometryRecord.h#
ICoreEssentials/UI/Windows/ICoreWindowGeometryRecord.h
THE PERSISTED WINDOW GEOMETRY RECORD -- ONE FORMAT, EVERY BACKEND
Row A8.4, §0.159 Ruling 2 (owner, 2026-08-24) of the macOS backend's migration notes -- named by row rather than by file, because this banner is reproduced verbatim on a PUBLIC generated API page and D15 forbids a public page naming a contributor-tree document (§0.161). This file exists because three backends had three answers to "what does ICoreWindow::saveGeometry() hand back", and the bytes are PERSISTED between runs -- so the disagreement was not a style question, it was a stored-format question, and §0.110 measured what it cost.
⚠⚠ THE DEFECT THIS REPLACES, BECAUSE IT IS THE REASON FOR THE VERSION BYTE BELOW BEING '2' AND NOT '1'. Two of the three seats already wrote a portable text record, both stamped '1', and THE TWO RECORDS ARE NOT THE SAME:
ICoreWindowGeometryRecord#
ICoreWindowGeometryRecord.h:50 · struct · 0 declaration(s)
What is stored, and the two things a bare rectangle cannot survive.
struct ICoreWindowGeometryRecord {
public:
double x = 0.0;
double y = 0.0;
double width = 0.0;
double height = 0.0;
// ⚠ HOW MANY DISPLAYS EXISTED WHEN THIS WAS SAVED, AND IT IS THE WHOLE
// REASON THIS IS NOT JUST FOUR NUMBERS. A window saved at x = -1800 on a
// left-hand second display restores OFF-SCREEN once that display is gone --
// invisible, focusable, and not recoverable without deleting the settings
// file. Recording the count lets a restore REFUSE a geometry the machine
// can no longer honour.
int screenCount = 1;
// Restoring a maximised window as a floating rectangle is a visible
// regression, and it is the one thing the Qt blob carried that the AppKit
// record did not: QWidget::saveGeometry stores the state and
// QWidget::restoreGeometry re-maximises. Carried here so that dropping the
// Qt blob (§0.159 Ruling 2) costs nothing a user can see.
//
// ⚠ A seat with no maximised state of its own leaves this false and ignores
// it on the way back in. That is a seat's decision, not a format hole.
bool maximized = false;
};
};