From e4b293fe3ba15879056d0fd3740793ec5455c616 Mon Sep 17 00:00:00 2001 From: Sergey Linev <S.Linev@gsi.de> Date: Thu, 27 Jul 2017 12:12:31 +0200 Subject: [PATCH] webgui: implement sync and async mode for Canvas::SaveAs() method When synchronous mode specified (defualt), method blocked until file is produced. With asynchronous mode method returned and file will be produced in background. --- graf2d/gpad/v7/inc/ROOT/TCanvas.hxx | 2 +- .../v7/inc/ROOT/TVirtualCanvasPainter.hxx | 2 +- graf2d/gpad/v7/src/TCanvas.cxx | 6 +-- gui/canvaspainter/v7/src/TCanvasPainter.cxx | 39 +++++++++++++++++-- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx b/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx index f96904f2979..9a98b8b2d02 100644 --- a/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx +++ b/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx @@ -139,7 +139,7 @@ public: void Update(bool async = false); /// Save canvas in image file - void SaveAs(const std::string &filename); + void SaveAs(const std::string &filename, bool async = false); /// Get the canvas's title. const std::string &GetTitle() const { return fTitle; } diff --git a/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx b/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx index 1c0195acbde..446dcbf936b 100644 --- a/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx +++ b/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx @@ -60,7 +60,7 @@ public: virtual bool IsCanvasModified(uint64_t) const = 0; /// perform special action when drawing is ready - virtual void DoWhenReady(const std::string &, const std::string &) = 0; + virtual void DoWhenReady(const std::string &, const std::string &, bool) = 0; virtual void NewDisplay(const std::string &where) = 0; diff --git a/graf2d/gpad/v7/src/TCanvas.cxx b/graf2d/gpad/v7/src/TCanvas.cxx index 79db04fce18..38c2e50e015 100644 --- a/graf2d/gpad/v7/src/TCanvas.cxx +++ b/graf2d/gpad/v7/src/TCanvas.cxx @@ -101,14 +101,14 @@ void ROOT::Experimental::TCanvas::Show(const std::string &where) } } -void ROOT::Experimental::TCanvas::SaveAs(const std::string &filename) +void ROOT::Experimental::TCanvas::SaveAs(const std::string &filename, bool async) { if (!fPainter) fPainter = Internal::TVirtualCanvasPainter::Create(*this, true); if (filename.find(".svg") != std::string::npos) - fPainter->DoWhenReady("SVG", filename); + fPainter->DoWhenReady("SVG", filename, async); else if (filename.find(".png") != std::string::npos) - fPainter->DoWhenReady("PNG", filename); + fPainter->DoWhenReady("PNG", filename, async); } // TODO: removal from GetHeldCanvases(). diff --git a/gui/canvaspainter/v7/src/TCanvasPainter.cxx b/gui/canvaspainter/v7/src/TCanvasPainter.cxx index 16fa8cfc58e..43f68f1dc01 100644 --- a/gui/canvaspainter/v7/src/TCanvasPainter.cxx +++ b/gui/canvaspainter/v7/src/TCanvasPainter.cxx @@ -195,6 +195,7 @@ private: ROOT::Experimental::TPadDisplayItem fDisplayList; ///!< full list of items to display WebCommandsList fCmds; ///!< list of submitted commands uint64_t fCmdsCnt; ///!< commands counter + std::string fWaitingCmdId; ///!< command id waited for complition uint64_t fSnapshotVersion; ///!< version of snapshot std::string fSnapshot; ///!< last produced snapshot @@ -232,7 +233,7 @@ public: /// The painter observes it; it needs to know should the TCanvas be deleted. TCanvasPainter(const std::string &name, const ROOT::Experimental::TCanvas &canv, bool batch_mode) : THttpWSHandler(name.c_str(), "title"), fCanvas(canv), fBatchMode(batch_mode), fWebConn(), fDisplayList(), - fCmds(), fCmdsCnt(0), fSnapshotVersion(0), fSnapshot(), fSnapshotDelivered(0) + fCmds(), fCmdsCnt(0), fWaitingCmdId(), fSnapshotVersion(0), fSnapshot(), fSnapshotDelivered(0) { CreateHttpServer(); gServer->Register("/web7gui", this); @@ -247,7 +248,7 @@ public: virtual bool IsCanvasModified(uint64_t) const override; /// perform special action when drawing is ready - virtual void DoWhenReady(const std::string &cmd, const std::string &arg) final; + virtual void DoWhenReady(const std::string &cmd, const std::string &arg, bool async) final; // open new display for the canvas virtual void NewDisplay(const std::string &where) override; @@ -429,15 +430,42 @@ bool TCanvasPainter::WaitWhenCanvasPainted(uint64_t ver) return false; } -void TCanvasPainter::DoWhenReady(const std::string &name, const std::string &arg) +void TCanvasPainter::DoWhenReady(const std::string &name, const std::string &arg, bool async) { + if (!async && !fWaitingCmdId.empty()) { + Error("DoWhenReady", "Fail to submit sync command when previous is still awaited - use async"); + async = true; + } + WebCommand cmd; - cmd.fId = TString::ULLtoa(fCmdsCnt++, 10); + cmd.fId = TString::ULLtoa(++fCmdsCnt, 10); cmd.fName = name; cmd.fArg = arg; cmd.fRunning = false; fCmds.push_back(cmd); + + if (!async) fWaitingCmdId = cmd.fId; + CheckDataToSend(); + + if (async) return; + + uint64_t cnt = 0; + bool had_connection = false; + + while (true) { + if (fWebConn.size() > 0) + had_connection = true; + if ((fWebConn.size() == 0) && (had_connection || (cnt > 1000))) + return; // wait ~1 min if no new connection established + if (fWaitingCmdId.empty()) { + printf("Command %s waiting READY!!!\n", name.c_str()); + return; + } + gSystem->ProcessEvents(); + gSystem->Sleep((++cnt < 500) ? 1 : 100); // increase sleep interval when do very often + } + } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -448,6 +476,9 @@ void TCanvasPainter::PopFrontCommand(bool) { if (fCmds.size() == 0) return; + // simple condition, which will be checked in waiting loop + if (!fWaitingCmdId.empty() && (fWaitingCmdId == fCmds.front().fId)) fWaitingCmdId.clear(); + fCmds.pop_front(); } -- GitLab