Generated reference › API — ICoreEssentials/UI/Windows
kind: generated#api#icoreessentials-ui-windows

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.

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 snapshot member; 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 now

Or, 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; and class 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;
};
};