mirror of
https://github.com/logos-co/logos-app.git
synced 2026-08-31 03:11:08 +00:00
Measured on the built artefact: main_ui.dylib DEFINES zero and IMPORTS zero of
TokenManager, StoreRegistry, LogosAPI, LogosAPIClient and logos_core_*, out of
3410 symbols read. It links Qt and nothing else from this workspace, which
nix/symbol-gate.nix enforces across the in-process image set.
Getting there needed the last non-Qt types off the boundary: the model
properties cross as QAbstractItemModel*, catalogInstallStageChanged carries an
int rather than InstallStage::Value, and the two prebuilt AppsFilterProxy
instances are declared in QML instead of owned by MainUIBackend. That last one
removes a real inversion -- PackageCoordinator called setRequiredPackages() on
a proxy the host held a pointer to; it now emits requiredPackagesResolved() and
QML binds to the republished property.
Window resolves the plugin, qobject_casts it to IShellView, checks
hostAbiVersion() against IShellHost_abi, and calls createShell(IShellHost*).
No error-label fallback widget: that degraded to something that looked like a
working app with an empty window.
Filter proxies read role constants off host-side models and InstallEnums is
used by nine host files, so app/interfaces/ gains the contract headers both
sides compile against -- the models inherit the role structs, leaving every
AppsModel::NameRole call site unchanged. The plugin's include path is
app/interfaces only, so including a host header does not compile.
Four things only running it finds:
* Logos::DesignSystem may be linked by exactly ONE image -- both linked it
and the app aborted with "Cannot add multiple registrations for
Logos.Icons"; QML module registration is process-global
* qmltyperegistrar emits no #include for a SOURCES header given as an
absolute path outside the project
* each qt_add_qml_module is its own target and inherits no include dirs
* AUTOMOC pairs header<->cpp by same-basename-same-DIRECTORY, which the
split breaks
tst_AppManagerView.qml grows five tests for the QML binding, checked with a
negative control: breaking one assertion fails qml-tests, so they run.
41 lines
1.9 KiB
C++
41 lines
1.9 KiB
C++
#pragma once
|
|
|
|
#include <QtPlugin>
|
|
|
|
class QWidget;
|
|
class IShellHost;
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// IShellView — the UI shell, from the host's side.
|
|
//
|
|
// The seam for the main UI. IComponent is not reused here: its signature
|
|
// (`createWidget(LogosAPI*)`) names the very type this boundary exists to keep
|
|
// out of the shell. It stays exactly as it is for the third-party legacy widget
|
|
// plugins PluginLoader still loads.
|
|
//
|
|
// Window resolves the shell with qobject_cast<IShellView*> on the QPluginLoader
|
|
// instance — NOT a QMetaObject::invokeMethod("createWidget") string call, which
|
|
// is a silent-failure path: change an argument type and both sides still
|
|
// compile, then miss at runtime.
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
class IShellView {
|
|
public:
|
|
virtual ~IShellView() = default;
|
|
|
|
// Builds the shell widget. `host` is borrowed and outlives the shell; a
|
|
// null host is FATAL, not a degraded mode — failing here beats a null
|
|
// dereference later.
|
|
virtual QWidget* createShell(IShellHost* host) = 0;
|
|
|
|
// Tears the shell down. Must detach from the host (setObserver(nullptr))
|
|
// before returning, so no late callback reaches a destroyed observer.
|
|
virtual void destroyShell(QWidget* widget) = 0;
|
|
|
|
// Must return IShellHost_abi as compiled into the shell. The host compares
|
|
// it against its own and refuses to continue on a mismatch.
|
|
virtual int hostAbiVersion() const = 0;
|
|
};
|
|
|
|
#define IShellView_iid "com.logos.basecamp.IShellView/1.0"
|
|
Q_DECLARE_INTERFACE(IShellView, IShellView_iid)
|