Something went wrong. Try again.
The agentic engineering control plane for the posthuman future
Something went wrong. Try again.
11 kB · 354 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355#include "MissionControlController.h"
#include "AppModel.h"#include "PanePool.h"#include "SplitTree.h"#include "Workspace.h"
using namespace Qt::Literals::StringLiterals;
namespace {
// Pixels of movement before a press becomes a drag. Below it, release is// a click.constexpr qreal kDragThreshold = 8.0;
// Drop specificity. The most specific claim for a release wins, which// makes the result independent of QML signal-handler ordering: a pane's// zone beats the card's append backdrop, which beats the row's newtab.int zoneRank(const QString& zone){ if (zone == u"newtab"_s) { return 1; } if (zone == u"append"_s) { return 2; } return 3;}
int paneCountOf(const XenoTab* tab){ if (tab == nullptr || tab->treeRoot() == nullptr) { return 0; } return static_cast<int>(paneRectsNormalized(*tab->treeRoot()).size());}
} // namespace
MissionControlController::MissionControlController(QObject* parent) : QObject(parent){}
AppModel* MissionControlController::model() const{ return m_model;}
void MissionControlController::setModel(AppModel* model){ if (m_model == model) { return; } m_model = model; emit modelChanged();}
PanePool* MissionControlController::pool() const{ return m_pool;}
void MissionControlController::setPool(PanePool* pool){ if (m_pool == pool) { return; } m_pool = pool; emit poolChanged();}
// --- pointer ingestion -------------------------------------------------------
void MissionControlController::setScene(const qreal sceneX, const qreal sceneY){ if (m_scene == QPointF{sceneX, sceneY}) { return; } m_scene = {sceneX, sceneY}; emit pointerChanged();}
void MissionControlController::pointerPressed(const qreal sceneX, const qreal sceneY){ setScene(sceneX, sceneY); m_press = {sceneX, sceneY}; m_clickPaneId = QString(); emit pressChanged(); // A fresh press clears the previous gesture's armed flag, so a release // handler can read dragArmed as "this press became a drag". if (m_dragArmed) { m_dragArmed = false; emit dragArmedChanged(); } if (!m_pressed) { m_pressed = true; emit pressedChanged(); }}
void MissionControlController::pointerMoved(const qreal sceneX, const qreal sceneY){ setScene(sceneX, sceneY); if (!m_pressed || m_dragArmed) { return; } const qreal dx = sceneX - m_press.x(); const qreal dy = sceneY - m_press.y(); if ((dx * dx) + (dy * dy) < (kDragThreshold * kDragThreshold)) { return; } m_dragArmed = true; emit dragArmedChanged();}
void MissionControlController::pointerReleased(const qreal sceneX, const qreal sceneY){ // Publish the release position first so every containment binding // re-evaluates before anyone claims. setScene(sceneX, sceneY); m_pressed = false; // QML signal delivery is synchronous: by the time this returns, every // hot MissionDropZone has called finishDrag() and any clicked pane has // called claimClick(). emit pressedChanged();
if (m_dragActive) { if (m_claimZone.isEmpty()) { // Nothing legal under the pointer: the drag is abandoned. cancelDrag(); } else { executeClaim(); } return; }
// Not a drag: a click. Reveal the clicked pane (if any), then close. // The engine — not competing QML handlers — owns this so "reveal the // pane" can never race "close the overlay". if (!m_clickPaneId.isEmpty() && m_model != nullptr) { m_model->revealPane(m_clickPaneId); } m_clickPaneId = QString(); emit closeRequested();}
void MissionControlController::claimClick(const QString& paneId){ // Only a press that never armed a drag is a click; the first pane to // claim wins (panes tile the fit box, so at most one contains it). if (m_pressed || m_dragArmed || m_dragActive) { return; } if (m_clickPaneId.isEmpty()) { m_clickPaneId = paneId; }}
// --- drag engine -------------------------------------------------------------
void MissionControlController::beginDrag(const QString& paneId, const int wsIndex, const int tabIndex, const qreal grabX, const qreal grabY, const qreal baseW, const qreal baseH){ // The first pane to claim the press owns the drag. if (m_dragActive || paneId.isEmpty()) { return; } m_dragActive = true; m_draggedPaneId = paneId; m_grab = {grabX, grabY}; m_ghostBase = {baseW, baseH}; m_sourceWs = wsIndex; m_sourceTab = tabIndex; m_claimZone = QString(); m_claimPaneId = QString(); m_claimWs = -1; m_claimTab = -1;
// Resolve the ghost's snapshot target and publish the drag-active state // BEFORE capturing. The overlay watches dragActiveChanged (Connections // below) and performs the capture itself: the grab must be masked // (hide the opaque backdrop for the synchronous full-window grab), and // masking is scene-graph work that never belongs in this class. m_snapshotTarget = nullptr; if (m_pool != nullptr) { m_snapshotTarget = m_pool->item(paneId); } emit dragActiveChanged();}
void MissionControlController::finishDrag(const QString& zone, const QString& paneId, const int wsIndex, const int tabIndex){ if (!m_dragActive || zone.isEmpty()) { return; } // Highest specificity wins; ties keep the first claim. if (!m_claimZone.isEmpty() && zoneRank(m_claimZone) >= zoneRank(zone)) { return; } m_claimZone = zone; m_claimPaneId = paneId; m_claimWs = wsIndex; m_claimTab = tabIndex;}
void MissionControlController::executeClaim(){ const QString zone = m_claimZone; if (m_model == nullptr || isIllegalDrop(zone, m_claimPaneId, m_claimWs, m_claimTab)) { resetDragState(); return; } // Defer the mutation one event-loop turn. The QML ghost is a live // ShaderEffectSource over the dragged pane's TerminalQuickItem; the drop // re-parents / re-adopts that item, and sampling a reparenting RHI item // wedges its render layer — the pane lands black in its new split (the // "void"). Release the sample (dragActiveChanged → the QML SES source // unbinds) and let one render pass process the unbind BEFORE the model // mutates. An emit alone is not enough: a synchronous emit only marks the // QML binding dirty; the scene graph still holds the stale source pointer // until the next sync, which would otherwise run after the reparent. m_snapshotTarget = nullptr; m_dragActive = false; emit dragActiveChanged(); QMetaObject::invokeMethod(this, &MissionControlController::executeQueuedDrop, Qt::QueuedConnection);}
// The deferred half of executeClaim. Claim fields and draggedPaneId are// still set (only dragActive/snapshotTarget were released); finishDrag and// beginDrag both guard on dragActive, so nothing can mutate the claim// during the gap.void MissionControlController::executeQueuedDrop(){ const QString zone = m_claimZone; if (m_model == nullptr || m_draggedPaneId.isEmpty() || zone.isEmpty()) { resetDragState(); return; } if (zone == u"center"_s) { m_model->swapPanes(m_draggedPaneId, m_claimPaneId); } else if (zone == u"append"_s) { m_model->movePaneToTab(m_draggedPaneId, m_claimWs, m_claimTab); } else if (zone == u"newtab"_s) { m_model->movePaneToNewTab(m_draggedPaneId, m_claimWs); } else { m_model->movePaneBeside(m_draggedPaneId, m_claimPaneId, zone); } emit dropExecuted(zone); resetDragState();}
void MissionControlController::cancelDrag(){ resetDragState();}
bool MissionControlController::legalDrop(const QString& zone, const QString& paneId, const int wsIndex, const int tabIndex) const{ if (!m_dragActive || zone.isEmpty()) { return false; } return !isIllegalDrop(zone, paneId, wsIndex, tabIndex);}
// Mirrors AppModel's four pane-move guards exactly, so a lit zone always// mutates and a refused drop never lights. Source facts:// movePaneBeside (edge zones): refuses a self-drop; same-tab needs >=2// source panes; cross-tab refuses only the workspace's last pane of// its last tab.// swapPanes (center): refuses only a self-swap.// movePaneToTab (append): refuses srcTree<2; cross-tab out of a// single-tab source workspace.// movePaneToNewTab (newtab): refuses cross-workspace when the source is// one tab of one pane (it would delete the source workspace).bool MissionControlController::isIllegalDrop(const QString& zone, const QString& paneId, const int wsIndex, const int tabIndex) const{ if (m_model == nullptr || m_sourceWs < 0 || m_sourceTab < 0) { return false; } const QList<Workspace*> workspaces = m_model->workspaces(); if (m_sourceWs >= workspaces.size()) { return false; } const QList<XenoTab*> srcTabs = workspaces.at(m_sourceWs)->tabs(); const int srcTabCount = static_cast<int>(srcTabs.size()); if (m_sourceTab >= srcTabCount) { return false; } const int srcPanes = paneCountOf(srcTabs.at(m_sourceTab)); const bool sameTab = (wsIndex == m_sourceWs && tabIndex == m_sourceTab); // The source workspace's only tab holding only the dragged pane: moving // it out would silently delete the workspace. const bool onlyPaneOfOnlyTab = (srcTabCount <= 1 && srcPanes <= 1); const bool self = (!paneId.isEmpty() && paneId == m_draggedPaneId);
if (zone == u"center"_s) { return self; } if (zone == u"newtab"_s) { return (wsIndex != m_sourceWs) && onlyPaneOfOnlyTab; } if (zone == u"append"_s) { return srcPanes < 2 || (!sameTab && srcTabCount <= 1); } // Edge zones (left/right/up/down) -> movePaneBeside. if (self) { return true; } if (sameTab) { return srcPanes < 2; } return onlyPaneOfOnlyTab;}
void MissionControlController::resetDragState(){ const bool wasActive = m_dragActive; m_dragActive = false; m_draggedPaneId = QString(); m_grab = {0, 0}; m_ghostBase = {0, 0}; m_sourceWs = -1; m_sourceTab = -1; m_claimZone = QString(); m_claimPaneId = QString(); m_claimWs = -1; m_claimTab = -1; m_snapshotTarget = nullptr; if (wasActive) { emit dragActiveChanged(); }}