API — ICoreEssentials/UI/Backends/Gtk4/Windows
The public contract of 6 header(s) under ICoreEssentials/UI/Backends/Gtk4/Windows — 5 class/struct definition(s), 57 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 |
|---|---|---|---|
ICoreGtk4Modal.h | ICoreGtk4Modal | 7 | — |
ICoreGtk4Pickers.h | ICoreGtk4FileFilter | 0 | — |
ICoreGtk4Prompts.h | — | 0 | — |
ICoreGtk4TitleBarSeat.h | ICoreGtk4TitleBarSeat | 13 | public ICoreTitleBarHost |
ICoreGtk4Window.h | ICoreGtk4Window | 37 | — |
ICoreGtk4WindowGeometry.h | ICoreGtk4WindowGeometry | 0 | — |
ICoreGtk4Modal.h#
ICoreEssentials/UI/Backends/Gtk4/Windows/ICoreGtk4Modal.h
ICoreGtk4Modal#
ICoreGtk4Modal.h:42 · class · nested AlertSpec · 7 declaration(s)
The GTK4 backend's modal seat: the blocking run behind ICoreDialog::exec() and behind every prompt in this tier.
class ICoreGtk4Modal {
public:
// ICoreDialog::DialogCode, pinned here so the seat never includes the
// public header to learn two integers.
static constexpr int kRejected = 0;
static constexpr int kAccepted = 1;
// Blocks until `endModal(token, code)` and returns that code. `token` is
// any non-null pointer that identifies this run; passing null returns
// kRejected immediately rather than blocking forever.
//
// ⚠ THE FRAME IS FOUND BY INDEX AND NEVER BY `back()`. A nested run pushes
// on top of this one, so the innermost frame is not this caller's — and the
// storage may reallocate under a nested push, so a reference taken before
// the pump would dangle. Both are the same one-line mistake and neither
// would fail on the single-dialog path every call site exercises.
static int runModal(void* token);
// Ends the run identified by `token` with `code`. Tolerates a token that is
// not running — a dialog answered twice, or answered after its exec()
// returned, is a no-op rather than a corrupt stack.
//
// ⚠ IT DOES NOT HAVE TO BE THE INNERMOST RUN, AND THAT IS DELIBERATE. A
// dialog that accepts itself while a SECOND dialog is stacked in front of
// it marks its own frame done; its `runModal` cannot re-check the flag
// until the inner run has returned, because the outer loop is below the
// inner one on the C++ stack. So the answer is HELD and applied when the
// outer run is current again — which is exactly what Qt's nested event
// loops do by themselves, and what `ICoreAppKitModal`'s `isModalWindow()`
// note describes having to arrange by hand on a toolkit that would
// otherwise hand the inner exec() the outer dialog's result code.
static void endModal(void* token, int code);
// Is any modal run in progress?
[[nodiscard]] static bool isRunningModal();
// Is THIS token's run in progress? Ask this, not isRunningModal(), before
// ending a run you did not start.
[[nodiscard]] static bool isModalToken(void* token);
// How many runs are stacked. 0 when none. A rig reads this to prove the
// nest unwinds; nothing in the product needs it.
[[nodiscard]] static std::size_t nestingDepth();
// ---- the async-toolkit bridge -----------------------------------------
//
// ⚠⚠ THIS IS THE **OTHER** BLOCKING SHAPE IN THIS SEAT, AND CONFUSING IT
// WITH `runModal()` IS THE ONE MISTAKE THIS COMMENT EXISTS TO STOP.
// `runModal()`/`endModal()` is for a run THIS TREE'S OWN CODE ends -- a
// dialog button, a prompt button -- and it carries a token so a nested run
// can be told from an outer one. This is for a run the TOOLKIT ends: an
// async GTK call whose `GAsyncReadyCallback` lands on the same thread and
// sets a flag. There is no token, because there is nothing for a second
// party to end.
//
// Blocks until `done` is true, pumping the application's own loop. That is
// the SAME pump `runModal()` uses and for the same reason: a nested pump on
// a fresh `GMainContext` starves the outer application (this header's
// banner has the measurement).
//
// ⚠ THE CALLBACK MUST CALL `icoreGtk4WakeMainContext()` AFTER SETTING THE
// FLAG. A bool is invisible to the toolkit, so a pump already blocked in
// `poll()` waiting for the next event would sit there until something
// unrelated woke it -- the flag is set and nothing looks at it. The wake is
// what turns a C++ store into an event the loop can see.
//
// ⚠ `const bool&` RATHER THAN A POINTER, so a caller cannot pass null and
// block forever. It is deliberately not `volatile`: this is one thread, the
// callback runs from inside the pump, and `volatile` would say otherwise.
//
// It was file-local in this seat until the three pickers of the row above
// needed the same eight lines -- `gtk_file_dialog_open()`,
// `gtk_color_dialog_choose_rgba()` and `gtk_font_dialog_choose_font()` are
// all exactly this shape. Lifted rather than copied, with the signature
// shaped by four real callers instead of one (SW5).
static void awaitToolkitCallback(const bool& done);
// ---- the system alert, behind every prompt in this tier ---------------
//
// ⚠ THE RECORD IS BUILT BY `ICoreGtk4Prompts`, WHICH IS PLAIN C++ AND HAS A
// SUITE. This struct is the seam between the half a rig can decide (which
// buttons, in what order, which one is default, which one Escape picks, and
// what each index MEANS) and the half it cannot (a person clicking one).
struct AlertSpec {
std::string title;
std::string detail;
// Left to right, as GTK lays them out.
std::vector<std::string> buttons;
// ⚠⚠ INDICES, AND ON THIS TOOLKIT THEY ARE INDEPENDENT OF THE ORDER --
// WHICH IS THE ONE THING THIS BACKEND CAN DO THAT AppKit CANNOT.
// `ICoreAppKitPrompts` records having to weld three facts together
// ("the first button added is simultaneously the default, the one
// Return activates and the RIGHTMOST"), so a caller there cannot choose
// visual order and default separately. `gtk_alert_dialog_set_buttons()`
// takes the order, and `set_default_button()` / `set_cancel_button()`
// take indices into it -- measured to round-trip independently.
// -1 for "none".
int defaultButton = -1;
int cancelButton = -1;
// A `GtkWindow*`, opaque here so this header names no toolkit. Null is
// normal and means app-modal -- most call sites pass a panel, some pass
// nothing.
void* parentWindow = nullptr;
};
// Presents `spec` and blocks until it is answered, returning the index of
// the button that ended it.
//
// ⚠⚠ IT RETURNS `spec.cancelButton` FOR A DISMISSAL, AND -1 ONLY WHEN THERE
// IS NO CANCEL BUTTON TO NAME. `gtk_alert_dialog_choose()` reports a
// dismissal as an ERROR rather than as a choice, and the callers above turn
// an index into an answer -- so folding "the user pressed Escape" onto the
// dismissive button is what keeps every mapping in ICoreGtk4Prompts a total
// function of an index. -1 is still a real input there and every mapping
// folds it to the safe answer.
static int runAlert(const AlertSpec& spec);
// ---- the two input prompts --------------------------------------------
//
// ⚠⚠ NOT AN ALERT, AND THAT IS FORCED RATHER THAN CHOSEN. `GtkAlertDialog`
// is a `GObject` and NOT a `GtkWidget` -- `GTK_IS_WIDGET()` on one is 0,
// measured -- so it has no accessory slot, no child, and no widget of any
// kind to reach. The AppKit peer puts its field in the alert's accessory
// view; there is no such thing here, so these two build a real `GtkWindow`.
// This board's modality row asks for "`GtkAlertDialog` with a custom child
// for the input case" and that half of the clause is not buildable.
//
// Both return the index of the button that ended the prompt, in the same
// vocabulary `runAlert()` uses, and write the typed/chosen value through
// the out-parameter only when it is meaningful.
// `initial` seeds the field; `outText` receives what was typed.
static int runTextPrompt(const AlertSpec& spec, const std::string& initial,
std::string* outText);
// `items` fills the chooser. `editable` allows a value that is not in the
// list, which is what the wrapper's own parameter promises.
static int runItemPrompt(const AlertSpec& spec, const std::vector<std::string>& items,
int currentIndex, bool editable, std::string* outChoice);
};
};
ICoreGtk4Pickers.h#
ICoreEssentials/UI/Backends/Gtk4/Windows/ICoreGtk4Pickers.h
The GTK4 backend's seat for the three pickers the application hands to the operating system -- the half that is PLAIN C++ and can be proved without a display. (The planning row is named in the .cpp, not here: the docs generator lifts header banners onto public API pages.)
NO GTK TYPE IN THIS HEADER, deliberately, and it is the same split
ICoreAppKitNativeDialogs.hmade one toolkit over: opening a picker needs a window server and cannot be proved in this tree's rigs, while turning Qt's filter string into what the toolkit wants is pure string work whose failure mode is silent and severe -- a filter that translates wrongly hides the files the user came to pick, on every open, and nothing reports it.⚠⚠ THE PRESENTATION HALF IS NOT DRIVABLE ON THIS BACKEND AT ALL, WHICH IS SHARPER THAN "NEEDS A DISPLAY" AND IS MEASURED RATHER THAN ASSUMED. The
ICoreGtk4FileFilter#
ICoreGtk4Pickers.h:56 · struct · 0 declaration(s)
One Name (patterns) group out of a Qt filter string.
struct ICoreGtk4FileFilter {
public:
// What the user reads. "Images" out of "Images (*.png *.jpg)".
std::string label;
// Bare suffixes, lowercased, with no dot and no star: {"png", "jpg"}.
// A compound suffix is kept whole: `*.tar.gz` yields `tar.gz`.
std::vector<std::string> suffixes;
// ⚠ SEPARATE FROM AN EMPTY `suffixes`, AND THE DIFFERENCE IS REAL RATHER
// THAN TIDY. `"Executables (*.exe *)"` is a named group whose pattern list
// contains a bare star -- so the group matches anything, AND it still names
// `exe`. A record that said "any file" by clearing the list would throw the
// `exe` away, and `icoreGtk4SpellFilter()` would then hand the caller a
// filter string it cannot recognise.
bool anyFile = false;
};
};
ICoreGtk4Prompts.h#
ICoreEssentials/UI/Backends/Gtk4/Windows/ICoreGtk4Prompts.h
Every decision the message and input prompts make, as PLAIN C++ -- no GTK, no GLib, nothing that needs a display to evaluate. The seat beside this file presents the record these functions build and reports which button ended it; the four functions at the bottom turn that index back into the answer the wrapper promised its caller.
⚠ NOTHING ABOVE src/ICoreEssentials/UI/Backends/Gtk4/ MAY INCLUDE THIS. Direct peer of
../../AppKit/Windows/ICoreAppKitPrompts.h.⚠ THIS SPLIT IS THE POINT OF THE FILE, NOT TIDINESS -- and it is A3.1's argument, reused here because it is right rather than because it is there. A prompt cannot be answered by a test without a person clicking it, so a suite over the PRESENTATION proves almost nothing. The button set, their order, the default, the escape route and the index-to-answer mapping are exactly where a
File-scope declarations#
// ---- the six message-box shapes -------------------------------------------
enum class Notification { Critical, Warning, Information };
// Mirrors ICoreMessageBox::SaveAnswer without naming it -- this header sits
// under the backend and does not include the public one.
enum class SaveChoice { Save, Discard, Cancel };
ICoreGtk4TitleBarSeat.h#
ICoreEssentials/UI/Backends/Gtk4/Windows/ICoreGtk4TitleBarSeat.h
ICoreGtk4TitleBarSeat#
ICoreGtk4TitleBarSeat.h:20 · class · bases public ICoreTitleBarHost · pImpl · 13 declaration(s)
The GTK4 seat for ICoreTitleBar, shared by ICoreWindow and ICoreDialog.
class ICoreGtk4TitleBarSeat : public ICoreTitleBarHost {
public:
ICoreGtk4TitleBarSeat(std::function<GtkWindow*()> windowOf, ICoreTitleBarRole role);
~ICoreGtk4TitleBarSeat() override;
ICoreGtk4TitleBarSeat(const ICoreGtk4TitleBarSeat&) = delete;
ICoreGtk4TitleBarSeat& operator=(const ICoreGtk4TitleBarSeat&) = delete;
// The explicit choice; nullptr keeps GTK's own titlebar. Either opts out
// of ICoreTitleBarProvider.
void setBar(ICoreTitleBar* bar);
[[nodiscard]] ICoreTitleBar* bar() const;
// Ask ICoreTitleBarProvider once, BEFORE the first show of a decorated
// window: GTK does not promise to honour gtk_window_set_titlebar() on a
// window that is already visible.
void adoptDefaultIfNeeded();
void titleBarBeginMove() override;
void titleBarDoubleClicked() override;
void titleBarMinimize() override;
void titleBarToggleMaximize() override;
void titleBarClose() override;
void titleBarChanged() override;
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreGtk4Window.h#
ICoreEssentials/UI/Backends/Gtk4/Windows/ICoreGtk4Window.h
ICoreGtk4Window#
ICoreGtk4Window.h:83 · class · pImpl · 37 declaration(s)
class ICoreGtk4Window {
public:
ICoreGtk4Window();
~ICoreGtk4Window();
ICoreGtk4Window(const ICoreGtk4Window&) = delete;
ICoreGtk4Window& operator=(const ICoreGtk4Window&) = delete;
[[nodiscard]] GtkWindow* window() const;
[[nodiscard]] GtkWidget* widget() const;
// The content the window hosts. Null clears it. Takes a GtkWidget the caller
// already owns a reference discipline for -- gtk_window_set_child() sinks
// the floating reference, which is the GObject half of "the window owns its
// child now".
void setChild(GtkWidget* child);
[[nodiscard]] GtkWidget* child() const;
// ---- size, in CONTENT units on both sides of the call -----------------
void setContentSize(int width, int height);
void contentSize(int& width, int& height) const;
void setMinimumContentSize(int width, int height);
void minimumContentSize(int& width, int& height) const;
// ---- state -------------------------------------------------------------
void show();
void hide();
void present(); // show + raise + focus, which GTK4 fuses
// Asks the window to close: emits `close-request`, and hides unless a
// handler vetoes. ⚠ IT IS NOT `gtk_window_close()` ALONE -- that call
// returns early on a window that was never presented, so the close-request
// chain never runs and a closing hook fires zero times. The unrealized case
// is run by hand here so `close()` means the same thing whether or not the
// window has been on screen -- which is what the Qt seat means by it, and
// what the wrapper above promises. ⚠ NOT a claim about all four seats:
// `[NSWindow close]` does not send `windowShouldClose:` either, and whether
// that seat has the same gap is open and UNMEASURED (Apple backend,
// A1.10). Linux backend, L9.30; the measurement is in the .cpp.
void close();
void maximize();
[[nodiscard]] bool isMaximized() const;
void minimize();
[[nodiscard]] bool isMinimized() const; // see deleted-API note 3
[[nodiscard]] bool isVisible() const;
[[nodiscard]] bool isActive() const;
void setTitle(const std::string& title);
void setDecorated(bool decorated);
void setOpacity(double opacity);
// ---- what this window IS ----------------------------------------------
//
// Sets the decoration, the resizability and the dismiss behaviour together,
// because they are one decision. Idempotent; a fresh window is
// DecoratedWindow already.
void setNature(ICoreGtk4WindowNature nature);
[[nodiscard]] ICoreGtk4WindowNature nature() const;
// The window this one belongs to. ⚠ NOT A PARENT IN THE WIDGET SENSE: it is
// `gtk_window_set_transient_for`, which is what keeps a dialog above its
// owner and lets a compositor place it. Null clears it.
//
// ⚠⚠ IT IS THE ONLY POSITIONING INPUT WAYLAND ACCEPTS FROM A CLIENT, which
// is why every nature that used to be placed by coordinate sets it instead:
// deleted-API note 1 means a popup CANNOT be moved under its anchor, and a
// transient-for is the whole of what a client may say about where its own
// surface goes.
void setTransientFor(GtkWindow* parent);
[[nodiscard]] GtkWindow* transientFor() const;
void setModal(bool modal);
[[nodiscard]] bool isModal() const;
// Fired when a Popup dismisses itself because the pointer went elsewhere.
// Never fired for any other nature.
void setDismissedHook(std::function<void()> hook);
// The device-pixel ratio of the display this window is on. Fractional where
// GTK can express it (4.12+), integral at the 4.8 floor -- see the .cpp.
[[nodiscard]] double devicePixelRatio() const;
// How many monitors the display has right now, for the geometry record.
[[nodiscard]] static int screenCount();
// ---- hooks -------------------------------------------------------------
// Answering false VETOES the close, which is `close-request` returning TRUE
// inverted at the one place the inversion is legible.
void setClosingHook(std::function<bool()> hook);
void setActivatedHook(std::function<void()> hook);
void setShownHook(std::function<void()> hook);
void setResizedHook(std::function<void(int contentWidth, int contentHeight)> hook);
void setScaleChangedHook(std::function<void(double)> hook);
// The window's own key stream (L1.4). ⚠ THE ARGUMENTS ARE A RAW GDK KEYVAL
// AND A RAW GdkModifierType WORD, deliberately untranslated: turning them
// into an ICoreKeyEvent is Events/ICoreGtk4EventMap's, which is the one
// place the correspondence is written down and the one thing the verify rig
// can check. Answering true consumes the key.
//
// ⚠⚠ IT IS A CAPTURE-PHASE CONTROLLER ON THE WINDOW, WHICH IS WHAT
// "window-scoped" MEANS AND IS NOT WHAT A BUBBLE-PHASE ONE WOULD GIVE.
// Qt delivers a window's key handler BEFORE the focused widget's, which is
// what lets a shell swallow a shortcut; a bubble-phase controller on the
// window runs AFTER every widget under it and would only ever see the keys
// nobody wanted.
void setKeyPressedHook(std::function<bool(unsigned int keyval,
unsigned int modifierState)> hook);
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
File-scope declarations#
// The toolkit half of ICoreWindow on GTK4: it owns the GtkWindow, it decides
// nothing, and it is the only file in the zone that touches one.
//
// ⚠ NOTHING ABOVE src/ICoreEssentials/UI/Backends/Gtk4/ MAY INCLUDE THIS. It
// names GTK in a header, which is what the architecture census row R2.4 refuses
// everywhere else in this tree.
enum class ICoreGtk4WindowNature {
// A real window with the OS title bar -- or, under Wayland, the CSD title
// bar GTK draws itself. The default a fresh ICoreGtk4Window already is.
DecoratedWindow,
// A real window with no title bar. Still resizable, still in the task bar.
FramelessWindow,
// Dismissed by a click elsewhere, and takes focus. ⚠ THE DISMISS IS THIS
// CLASS'S OWN and rides on `notify::is-active`, because GTK4 has no
// grab-and-dismiss popup window: see the .cpp.
Popup,
// A hover card: no frame, no shadow, and NEVER TAKES FOCUS. ⚠ The last of
// those three is UNANSWERABLE on GTK4 -- see deleted-API note 6.
FloatingCard,
};
ICoreGtk4WindowGeometry.h#
ICoreEssentials/UI/Backends/Gtk4/Windows/ICoreGtk4WindowGeometry.h
ICoreGtk4WindowGeometry#
ICoreGtk4WindowGeometry.h:22 · struct · 0 declaration(s)
The persisted window geometry, and the two functions that turn it into bytes and back.
struct ICoreGtk4WindowGeometry {
public:
int width = 0;
int height = 0;
int screenCount = 0;
bool maximized = false;
};
};