Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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 "TROOT.h"
22 
23 namespace {
24 
25 static std::mutex &GetHeldCanvasesMutex()
26 {
27  static std::mutex sMutex;
28  return sMutex;
29 }
30 
31 static std::vector<std::shared_ptr<ROOT::Experimental::RCanvas>> &GetHeldCanvases()
32 {
33  static std::vector<std::shared_ptr<ROOT::Experimental::RCanvas>> sCanvases;
34  return sCanvases;
35 }
36 
37 
38 } // namespace
39 
40 const std::vector<std::shared_ptr<ROOT::Experimental::RCanvas>> ROOT::Experimental::RCanvas::GetCanvases()
41 {
42  std::lock_guard<std::mutex> grd(GetHeldCanvasesMutex());
43 
44  return GetHeldCanvases();
45 }
46 
47 ///////////////////////////////////////////////////////////////////////////////////////
48 /// Returns true is canvas was modified since last painting
49 
50 bool ROOT::Experimental::RCanvas::IsModified() const
51 {
52  return fPainter ? fPainter->IsCanvasModified(fModified) : fModified;
53 }
54 
55 void ROOT::Experimental::RCanvas::Update(bool async, CanvasCallback_t callback)
56 {
57  if (fPainter)
58  fPainter->CanvasUpdated(fModified, async, callback);
59 }
60 
61 std::shared_ptr<ROOT::Experimental::RCanvas> ROOT::Experimental::RCanvas::Create(const std::string &title)
62 {
63  auto pCanvas = std::make_shared<RCanvas>();
64  pCanvas->SetTitle(title);
65  {
66  std::lock_guard<std::mutex> grd(GetHeldCanvasesMutex());
67  GetHeldCanvases().emplace_back(pCanvas);
68  }
69  return pCanvas;
70 }
71 
72 //////////////////////////////////////////////////////////////////////////
73 /// Create new display for the canvas
74 /// The parameter `where` specifies which program could be used for display creation
75 /// Possible values:
76 ///
77 /// - `cef` Chromium Embeded Framework, local display, local communication
78 /// - `qt5` Qt5 WebEngine (when running via rootqt5), local display, local communication
79 /// - `browser` default system web-browser, communication via random http port from range 8800 - 9800
80 /// - `<prog>` any program name which will be started instead of default browser, like firefox or /usr/bin/opera
81 /// one could also specify $url in program name, which will be replaced with canvas URL
82 /// - `native` either any available local display or default browser
83 ///
84 /// Canvas can be displayed in several different places
85 
86 void ROOT::Experimental::RCanvas::Show(const std::string &where)
87 {
88  if (fPainter) {
89  bool isany = (fPainter->NumDisplays() > 0);
90 
91  if (!where.empty())
92  fPainter->NewDisplay(where);
93 
94  if (isany) return;
95  }
96 
97  if (!fModified)
98  fModified = 1; // 0 is special value, means no changes and no drawings
99 
100  if (!fPainter)
101  fPainter = Internal::RVirtualCanvasPainter::Create(*this);
102 
103  if (fPainter) {
104  fPainter->NewDisplay(where);
105  fPainter->CanvasUpdated(fModified, true, nullptr); // trigger async display
106  }
107 }
108 
109 //////////////////////////////////////////////////////////////////////////
110 /// Returns window name for canvas
111 
112 std::string ROOT::Experimental::RCanvas::GetWindowAddr() const
113 {
114  if (fPainter)
115  return fPainter->GetWindowAddr();
116 
117  return "";
118 }
119 
120 
121 //////////////////////////////////////////////////////////////////////////
122 /// Hide all canvas displays
123 
124 void ROOT::Experimental::RCanvas::Hide()
125 {
126  if (fPainter)
127  delete fPainter.release();
128 }
129 
130 //////////////////////////////////////////////////////////////////////////
131 /// Create image file for the canvas
132 /// Supported SVG (extension .svg), JPEG (extension .jpg or .jpeg) and PNG (extension .png)
133 /// \param async specifies if file can be created asynchronous to the caller thread
134 /// When operation completed, callback function is called
135 
136 void ROOT::Experimental::RCanvas::SaveAs(const std::string &filename, bool async, CanvasCallback_t callback)
137 {
138  if (!fPainter)
139  fPainter = Internal::RVirtualCanvasPainter::Create(*this);
140 
141  if (!fModified)
142  fModified = 1; // 0 is special value, means no changes and no drawings
143 
144  // TODO: for the future one have to ensure only batch connection is updated
145  Update(); // ensure that snapshot is created
146 
147  if (filename.find(".json") != std::string::npos) {
148  fPainter->DoWhenReady("JSON", filename, async, callback);
149  } else if (filename.find(".svg") != std::string::npos)
150  fPainter->DoWhenReady("SVG", filename, async, callback);
151  else if (filename.find(".png") != std::string::npos)
152  fPainter->DoWhenReady("PNG", filename, async, callback);
153  else if ((filename.find(".jpg") != std::string::npos) || (filename.find(".jpeg") != std::string::npos))
154  fPainter->DoWhenReady("JPEG", filename, async, callback);
155 }
156 
157 //////////////////////////////////////////////////////////////////////////
158 /// Remove canvas from global canvas lists, will be destroyed once last shared_ptr is disappear
159 
160 void ROOT::Experimental::RCanvas::Remove()
161 {
162  std::lock_guard<std::mutex> grd(GetHeldCanvasesMutex());
163  auto &held = GetHeldCanvases();
164  auto indx = held.size();
165  while (indx-- > 0) {
166  if (held[indx].get() == this)
167  held.erase(held.begin() + indx);
168  }
169 }
170 
171 //////////////////////////////////////////////////////////////////////////
172 /// Run canvas functionality for the given time (in seconds)
173 /// Used to process canvas-related actions in the appropriate thread context.
174 /// Must be regularly called when canvas created and used in extra thread.
175 /// Time parameter specifies minimal execution time in seconds - if default value 0 is used,
176 /// just all pending actions will be performed.
177 /// When canvas is not yet displayed - just performs sleep for given time interval.
178 ///
179 /// Example of usage:
180 ///
181 /// ~~~ {.cpp}
182 /// void draw_canvas(bool &run_loop, std::make_shared<RH1D> hist)
183 /// {
184 /// auto canvas = RCanvas::Create("Canvas title");
185 /// canvas->Draw(hist)->SetLineColor(RColor::kBlue);
186 /// canvas->Show();
187 /// while (run_loop) {
188 /// pHist->Fill(1);
189 /// canvas->Modified();
190 /// canvas->Update();
191 /// canvas->Run(0.1); // process canvas events
192 /// }
193 ///
194 /// canvas->Remove();
195 /// }
196 ///
197 /// int main()
198 /// {
199 /// RAxisConfig xaxis(100, -10., 10.);
200 /// auto pHist = std::make_shared<RH1D>(xaxis);
201 /// bool run_loop = true;
202 ///
203 /// std::thread thrd(draw_canvas, run_loop, pHist);
204 /// std::this_thread::sleep_for(std::chrono::seconds(100));
205 /// run_loop = false;
206 /// thrd.join();
207 /// return 0;
208 /// }
209 /// ~~~
210 
211 void ROOT::Experimental::RCanvas::Run(double tm)
212 {
213  if (fPainter) {
214  fPainter->Run(tm);
215  } else if (tm>0) {
216  std::this_thread::sleep_for(std::chrono::milliseconds(int(tm*1000)));
217  }
218 }
219 
220 //////////////////////////////////////////////////////////////////////////
221 /// To resolve problem with storing of shared pointers
222 /// Call this method when reading canvas from the file
223 /// Can be called many times - after reinitialization of shared pointers no changes will be performed
224 
225 void ROOT::Experimental::RCanvas::ResolveSharedPtrs()
226 {
227  Internal::RIOSharedVector_t vect;
228 
229  CollectShared(vect);
230 
231  for (unsigned n = 0; n < vect.size(); ++n) {
232  if (vect[n]->HasShared() || !vect[n]->GetIOPtr()) continue;
233 
234  auto shrd_ptr = vect[n]->MakeShared();
235 
236  for (auto n2 = n+1; n2 < vect.size(); ++n2) {
237  if (vect[n2]->GetIOPtr() == vect[n]->GetIOPtr()) {
238  if (vect[n2]->HasShared())
239  R__ERROR_HERE("Gpadv7") << "FATAL Shared pointer for same IO ptr already exists";
240  else
241  vect[n2]->SetShared(shrd_ptr);
242  }
243  }
244 
245  }
246 }