From 8911b9333303d9fa13bcf4ce544c070bcfd003b0 Mon Sep 17 00:00:00 2001 From: Matevz Tadel Date: Thu, 5 Nov 2026 14:10:14 -0800 Subject: [PATCH] [eve7] Clear a scene's output after streaming it to a new connection REveManager::WindowConnect() streams the world and the mandatory scenes to the new connection with StreamElements() and sends the output to that connection only, but leaves it in the scene. The next change cycle then runs SendChangesToSubscribers(), which sends whatever output a scene holds to every subscriber: every client received the full StreamElements of the world and of the mandatory scenes once more, re-ran onEveManagerInit(), rebuilt the summary tree and closed the editor. The same happened in the MIR path that subscribes a viewer to a scene later, where SendSceneChanges() follows the direct send immediately, so the new client got the full stream twice. Added REveScene::ClearOutput(), which drops fOutputJson, fOutputBinary and fTotalBinarySize, and call it after each direct send in both paths. SendChangesToSubscribers() uses it for the clearing it already did. Verified in the browser on track_set_collection.C: the editor of the track set stays open across the first MIR after a page load; before the change the first MIR closed it. Assisted-by: Claude:Fable 5.1 --- graf3d/eve7/inc/ROOT/REveScene.hxx | 1 + graf3d/eve7/src/REveManager.cxx | 7 +++++++ graf3d/eve7/src/REveScene.cxx | 11 +++++++++++ 3 files changed, 19 insertions(+) diff --git a/graf3d/eve7/inc/ROOT/REveScene.hxx b/graf3d/eve7/inc/ROOT/REveScene.hxx index 52ed28257cfb6..1cd75f71bc651 100644 --- a/graf3d/eve7/inc/ROOT/REveScene.hxx +++ b/graf3d/eve7/inc/ROOT/REveScene.hxx @@ -107,6 +107,7 @@ public: void StreamMotionChanges(nlohmann::json &arr); void SendChangesToSubscribers(); + void ClearOutput(); /// Output of the last StreamElements() or StreamRepresentationChanges(). const std::string &GetOutputJson() const { return fOutputJson; } diff --git a/graf3d/eve7/src/REveManager.cxx b/graf3d/eve7/src/REveManager.cxx index 765f1af1cbc72..ab907bd65835c 100644 --- a/graf3d/eve7/src/REveManager.cxx +++ b/graf3d/eve7/src/REveManager.cxx @@ -889,6 +889,9 @@ void REveManager::StreamToNewConnection(unsigned connid) Send(connid, fWorld->fOutputJson); printf(" for now assume world-scene has no render data, binary-size=%d\n", fWorld->fTotalBinarySize); assert(fWorld->fTotalBinarySize == 0); + // Sent to this connection only; the next SendSceneChanges() must not send + // it to everyone again. + fWorld->ClearOutput(); for (auto &c : fScenes->RefChildren()) { REveScene *scene = dynamic_cast(c); @@ -911,6 +914,7 @@ void REveManager::StreamToNewConnection(unsigned connid) } else { printf(" NOT sending binary, len = %d\n", scene->fTotalBinarySize); } + scene->ClearOutput(); } fServerState.fCV.notify_all(); @@ -1302,6 +1306,9 @@ void REveManager::MIRExecThread() Send(mir->fConnId, scene->fOutputJson); if (scene->fTotalBinarySize > 0) SendBinary(mir->fConnId, &scene->fOutputBinary[0], scene->fTotalBinarySize); + // Streamed to this connection only; SendSceneChanges() below must + // not send it to every subscriber. + scene->ClearOutput(); } SendSceneChanges(); diff --git a/graf3d/eve7/src/REveScene.cxx b/graf3d/eve7/src/REveScene.cxx index 95cc14fa13277..f7069b4eea7f9 100644 --- a/graf3d/eve7/src/REveScene.cxx +++ b/graf3d/eve7/src/REveScene.cxx @@ -371,6 +371,17 @@ void REveScene::SendChangesToSubscribers() } REX::gEve->SceneSubscriberWaitingResponse(client->fId); } + ClearOutput(); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Drop the output of the last StreamElements() or +/// StreamRepresentationChanges() once it has been sent, so that the next +/// SendChangesToSubscribers() does not send it again. REveManager calls this +/// after streaming a scene directly to one new connection. + +void REveScene::ClearOutput() +{ fOutputJson.clear(); fOutputBinary.clear(); fTotalBinarySize = 0;