mirror of
https://github.com/logos-co/logos-basecamp.git
synced 2026-08-27 14:51:07 +00:00
The shell held the host's objects: MainContainer owned MainUIBackend, took a
LogosAPI* and a QtLogosCore*, and connected to backend signals by concrete
type. Nothing stopped it minting identities or reading the token store.
Three headers in app/interfaces/, on the include path both targets share, so
there is exactly one copy and source drift is impossible:
* IShellHost -- 8 operations the shell may perform
* IShellObserver -- 5 notifications the host may deliver
* IShellView -- how the host builds and tears down the shell
Only QObject*, QWidget* and Qt value types cross. MainContainer holds one
IShellHost* and nothing else; QML reaches the backend as an opaque QObject*
via backendObject(), resolved through the metaobject, so no host C++ type has
to be nameable by the shell.
Ownership inverts: Window owns MainUIBackend, ShellHostAdapter and
MainShellView; the shell borrows. Teardown stops being a consequence of
construction order and becomes a stated contract:
1. beginShutdown() unmounts in-process UI plugin widgets WHILE the shell's
tree is intact -- they are docked inside it
2. destroyShell() detaches the observer, then deletes the shell
3. the backend goes, tearing down Package -> UIPlugin -> Core
4. main() destroys the core facade
Every observer forward is null-guarded: PluginLoader dispatches through
QTimer::singleShot(0, ...) and a 30s ViewModuleHost timeout, so a callback can
land after teardown starts, and QPointer cannot help -- IShellObserver is not
a QObject. UIPluginManager's plugin-widget maps become QPointer for the
mirror-image reason: those widgets are docked inside the shell, so its Qt
parent can destroy them without going through unloadUiModule.
IComponent is untouched and still serves the third-party legacy widget
plugins PluginLoader loads.
90 lines
2.6 KiB
C++
90 lines
2.6 KiB
C++
#include "ShellHostAdapter.h"
|
|
|
|
#include "MainUIBackend.h"
|
|
|
|
#include <QWidget>
|
|
|
|
ShellHostAdapter::ShellHostAdapter(MainUIBackend* backend, QObject* parent)
|
|
: QObject(parent)
|
|
, m_backend(backend)
|
|
{
|
|
if (!m_backend) {
|
|
qFatal("ShellHostAdapter requires a MainUIBackend instance");
|
|
}
|
|
|
|
// Signal → observer translation. Every forward is guarded on m_observer:
|
|
// the shell detaches during destroyShell(), but PluginLoader dispatches
|
|
// through QTimer::singleShot(0, ...) and a 30s ViewModuleHost timeout, so
|
|
// a backend signal can still arrive afterwards.
|
|
connect(m_backend, &MainUIBackend::currentActiveSectionIndexChanged, this, [this]() {
|
|
if (!m_observer || !m_backend) return;
|
|
m_observer->onSectionIndexChanged(m_backend->currentActiveSectionIndex());
|
|
});
|
|
|
|
connect(m_backend, &MainUIBackend::navigateToApps, this, [this]() {
|
|
if (!m_observer) return;
|
|
m_observer->onNavigateToApps();
|
|
});
|
|
|
|
connect(m_backend, &MainUIBackend::pluginWindowRequested, this,
|
|
[this](QWidget* widget, const QString& title) {
|
|
if (!m_observer) return;
|
|
m_observer->onPluginWindowRequested(widget, title);
|
|
});
|
|
|
|
connect(m_backend, &MainUIBackend::pluginWindowRemoveRequested, this,
|
|
[this](QWidget* widget) {
|
|
if (!m_observer) return;
|
|
m_observer->onPluginWindowRemoveRequested(widget);
|
|
});
|
|
|
|
connect(m_backend, &MainUIBackend::pluginWindowActivateRequested, this,
|
|
[this](QWidget* widget) {
|
|
if (!m_observer) return;
|
|
m_observer->onPluginWindowActivateRequested(widget);
|
|
});
|
|
}
|
|
|
|
ShellHostAdapter::~ShellHostAdapter() = default;
|
|
|
|
QObject* ShellHostAdapter::backendObject()
|
|
{
|
|
return m_backend.data();
|
|
}
|
|
|
|
int ShellHostAdapter::currentSectionIndex() const
|
|
{
|
|
return m_backend ? m_backend->currentActiveSectionIndex() : 0;
|
|
}
|
|
|
|
void ShellHostAdapter::setCurrentSectionIndex(int index)
|
|
{
|
|
if (m_backend) m_backend->setCurrentActiveSectionIndex(index);
|
|
}
|
|
|
|
void ShellHostAdapter::loadUiModule(const QString& name)
|
|
{
|
|
if (m_backend) m_backend->loadUiModule(name);
|
|
}
|
|
|
|
void ShellHostAdapter::unloadUiModule(const QString& name)
|
|
{
|
|
if (m_backend) m_backend->unloadUiModule(name);
|
|
}
|
|
|
|
void ShellHostAdapter::setCurrentVisibleApp(const QString& name)
|
|
{
|
|
if (m_backend) m_backend->setCurrentVisibleApp(name);
|
|
}
|
|
|
|
QString ShellHostAdapter::displayNameFor(const QString& name) const
|
|
{
|
|
// Same fallback the shell used to apply inline when the backend was null.
|
|
return m_backend ? m_backend->displayNameFor(name) : name;
|
|
}
|
|
|
|
void ShellHostAdapter::setObserver(IShellObserver* observer)
|
|
{
|
|
m_observer = observer;
|
|
}
|