Logo ROOT  
Reference Guide
RCanvas.cxx
Go to the documentation of this file.
1 /*************************************************************************
2  * Copyright (C) 1995-2015, Rene Brun and Fons Rademakers. *
3  * All rights reserved. *
4  * *
5  * For the licensing terms see $ROOTSYS/LICENSE. *
6  * For the list of contributors see $ROOTSYS/README/CREDITS. *
7  *************************************************************************/
8 
9 #include "ROOT/RCanvas.hxx"
10 
11 #include "ROOT/RLogger.hxx"
12 
13 #include <algorithm>
14 #include <memory>
15 #include <mutex>
16 #include <thread>
17 #include <chrono>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include "TList.h"
22 #include "TROOT.h"
23 
24 namespace {
25 
26 static std::mutex &GetHeldCanvasesMutex()
27 {
28  static std::mutex sMutex;
29  return sMutex;
30 }
31 
32 static std::vector<std::shared_ptr<ROOT::Experimental::RCanvas>> &GetHeldCanvases()
33 {
34  static std::vector<std::shared_ptr<ROOT::Experimental::RCanvas>> sCanvases;
35  return sCanvases;
36 }
37 
38 
39 } // namespace
40 
41 ///////////////////////////////////////////////////////////////////////////////////////
42 /// Returns list of created canvases
43 
44 const std::vector<std::shared_ptr<ROOT::Experimental::RCanvas>> ROOT::Experimental::RCanvas::GetCanvases()
45 {
46  std::lock_guard<std::mutex> grd(GetHeldCanvasesMutex());
47 
48  return GetHeldCanvases();
49 }
50 
51 ///////////////////////////////////////////////////////////////////////////////////////
52 /// Release list of held canvases pointers
53 /// If no other shared pointers exists on the canvas, object will be destroyed
54 
56 {
57  std::vector<std::shared_ptr<ROOT::Experimental::RCanvas>> vect;
58 
59  {
60  std::lock_guard<std::mutex> grd(GetHeldCanvasesMutex());
61 
62  std::swap(vect, GetHeldCanvases());
63  }
64 }
65 
66 ///////////////////////////////////////////////////////////////////////////////////////
67 /// Returns true is canvas was modified since last painting
68 
70 {
71  return fPainter ? fPainter->IsCanvasModified(fModified) : fModified;
72 }
73 
74 ///////////////////////////////////////////////////////////////////////////////////////
75 /// Update canvas
76 
78 {
79  if (fPainter)
80  fPainter->CanvasUpdated(fModified, async, callback);
81 }
82 
83 class RCanvasCleanup : public TObject {
84 public:
85 
86  static RCanvasCleanup *gInstance;
87 
88  RCanvasCleanup() : TObject() { gInstance = this; }
89 
90  virtual ~RCanvasCleanup()
91  {
92  gInstance = nullptr;
94  }
95 };
96 
97 RCanvasCleanup *RCanvasCleanup::gInstance = nullptr;
98 
99 
100 ///////////////////////////////////////////////////////////////////////////////////////
101 /// Create new canvas instance
102 
103 std::shared_ptr<ROOT::Experimental::RCanvas> ROOT::Experimental::RCanvas::Create(const std::string &title)
104 {
105  auto pCanvas = std::make_shared<RCanvas>();
106  pCanvas->SetTitle(title);
107  {
108  std::lock_guard<std::mutex> grd(GetHeldCanvasesMutex());
109  GetHeldCanvases().emplace_back(pCanvas);
110  }
111 
112  if (!RCanvasCleanup::gInstance) {
113  auto cleanup = new RCanvasCleanup();
114  TDirectory *dummydir = new TDirectory("rcanvas_cleanup_dummydir","title");
115  dummydir->GetList()->Add(cleanup);
116  gROOT->GetListOfClosedObjects()->Add(dummydir);
117  }
118 
119  return pCanvas;
120 }
121 
122 //////////////////////////////////////////////////////////////////////////
123 /// Create new display for the canvas
124 /// The parameter `where` specifies which program could be used for display creation
125 /// Possible values:
126 ///
127 /// - `cef` Chromium Embeded Framework, local display, local communication
128 /// - `qt5` Qt5 WebEngine (when running via rootqt5), local display, local communication
129 /// - `browser` default system web-browser, communication via random http port from range 8800 - 9800
130 /// - `<prog>` any program name which will be started instead of default browser, like firefox or /usr/bin/opera
131 /// one could also specify $url in program name, which will be replaced with canvas URL
132 /// - `native` either any available local display or default browser
133 ///
134 /// Canvas can be displayed in several different places
135 
136 void ROOT::Experimental::RCanvas::Show(const std::string &where)
137 {
138  if (fPainter) {
139  bool isany = (fPainter->NumDisplays() > 0);
140 
141  if (!where.empty())
142  fPainter->NewDisplay(where);
143 
144  if (isany) return;
145  }
146 
147  if (!fModified)
148  fModified = 1; // 0 is special value, means no changes and no drawings
149 
150  if (!fPainter)
151  fPainter = Internal::RVirtualCanvasPainter::Create(*this);
152 
153  if (fPainter) {
154  fPainter->NewDisplay(where);
155  fPainter->CanvasUpdated(fModified, true, nullptr); // trigger async display
156  }
157 }
158 
159 //////////////////////////////////////////////////////////////////////////
160 /// Returns window name for canvas
161 
163 {
164  if (fPainter)
165  return fPainter->GetWindowAddr();
166 
167  return "";
168 }
169 
170 
171 //////////////////////////////////////////////////////////////////////////
172 /// Hide all canvas displays
173 
175 {
176  if (fPainter)
177  delete fPainter.release();
178 }
179 
180 //////////////////////////////////////////////////////////////////////////
181 /// Create image file for the canvas
182 /// Supported SVG (extension .svg), JPEG (extension .jpg or .jpeg) and PNG (extension .png)
183 
184 bool ROOT::Experimental::RCanvas::SaveAs(const std::string &filename)
185 {
186  if (!fPainter)
187  fPainter = Internal::RVirtualCanvasPainter::Create(*this);
188 
189  if (!fPainter)
190  return false;
191 
192  auto width = fSize[0].fVal;
193  auto height = fSize[1].fVal;
194 
195  return fPainter->ProduceBatchOutput(filename, width > 1 ? (int) width : 800, height > 1 ? (int) height : 600);
196 }
197 
198 //////////////////////////////////////////////////////////////////////////
199 /// Remove canvas from global canvas lists, will be destroyed once last shared_ptr is disappear
200 
202 {
203  std::lock_guard<std::mutex> grd(GetHeldCanvasesMutex());
204  auto &held = GetHeldCanvases();
205  auto indx = held.size();
206  while (indx-- > 0) {
207  if (held[indx].get() == this)
208  held.erase(held.begin() + indx);
209  }
210 }
211 
212 //////////////////////////////////////////////////////////////////////////
213 /// Run canvas functionality for the given time (in seconds)
214 /// Used to process canvas-related actions in the appropriate thread context.
215 /// Must be regularly called when canvas created and used in extra thread.
216 /// Time parameter specifies minimal execution time in seconds - if default value 0 is used,
217 /// just all pending actions will be performed.
218 /// When canvas is not yet displayed - just performs sleep for given time interval.
219 ///
220 /// Example of usage:
221 ///
222 /// ~~~ {.cpp}
223 /// void draw_canvas(bool &run_loop, std::make_shared<RH1D> hist)
224 /// {
225 /// auto canvas = RCanvas::Create("Canvas title");
226 /// canvas->Draw(hist)->SetLineColor(RColor::kBlue);
227 /// canvas->Show();
228 /// while (run_loop) {
229 /// pHist->Fill(1);
230 /// canvas->Modified();
231 /// canvas->Update();
232 /// canvas->Run(0.1); // process canvas events
233 /// }
234 ///
235 /// canvas->Remove();
236 /// }
237 ///
238 /// int main()
239 /// {
240 /// RAxisConfig xaxis(100, -10., 10.);
241 /// auto pHist = std::make_shared<RH1D>(xaxis);
242 /// bool run_loop = true;
243 ///
244 /// std::thread thrd(draw_canvas, run_loop, pHist);
245 /// std::this_thread::sleep_for(std::chrono::seconds(100));
246 /// run_loop = false;
247 /// thrd.join();
248 /// return 0;
249 /// }
250 /// ~~~
251 
253 {
254  if (fPainter) {
255  fPainter->Run(tm);
256  } else if (tm>0) {
257  std::this_thread::sleep_for(std::chrono::milliseconds(int(tm*1000)));
258  }
259 }
260 
261 //////////////////////////////////////////////////////////////////////////
262 /// To resolve problem with storing of shared pointers
263 /// Call this method when reading canvas from the file
264 /// Can be called many times - after reinitialization of shared pointers no changes will be performed
265 
267 {
269 
270  CollectShared(vect);
271 
272  for (unsigned n = 0; n < vect.size(); ++n) {
273  if (vect[n]->HasShared() || !vect[n]->GetIOPtr()) continue;
274 
275  auto shrd_ptr = vect[n]->MakeShared();
276 
277  for (auto n2 = n+1; n2 < vect.size(); ++n2) {
278  if (vect[n2]->GetIOPtr() == vect[n]->GetIOPtr()) {
279  if (vect[n2]->HasShared())
280  R__ERROR_HERE("Gpadv7") << "FATAL Shared pointer for same IO ptr already exists";
281  else
282  vect[n2]->SetShared(shrd_ptr);
283  }
284  }
285 
286  }
287 }
288 
289 
290 /////////////////////////////////////////////////////////////////////////////////////////////////
291 /// Apply attributes changes to the drawable
292 /// Return mask with actions which were really applied
293 
294 std::unique_ptr<ROOT::Experimental::RDrawableReply> ROOT::Experimental::RChangeAttrRequest::Process()
295 {
296  // suppress all changes coming from non-main connection
297  if (!GetContext().IsMainConn())
298  return nullptr;
299 
300  auto canv = const_cast<ROOT::Experimental::RCanvas *>(GetContext().GetCanvas());
301  if (!canv) return nullptr;
302 
303  if ((ids.size() != names.size()) || (ids.size() != values.size())) {
304  R__ERROR_HERE("Gpadv7") << "Mismatch of arrays size in RChangeAttrRequest";
305  return nullptr;
306  }
307 
308  Version_t vers = 0;
309 
310  for(int indx = 0; indx < (int) ids.size(); indx++) {
311  if (ids[indx] == "canvas") {
312  if (canv->GetAttrMap().Change(names[indx], values[indx].get())) {
313  if (!vers) vers = canv->IncModified();
314  canv->SetDrawableVersion(vers);
315  }
316  } else {
317  auto drawable = canv->FindPrimitiveByDisplayId(ids[indx]);
318  if (drawable && drawable->GetAttrMap().Change(names[indx], values[indx].get())) {
319  if (!vers) vers = canv->IncModified();
320  drawable->SetDrawableVersion(vers);
321  }
322  }
323  }
324 
325  fNeedUpdate = (vers > 0) && update;
326 
327  return nullptr; // no need for any reply
328 }
n
const Int_t n
Definition: legend1.C:16
TDirectory::GetList
virtual TList * GetList() const
Definition: TDirectory.h:167
Version_t
short Version_t
Definition: RtypesCore.h:65
ROOT::Experimental::RCanvas::Show
void Show(const std::string &where="")
Display the canvas.
Definition: RCanvas.cxx:136
ROOT::Experimental::RCanvas::Remove
void Remove()
Remove canvas from global canvas lists, will be destroyed when shared_ptr will be removed.
Definition: RCanvas.cxx:201
ROOT::Experimental::RCanvas::GetCanvases
static const std::vector< std::shared_ptr< RCanvas > > GetCanvases()
Returns list of created canvases.
Definition: RCanvas.cxx:44
width
include TDocParser_001 C image html pict1_TDocParser_001 png width
Definition: TDocParser.cxx:121
ROOT::Experimental::RCanvas::IsModified
bool IsModified() const
Returns true is canvas was modified since last painting.
Definition: RCanvas.cxx:69
ROOT::Experimental::Internal::RVirtualCanvasPainter::Create
static std::unique_ptr< RVirtualCanvasPainter > Create(RCanvas &canv)
Loads the plugin that implements this class.
Definition: RVirtualCanvasPainter.cxx:41
ROOT::Experimental::RCanvas::Create
static std::shared_ptr< RCanvas > Create(const std::string &title)
Create new canvas instance.
Definition: RCanvas.cxx:103
TList.h
ROOT::Experimental::RCanvas::Hide
void Hide()
Hide all canvas displays.
Definition: RCanvas.cxx:174
ROOT::Experimental::CanvasCallback_t
std::function< void(bool)> CanvasCallback_t
Definition: RVirtualCanvasPainter.hxx:19
RCanvas.hxx
TROOT.h
update
static void update(gsl_integration_workspace *workspace, double a1, double b1, double area1, double error1, double a2, double b2, double area2, double error2)
Definition: RooAdaptiveGaussKronrodIntegrator1D.cxx:652
ROOT::Experimental::RCanvas::Update
void Update(bool async=false, CanvasCallback_t callback=nullptr)
update drawing
Definition: RCanvas.cxx:77
RLogger.hxx
R__ERROR_HERE
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
ROOT::Experimental::RCanvas::GetWindowAddr
std::string GetWindowAddr() const
Returns window name used to display canvas.
Definition: RCanvas.cxx:162
ROOT::Experimental::RChangeAttrRequest::Process
std::unique_ptr< RDrawableReply > Process() override
Apply attributes changes to the drawable Return mask with actions which were really applied.
Definition: RCanvas.cxx:294
ROOT::Experimental::RCanvas::SaveAs
bool SaveAs(const std::string &filename)
Save canvas in image file.
Definition: RCanvas.cxx:184
ROOT::Experimental::RCanvas::ResolveSharedPtrs
void ResolveSharedPtrs()
To resolve problem with storing of shared pointers Call this method when reading canvas from the file...
Definition: RCanvas.cxx:266
ROOT::Experimental::Internal::RIOSharedVector_t
std::vector< RIOSharedBase * > RIOSharedVector_t
Definition: RDrawable.hxx:52
ROOT::Experimental::RCanvas
A window's topmost RPad.
Definition: RCanvas.hxx:47
TList::Add
virtual void Add(TObject *obj)
Definition: TList.h:87
TObject
Mother of all ROOT objects.
Definition: TObject.h:37
ROOT::Experimental::RCanvas::Run
void Run(double tm=0.)
Run canvas functionality for given time (in seconds)
Definition: RCanvas.cxx:252
ROOT::Experimental::Internal::swap
void swap(RDirectoryEntry &e1, RDirectoryEntry &e2) noexcept
Definition: RDirectoryEntry.hxx:94
TDirectory
Describe directory structure in memory.
Definition: TDirectory.h:40
fSize
size_t fSize
Definition: DeclareConverters.h:342
gROOT
#define gROOT
Definition: TROOT.h:406
int
ROOT::Experimental::RCanvas::ReleaseHeldCanvases
static void ReleaseHeldCanvases()
Release list of held canvases pointers If no other shared pointers exists on the canvas,...
Definition: RCanvas.cxx:55