Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
REveManager.cxx
Go to the documentation of this file.
1// @(#)root/eve7:$Id$
2// Authors: Matevz Tadel & Alja Mrak-Tadel: 2006, 2007
3
4/*************************************************************************
5 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include <ROOT/REveManager.hxx>
13
14#include <ROOT/REveCamera.hxx>
15#include <ROOT/REveUtil.hxx>
17#include <ROOT/REveViewer.hxx>
18#include <ROOT/REveScene.hxx>
20#include <ROOT/REveClient.hxx>
21#include <ROOT/RWebWindow.hxx>
22#include <ROOT/RLogger.hxx>
23#include <ROOT/REveSystem.hxx>
26
27#include "TGeoManager.h"
28#include "TGeoMatrix.h"
29#include "TObjString.h"
30#include "TROOT.h"
31#include "TSystem.h"
32#include "TFile.h"
33#include "TMap.h"
34#include "TExMap.h"
35#include "TEnv.h"
36#include "TError.h"
37#include "TColor.h"
38#include "TPRegexp.h"
39#include "TClass.h"
40#include "TMethod.h"
41#include "TMethodCall.h"
42#include "THttpServer.h"
43#include "TTimer.h"
44#include "TApplication.h"
45
46#include <exception>
47#include <fstream>
48#include <memory>
49#include <sstream>
50#include <iostream>
51#include <regex>
52#include <system_error>
53#include <thread>
54
55#if defined(R__LINUX) || defined(R__MACOSX)
56#include <pthread.h>
57#endif
58
59#include <nlohmann/json.hpp>
60
61using namespace ROOT::Experimental;
62namespace REX = ROOT::Experimental;
63
64REveManager *REX::gEve = nullptr;
65
67{
68 std::vector<REveScene*> addedWatch;
69 std::vector<REveScene*> removedWatch;
70
71 void reset() {
72 addedWatch.clear();
73 removedWatch.clear();
74 }
75};
76
77thread_local std::vector<ROOT::RLogEntry> gEveLogEntries;
79
80namespace {
81
82/// Stack size of the calling thread in bytes, or 0 if it cannot be determined.
83size_t CurrentThreadStackSize()
84{
85#if defined(R__LINUX)
86 size_t size = 0;
87 pthread_attr_t attr;
88 if (pthread_getattr_np(pthread_self(), &attr) == 0) {
89 pthread_attr_getstacksize(&attr, &size);
90 pthread_attr_destroy(&attr);
91 }
92 return size;
93#elif defined(R__MACOSX)
94 return pthread_get_stacksize_np(pthread_self());
95#else
96 return 0;
97#endif
98}
99
100} // namespace
101
102/** \class REveManager
103\ingroup REve
104\ingroup webwidgets
105
106\brief Central application manager for web-based REve.
107
108Manages elements, GUI, GL scenes and GL viewers.
109
110Following parameters can be specified in .rootrc file
111
112WebEve.GLViewer: Three # kind of GLViewer, either Three, JSRoot or RCore
113WebEve.DisableShow: 1 # do not start new web browser when REveManager::Show is called
114WebEve.HTimeout: 200 # timeout in ms for elements highlight
115WebEve.DblClick: Off # mouse double click handling in GL viewer: Off or Reset
116WebEve.TableRowHeight: 33 # size of each row in pixels in the Table view, can be used to make design more compact
117*/
118
119////////////////////////////////////////////////////////////////////////////////
120
121REveManager::REveManager()
122 : // (Bool_t map_window, Option_t* opt) :
123 fExcHandler(nullptr), fVizDB(nullptr), fVizDBReplace(kTRUE), fVizDBUpdate(kTRUE), fGeometries(nullptr),
124 fGeometryAliases(nullptr),
125 fKeepEmptyCont(kFALSE)
126{
127 // Constructor.
128
129 static const REveException eh("REveManager::REveManager ");
130
131 if (REX::gEve)
132 throw eh + "There can be only one REve!";
133
134 REX::gEve = this;
135
137 fServerStatus.fTStart = std::time(nullptr);
138
140
141 fGeometries = new TMap;
145 fVizDB = new TMap;
147
148 fElementIdMap[0] = nullptr; // do not increase count for null element.
149
150 fWorld = new REveScene("EveWorld", "Top-level Eve Scene");
153
154 fSelectionList = new REveElement("Selection List");
155 fSelectionList->SetChildClass(TClass::GetClass<REveSelection>());
158 fSelection = new REveSelection("Global Selection", "", kRed, kViolet);
159 fSelection->SetIsMaster(true);
162 fHighlight = new REveSelection("Global Highlight", "", kGreen, kCyan);
163 fHighlight->SetIsMaster(true);
167
168 fViewers = new REveViewerList("Viewers");
171
172 fScenes = new REveSceneList("Scenes");
175
176 // --------------------------------
177 // Create camera list
178 // --------------------------------
179 fCameras = new REveElement("Cameras", "Camera list");
182
183 fGlobalScene = new REveScene("Geometry scene");
186
187 fEventScene = new REveScene("Event scene");
190
191 {
192 REveViewer *v = SpawnNewViewer("Default Viewer");
193 v->AddScene(fGlobalScene);
194 v->AddScene(fEventScene);
195 }
196
197 // !!! AMT increase threshold to enable color pick on client
199
200 // allow multiple connections
202
204 fWebWindow->UseServerThreads();
205 fWebWindow->SetDefaultPage("file:rootui5sys/eve7/index.html");
206
207 const char *gl_viewer = gEnv->GetValue("WebEve.GLViewer", "RCore");
208 const char *gl_dblclick = gEnv->GetValue("WebEve.DblClick", "Off");
209 Int_t htimeout = gEnv->GetValue("WebEve.HTimeout", 250);
210 Int_t table_row_height = gEnv->GetValue("WebEve.TableRowHeight", 0);
211 fWebWindow->SetUserArgs(Form("{ GLViewer: \"%s\", DblClick: \"%s\", HTimeout: %d, TableRowHeight: %d }", gl_viewer,
212 gl_dblclick, htimeout, table_row_height));
213
214 if (strcmp(gl_viewer, "RCore") == 0)
215 fIsRCore = true;
216
217 // this is call-back, invoked when message received via websocket
218 fWebWindow->SetCallBacks([this](unsigned connid) { WindowConnect(connid); },
219 [this](unsigned connid, const std::string &arg) { WindowData(connid, arg); },
220 [this](unsigned connid) { WindowDisconnect(connid); });
221 fWebWindow->SetGeometry(900, 700); // configure predefined window geometry
222 fWebWindow->SetConnLimit(100); // maximal number of connections
223 fWebWindow->SetMaxQueueLength(1000); // number of allowed entries in the window queue
224
225 fMIRExecThread = std::thread{[this] { MIRExecThread(); }};
226
227 // activate interpreter error report
228 gInterpreter->ReportDiagnosticsToErrorHandler();
230}
231
232////////////////////////////////////////////////////////////////////////////////
233/// Destructor.
234
236{
237 fMIRExecThread.join();
238
239 // QQQQ How do we stop THttpServer / fWebWindow?
240
245 // Not needed - no more top-items: fScenes->Destroy();
246 fScenes = nullptr;
247
250 // Not needed - no more top-items: fViewers->Destroy();
251 fViewers = nullptr;
252
253 // fWindowManager->DestroyWindows();
254 // fWindowManager->DecDenyDestroy();
255 // fWindowManager->Destroy();
256 // fWindowManager = 0;
257
260
261 delete fGeometryAliases;
262 delete fGeometries;
263 delete fVizDB;
264 delete fExcHandler;
265}
266
267////////////////////////////////////////////////////////////////////////////////
268/// Create a new GL viewer.
269
270REveViewer *REveManager::SpawnNewViewer(const char *name, const char *title)
271{
272 REveViewer *v = new REveViewer(name, title);
274 return v;
275}
276
277////////////////////////////////////////////////////////////////////////////////
278/// Create a new scene.
279
280REveScene *REveManager::SpawnNewScene(const char *name, const char *title)
281{
282 REveScene *s = new REveScene(name, title);
284 return s;
285}
286
288{
289 printf("REveManager::RegisterRedraw3D() obsolete\n");
290}
291
292////////////////////////////////////////////////////////////////////////////////
293/// Perform 3D redraw of scenes and viewers whose contents has
294/// changed.
295
297{
298 printf("REveManager::DoRedraw3D() obsolete\n");
299}
300
301////////////////////////////////////////////////////////////////////////////////
302/// Perform 3D redraw of all scenes and viewers.
303
304void REveManager::FullRedraw3D(Bool_t /*resetCameras*/, Bool_t /*dropLogicals*/)
305{
306 printf("REveManager::FullRedraw3D() obsolete\n");
307}
308
309////////////////////////////////////////////////////////////////////////////////
310/// Clear all selection objects. Can make things easier for EVE when going to
311/// the next event. Still, destruction os selected object should still work
312/// correctly as long as it is executed within a change cycle.
313
315{
316 for (auto el : fSelectionList->fChildren) {
317 dynamic_cast<REveSelection *>(el)->ClearSelection();
318 }
319}
320
321////////////////////////////////////////////////////////////////////////////////
322/// Add an element. If parent is not specified it is added into
323/// current event (which is created if does not exist).
324
326{
327 if (parent == nullptr) {
328 // XXXX
329 }
330
331 parent->AddElement(element);
332}
333
334////////////////////////////////////////////////////////////////////////////////
335/// Add a global element, i.e. one that does not change on each
336/// event, like geometry or projection manager.
337/// If parent is not specified it is added to a global scene.
338
340{
341 if (!parent)
342 parent = fGlobalScene;
343
344 parent->AddElement(element);
345}
346
347////////////////////////////////////////////////////////////////////////////////
348/// Remove element from parent.
349
351{
352 parent->RemoveElement(element);
353}
354
355////////////////////////////////////////////////////////////////////////////////
356/// Lookup ElementId in element map and return corresponding REveElement*.
357/// Returns nullptr if the id is not found
358
360{
361 auto it = fElementIdMap.find(id);
362 return (it != fElementIdMap.end()) ? it->second : nullptr;
363}
364
365////////////////////////////////////////////////////////////////////////////////
366/// Assign a unique ElementId to given element.
367
369{
370 static const REveException eh("REveManager::AssignElementId ");
371
373 throw eh + "ElementId map is full.";
374
375next_free_id:
376 while (fElementIdMap.find(++fLastElementId) != fElementIdMap.end())
377 ;
378 if (fLastElementId == 0)
379 goto next_free_id;
380 // MT - alternatively, we could spawn a thread to find next thousand or so ids and
381 // put them in a vector of ranges. Or collect them when they are freed.
382 // Don't think this won't happen ... online event display can run for months
383 // and easily produce 100000 objects per minute -- about a month to use up all id space!
384
385 element->fElementId = fLastElementId;
386 fElementIdMap.insert(std::make_pair(fLastElementId, element));
388}
389
390////////////////////////////////////////////////////////////////////////////////
391/// Activate EVE browser (summary view) for specified element id
392
394{
395 nlohmann::json msg = {};
396 msg["content"] = "BrowseElement";
397 msg["id"] = id;
398
399 fWebWindow->Send(0, msg.dump());
400}
401
402////////////////////////////////////////////////////////////////////////////////
403/// Ask every connected client to grab its GL viewers and POST each image to an
404/// image collector. Each client posts the views it shows, all tagged with the
405/// same `event_id`.
406///
407/// The body is `application/octet-stream`, width*height*4 bytes of RGBA8 with
408/// straight alpha and no background, so it composites onto any backdrop.
409/// Headers X-Width, X-Height, X-Event-ID and X-View-Type describe it; X-Flip-Y
410/// is 1 when the rows are in WebGL bottom-up order. RenderCore's
411/// util/image-gator.js is a reference receiver. The default collector is on
412/// loopback; a remote one needs TLS and authentication.
413///
414/// \param event_id tag recorded with the image, e.g. run/lumi/event
415/// \param url collector endpoint; empty takes rootrc `WebEve.ImageGatorUrl`,
416/// which defaults to http://localhost:3000/capture
417/// \param scale multiplier on the viewer viewport; 1 is what the operator sees
418/// \param viewers restrict to these viewer names; empty means all of them
419
420void REveManager::GrabImages(std::string_view event_id, std::string_view url, int scale,
421 const std::vector<std::string> &viewers)
422{
423 std::string dest(url);
424 if (dest.empty())
425 dest = gEnv->GetValue("WebEve.ImageGatorUrl", "http://localhost:3000/capture");
426
427 nlohmann::json msg = {};
428 // clang-format off
429 msg["content"] = "GrabImage";
430 msg["event_id"] = std::string(event_id);
431 msg["url"] = dest;
432 msg["scale"] = scale;
433 msg["viewers"] = viewers;
434 // clang-format on
435
436 fWebWindow->Send(0, msg.dump());
437}
438
439////////////////////////////////////////////////////////////////////////////////
440/// Called from REveElement prior to its destruction so the
441/// framework components (like object editor) can unreference it.
442
444{
445 if (el->fImpliedSelected > 0) {
446 for (auto slc : fSelectionList->fChildren) {
447 REveSelection *sel = dynamic_cast<REveSelection *>(slc);
448 sel->RemoveImpliedSelectedReferencesTo(el);
449 }
450
451 if (el->fImpliedSelected != 0)
452 Error("REveManager::PreDeleteElement", "ImpliedSelected not zero (%d) after cleanup of selections.",
453 el->fImpliedSelected);
454 }
455 // Primary selection deregistration is handled through Niece removal from Aunts.
456
457 if (el->fElementId != 0) {
458 auto it = fElementIdMap.find(el->fElementId);
459 if (it != fElementIdMap.end()) {
460 if (it->second == el) {
461 fElementIdMap.erase(it);
463 } else
464 Error("PreDeleteElement", "element ptr in ElementIdMap does not match the argument element.");
465 } else
466 Error("PreDeleteElement", "element id %u was not registered in ElementIdMap.", el->fElementId);
467 } else
468 Error("PreDeleteElement", "element with 0 ElementId passed in.");
469}
470
471////////////////////////////////////////////////////////////////////////////////
472/// Insert a new visualization-parameter database entry. Returns
473/// true if the element is inserted successfully.
474/// If entry with the same key already exists the behaviour depends on the
475/// 'replace' flag:
476/// - true - The old model is deleted and new one is inserted (default).
477/// Clients of the old model are transferred to the new one and
478/// if 'update' flag is true (default), the new model's parameters
479/// are assigned to all clients.
480/// - false - The old model is kept, false is returned.
481///
482/// If insert is successful, the ownership of the model-element is
483/// transferred to the manager.
484
486{
487 TPair *pair = (TPair *)fVizDB->FindObject(tag);
488 if (pair) {
489 if (replace) {
490 model->IncDenyDestroy();
491 model->SetRnrChildren(kFALSE);
492
493 REveElement *old_model = dynamic_cast<REveElement *>(pair->Value());
494 if (old_model) {
495 while (old_model->HasChildren()) {
496 REveElement *el = old_model->FirstChild();
497 el->SetVizModel(model);
498 if (update) {
499 el->CopyVizParams(model);
501 }
502 }
503 old_model->DecDenyDestroy();
504 }
505 pair->SetValue(dynamic_cast<TObject *>(model));
506 return kTRUE;
507 } else {
508 return kFALSE;
509 }
510 } else {
511 model->IncDenyDestroy();
512 model->SetRnrChildren(kFALSE);
513 fVizDB->Add(new TObjString(tag), dynamic_cast<TObject *>(model));
514 return kTRUE;
515 }
516}
517
518////////////////////////////////////////////////////////////////////////////////
519/// Insert a new visualization-parameter database entry with the default
520/// parameters for replace and update, as specified by members
521/// fVizDBReplace(default=kTRUE) and fVizDBUpdate(default=kTRUE).
522/// See docs of the above function.
523
528
529////////////////////////////////////////////////////////////////////////////////
530/// Find a visualization-parameter database entry corresponding to tag.
531/// If the entry is not found 0 is returned.
532
534{
535 return dynamic_cast<REveElement *>(fVizDB->GetValue(tag));
536}
537
538////////////////////////////////////////////////////////////////////////////////
539/// Load visualization-parameter database from file filename. The
540/// replace, update arguments replace the values of fVizDBReplace
541/// and fVizDBUpdate members for the duration of the macro
542/// execution.
543
545{
546 Bool_t ex_replace = fVizDBReplace;
547 Bool_t ex_update = fVizDBUpdate;
548 fVizDBReplace = replace;
550
552
553 fVizDBReplace = ex_replace;
554 fVizDBUpdate = ex_update;
555}
556
557////////////////////////////////////////////////////////////////////////////////
558/// Load visualization-parameter database from file filename.
559/// State of data-members fVizDBReplace and fVizDBUpdate determine
560/// how the registered entries are handled.
561
567
568////////////////////////////////////////////////////////////////////////////////
569/// Save visualization-parameter database to file filename.
570
572{
573 TPMERegexp re("(.+)\\.\\w+");
574 if (re.Match(filename) != 2) {
575 Error("SaveVizDB", "filename does not match required format '(.+)\\.\\w+'.");
576 return;
577 }
578
579 TString exp_filename(filename);
580 gSystem->ExpandPathName(exp_filename);
581
582 std::ofstream out(exp_filename, std::ios::out | std::ios::trunc);
583 out << "void " << re[1] << "()\n";
584 out << "{\n";
585 out << " REveManager::Create();\n";
586
588
589 Int_t var_id = 0;
590 TString var_name;
591 TIter next(fVizDB);
592 TObjString *key;
593 while ((key = (TObjString *)next())) {
594 REveElement *mdl = dynamic_cast<REveElement *>(fVizDB->GetValue(key));
595 if (mdl) {
596 var_name.Form("x%03d", var_id++);
597 mdl->SaveVizParams(out, key->String(), var_name);
598 } else {
599 Warning("SaveVizDB", "Saving failed for key '%s'.", key->String().Data());
600 }
601 }
602
603 out << "}\n";
604 out.close();
605}
606
607////////////////////////////////////////////////////////////////////////////////
608/// Get geometry with given filename.
609/// This is cached internally so the second time this function is
610/// called with the same argument the same geo-manager is returned.
611/// gGeoManager is set to the return value.
612
614{
615 static const REveException eh("REveManager::GetGeometry ");
616
617 TString exp_filename = filename;
618 gSystem->ExpandPathName(exp_filename);
619 printf("REveManager::GetGeometry loading: '%s' -> '%s'.\n", filename.Data(), exp_filename.Data());
620
622 if (gGeoManager) {
624 } else {
625 Bool_t locked = TGeoManager::IsLocked();
626 if (locked) {
627 Warning("REveManager::GetGeometry", "TGeoManager is locked ... unlocking it.");
629 }
630 if (TGeoManager::Import(filename) == nullptr) {
631 throw eh + "TGeoManager::Import() failed for '" + exp_filename + "'.";
632 }
633 if (locked) {
635 }
636
638
639 // Import colors exported by Gled, if they exist.
640 {
641 TFile f(exp_filename, "READ");
642 TObjArray *collist = (TObjArray *)f.Get("ColorList");
643 f.Close();
644 if (collist) {
646 TGeoVolume *vol;
647 while ((vol = (TGeoVolume *)next()) != nullptr) {
648 Int_t oldID = vol->GetLineColor();
649 TColor *col = (TColor *)collist->At(oldID);
650 Float_t r, g, b;
651 col->GetRGB(r, g, b);
652 Int_t newID = TColor::GetColor(r, g, b);
653 vol->SetLineColor(newID);
654 }
655 }
656 }
657
659 }
660 return gGeoManager;
661}
662
663////////////////////////////////////////////////////////////////////////////////
664/// Get geometry with given alias.
665/// The alias must be registered via RegisterGeometryAlias().
666
668{
669 static const REveException eh("REveManager::GetGeometry ");
670
671 TObjString *full_name = (TObjString *)fGeometryAliases->GetValue(alias);
672 if (!full_name)
673 throw eh + "geometry alias '" + alias + "' not registered.";
674 return GetGeometry(full_name->String());
675}
676
677////////////////////////////////////////////////////////////////////////////////
678/// Get the default geometry.
679/// It should be registered via RegisterGeometryName("Default", `<URL>`).
680
685
686////////////////////////////////////////////////////////////////////////////////
687/// Get the default viewer.
688///
689
691{
692 return dynamic_cast<REveViewer*>(fViewers->FirstChild());
693}
694
695////////////////////////////////////////////////////////////////////////////////
696/// Utility function to allow remote RWebWindow connections.
697/// Disable loopback when use remote client.
698/// Authentification key has to be disabled in the case of multiple connections.
699/// The default arguments prevent remote connections for the security reasons.
700//
701void REveManager::AllowMultipleRemoteConnections(bool loopBack, bool requireAuthKey)
702{
704 fWebWindow->SetRequireAuthKey(requireAuthKey);
705}
706
707////////////////////////////////////////////////////////////////////////////////
708/// Register 'name' as an alias for geometry file 'filename'.
709/// The old aliases are silently overwritten.
710/// After that the geometry can be retrieved also by calling:
711/// REX::gEve->GetGeometryByName(name);
712
717
718////////////////////////////////////////////////////////////////////////////////
719/// Work-around uber ugly hack used in SavePrimitive and co.
720
722{
723 gROOT->ResetClassSaved();
724}
725
726////////////////////////////////////////////////////////////////////////////////
727/// Register new directory to THttpServer
728// For example: AddLocation("mydir/", "/test/EveWebApp/ui5");
729//
730void REveManager::AddLocation(const std::string &locationName, const std::string &path)
731{
732 fWebWindow->GetServer()->AddLocation(locationName.c_str(), path.c_str());
733}
734
735////////////////////////////////////////////////////////////////////////////////
736/// Set content of default window HTML page
737// Got example: SetDefaultHtmlPage("file:currentdir/test.html")
738//
739void REveManager::SetDefaultHtmlPage(const std::string &path)
740{
741 fWebWindow->SetDefaultPage(path);
742}
743
744////////////////////////////////////////////////////////////////////////////////
745/// Set client version, used as prefix in scripts URL
746/// When changed, web browser will reload all related JS files while full URL will be different
747/// Default is empty value - no extra string in URL
748/// Version should be string like "1.2" or "ver1.subv2" and not contain any special symbols
749void REveManager::SetClientVersion(const std::string &version)
750{
751 fWebWindow->SetClientVersion(version);
752}
753
754////////////////////////////////////////////////////////////////////////////////
755/// If global REveManager* REX::gEve is not set initialize it.
756/// Returns REX::gEve.
757
759{
760 static const REveException eh("REveManager::Create ");
761
762 if (!REX::gEve) {
763 // XXXX Initialize some server stuff ???
764
765 REX::gEve = new REveManager();
766 }
767 return REX::gEve;
768}
769
770////////////////////////////////////////////////////////////////////////////////
771/// Properly terminate global REveManager.
772
774{
775 if (!REX::gEve)
776 return;
777
778 delete REX::gEve;
779 REX::gEve = nullptr;
780}
781
782void REveManager::ExecuteInMainThread(std::function<void()> func)
783{
784 class XThreadTimer : public TTimer {
785 std::function<void()> foo_;
786 public:
787 XThreadTimer(std::function<void()> f) : foo_(f)
788 {
789 SetTime(0);
791 gSystem->AddTimer(this);
792 }
793 Bool_t Notify() override
794 {
795 foo_();
796 gSystem->RemoveTimer(this);
797 delete this;
798 return kTRUE;
799 }
800 };
801
802 new XThreadTimer(func);
803}
804
806{
808 // QQQQ Should call Terminate() but it needs to:
809 // - properly stop MIRExecThread;
810 // - shutdown civet/THttp/RWebWindow
812 });
813}
814
815////////////////////////////////////////////////////////////////////////////////
816/// Process new connection from web window.
817///
818/// This is called in a web-server thread, which can have a small stack (the
819/// builtin civetweb uses 100 KB unless configured otherwise). Streaming the
820/// scenes can need much more: the first IsA() of an element class makes cling
821/// load declarations, which recurses deeply. If the current thread's stack is
822/// small, the streaming runs in a thread with the default stack size instead,
823/// and this thread waits for it.
824
825void REveManager::WindowConnect(unsigned connid)
826{
827 static constexpr size_t kMinStackSize = 1024 * 1024;
828
829 size_t stack_size = CurrentThreadStackSize();
830 if (stack_size == 0 || stack_size >= kMinStackSize) {
831 StreamToNewConnection(connid);
832 return;
833 }
834
835 // An exception is passed back to this thread, where it would have appeared before.
836 std::exception_ptr exc;
837 std::thread thrd;
838 try {
839 thrd = std::thread([this, connid, &exc] {
840#if defined(R__LINUX)
841 pthread_setname_np(pthread_self(), "eve_connect");
842#endif
843 try {
844 StreamToNewConnection(connid);
845 } catch (...) {
846 exc = std::current_exception();
847 }
848 });
849 } catch (const std::system_error &e) {
850 ::Warning("REveManager::WindowConnect",
851 "could not start streaming thread (%s), streaming in the web-server thread with stack size %zu",
852 e.what(), stack_size);
853 StreamToNewConnection(connid);
854 return;
855 }
856 thrd.join();
857 if (exc)
858 std::rethrow_exception(exc);
859}
860
861////////////////////////////////////////////////////////////////////////////////
862/// Register new connection and stream the world and the mandatory scenes to it.
863
865{
866 std::unique_lock<std::mutex> lock(fServerState.fMutex);
867
869 {
870 fServerState.fCV.wait(lock);
871 }
872
873 fConnList.emplace_back(connid);
874 printf("connection established %u\n", connid);
875
876 // QQQQ do we want mir-time here as well? maybe set it at the end of function?
877 // Note, this is all under lock, so nobody will get state out in between.
878 fServerStatus.fTLastMir = fServerStatus.fTLastConnect = std::time(nullptr);
880
881 // This prepares core and render data buffers.
882 printf("\nEVEMNG ............. streaming the world scene.\n");
883
884 fWorld->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow));
886
887 printf(" sending json, len = %d\n", (int)fWorld->fOutputJson.size());
888 Send(connid, fWorld->fOutputJson);
889 printf(" for now assume world-scene has no render data, binary-size=%d\n", fWorld->fTotalBinarySize);
890 assert(fWorld->fTotalBinarySize == 0);
891
892 for (auto &c : fScenes->RefChildren()) {
893 REveScene *scene = dynamic_cast<REveScene *>(c);
894 if (!scene->GetMandatory())
895 continue;
896
897 scene->AddSubscriber(std::make_unique<REveClient>(connid, fWebWindow));
898 printf("\nEVEMNG ............. streaming scene %s [%s]\n", scene->GetCTitle(), scene->GetCName());
899
900 // This prepares core and render data buffers.
901 scene->StreamElements();
902
903 printf(" sending json, len = %d\n", (int)scene->fOutputJson.size());
904 Send(connid, scene->fOutputJson);
905
906 if (scene->fTotalBinarySize > 0) {
907 printf(" sending binary, len = %d\n", scene->fTotalBinarySize);
908 SendBinary(connid, &scene->fOutputBinary[0], scene->fTotalBinarySize);
909 } else {
910 printf(" NOT sending binary, len = %d\n", scene->fTotalBinarySize);
911 }
912 }
913
914 fServerState.fCV.notify_all();
915}
916
917////////////////////////////////////////////////////////////////////////////////
918/// Process disconnect of web window
919
920void REveManager::WindowDisconnect(unsigned connid)
921{
922 std::unique_lock<std::mutex> lock(fServerState.fMutex);
923 auto conn = fConnList.end();
924 for (auto i = fConnList.begin(); i != fConnList.end(); ++i) {
925 if (i->fId == connid) {
926 conn = i;
927 break;
928 }
929 }
930 // this should not happen, just check
931 if (conn == fConnList.end()) {
932 printf("error, connection not found!");
933 } else {
934 printf("connection closed %u\n", connid);
935 fConnList.erase(conn);
936 for (auto &c : fScenes->RefChildren()) {
937 REveScene *scene = dynamic_cast<REveScene *>(c);
938 scene->RemoveSubscriber(connid);
939 }
940 fWorld->RemoveSubscriber(connid);
941 }
942
943 // User case: someone can close browser tab as clients are updateding
944 // note if scene changes are in progess the new serverstate will be changes after finish those
946 {
947 if (fPendingSceneChanges && !fConnList.empty()) {
948 // The closed connection was the last one busy: send the changes held
949 // back for it, as its acknowledgement would have.
950 fPendingSceneChanges = false;
953 } else {
954 // No one left to send to; the stamps stay for the next EndChange().
955 fPendingSceneChanges = false;
957 }
958 fServerState.fCV.notify_all();
959 }
960
961 fServerStatus.fTLastDisconnect = std::time(nullptr);
963
964 fServerState.fCV.notify_all();
965}
966
967////////////////////////////////////////////////////////////////////////////////
968/// Process data from web window
969
970void REveManager::WindowData(unsigned connid, const std::string &arg)
971{
972 static const REveException eh("REveManager::WindowData ");
973
974 // find connection object
975 bool found = false;
976 for (auto &conn : fConnList) {
977 if (conn.fId == connid) {
978 found = true;
979 break;
980 }
981 }
982
983 // this should not happen, just check
984 if (!found) {
985 R__LOG_ERROR(REveLog()) << "Internal error - no connection with id " << connid << " found";
986 return;
987 }
988
989
990 if (arg.compare("__REveDoneChanges") == 0)
991 {
992 // client status data
993 std::unique_lock<std::mutex> lock(fServerState.fMutex);
994
995 for (auto &conn : fConnList) {
996 if (conn.fId == connid) {
997 conn.fState = Conn::Free;
998 break;
999 }
1000 }
1001
1004 // Changes stamped while the previous ones were in flight. Sending
1005 // them leaves the clients busy again.
1006 fPendingSceneChanges = false;
1009 } else {
1011 }
1012 fServerState.fCV.notify_all();
1013 }
1014
1015 return;
1016 }
1018 {
1019 if (fHttpPublic)
1020 {
1021 R__LOG_INFO(REveLog()) << "REveManager::WindowData, file dialog is not allowed in restriced public mode";
1022 }
1023 else
1024 {
1026 }
1027 return;
1028 }
1029 else if (arg.compare(0, 11, "SETCHANNEL:") == 0) {
1030 std::string s = arg.substr(11);
1031 auto p = s.find(",");
1032 int eveid = std::stoi(s.substr(0, p));
1033 int chid = std::stoi(s.substr(p+1));
1034
1035 REveElement* n = FindElementById(eveid);
1036 auto nn = dynamic_cast<REveGeoTopNodeData*>(n);
1037 if (nn) nn->SetChannel(connid, chid);
1038
1039 return;
1040 }
1041
1042 nlohmann::json cj = nlohmann::json::parse(arg);
1043 if (gDebug > 0)
1044 ::Info("REveManager::WindowData", "MIR test %s\n", cj.dump().c_str());
1045
1046 std::string cmd = cj["mir"];
1047 int id = cj["fElementId"];
1048 std::string ctype = cj["class"];
1049
1050 ScheduleMIR(cmd, id, ctype, connid);
1051}
1052
1053//
1054//____________________________________________________________________
1055void REveManager::ScheduleMIR(const std::string &cmd, ElementId_t id, const std::string& ctype, unsigned connid)
1056{
1057 std::unique_lock<std::mutex> lock(fServerState.fMutex);
1058 fServerStatus.fTLastMir = std::time(nullptr);
1059 fMIRqueue.push(std::make_shared<MIR>(cmd, id, ctype, connid));
1060
1061 if (fMIRqueue.size() > 5)
1062 std::cout << "Warning, REveManager::ScheduleMIR(). queue size " << fMIRqueue.size() << std::endl;
1063
1065 fServerState.fCV.notify_all();
1066}
1067
1068//
1069//____________________________________________________________________
1070void REveManager::ExecuteMIR(std::shared_ptr<MIR> mir)
1071{
1072 static const REveException eh(""); // Empty -- all errors go to R__LOG
1073
1074 //if (gDebug > 0)
1075 ::Info("REveManager::ExecuteCommand", "MIR cmd %s", mir->fCmd.c_str());
1076
1077 std::string tag = mir->fCtype + "::<to-be-determined>";
1078
1079 try {
1080 REveElement *el = FindElementById(mir->fId);
1081 if ( ! el) throw eh + "Element with id " + mir->fId + " not found";
1082
1083 static const std::regex cmd_re("^(\\w[\\w\\d]*)\\(\\s*(.*)\\s*\\)\\s*;?\\s*$", std::regex::optimize);
1084 std::smatch m;
1085 std::regex_search(mir->fCmd, m, cmd_re);
1086 if (m.size() != 3)
1087 throw eh + "Command string parse error: '" + mir->fCmd + "'.";
1088
1089 static const TClass *elem_cls = TClass::GetClass<REX::REveElement>();
1090
1091 TClass *call_cls = TClass::GetClass(mir->fCtype.c_str());
1092 if ( ! call_cls)
1093 throw eh + "Class '" + mir->fCtype + "' not found.";
1094
1095 void *el_casted = call_cls->DynamicCast(elem_cls, el, false);
1096 if ( ! el_casted)
1097 throw eh + "Dynamic cast from REveElement to '" + mir->fCtype + "' failed.";
1098
1099 tag = mir->fCtype + "::" + m.str(1);
1100
1101 std::shared_ptr<TMethodCall> mc;
1102 auto mmi = fMethCallMap.find(tag);
1103 if (mmi != fMethCallMap.end())
1104 {
1105 mc = mmi->second;
1106 }
1107 else
1108 {
1109 const TMethod *meth = call_cls->GetMethodAllAny(m.str(1).c_str());
1110 if ( ! meth)
1111 throw eh + "Can not find TMethod matching '" + m.str(1) + "'.";
1112 mc = std::make_shared<TMethodCall>(meth);
1113 fMethCallMap.insert(std::make_pair(tag, mc));
1114 }
1115
1117
1119 mc->Execute(el_casted, m.str(2).c_str());
1120
1122 R__LOG_ERROR(REveLog()) << eh << "error executing " << tag << ":" << REveElement::stlMirErrorString << " (code " << REveElement::stlMirError << ").";
1123 }
1125
1126 // Alternative implementation through Cling. "Leaks" 200 kB per call.
1127 // This might be needed for function calls that involve data-types TMethodCall
1128 // can not handle.
1129 // std::stringstream cmd;
1130 // cmd << "((" << mir->fCtype << "*)" << std::hex << std::showbase << (size_t)el << ")->" << mir->fCmd << ";";
1131 // std::cout << cmd.str() << std::endl;
1132 // gROOT->ProcessLine(cmd.str().c_str());
1133 } catch (std::exception &e) {
1134 R__LOG_ERROR(REveLog()) << "caught exception executing " << tag << ": " << e.what();
1135 } catch (...) {
1136 R__LOG_ERROR(REveLog()) << "caught unknown execption.";
1137 }
1138}
1139
1140// Write scene change into scenes's internal json member
1142{
1144
1145 for (auto &el : fScenes->RefChildren())
1146 {
1147 REveScene* s = dynamic_cast<REveScene*>(el);
1149 }
1150}
1151
1152////////////////////////////////////////////////////////////////////////////////
1153/// Send transformation-only changes on the motion channel: the same websocket,
1154/// outside the BeginChanges/EndChanges cycle, with no acknowledgement. The
1155/// message is sent directly, so it goes only when every connection can take a
1156/// direct send. Otherwise the elements stay stamped and go out with the
1157/// regular changes, which carry the same matrix and motion. The motion's t0 is
1158/// stamped by REveTrans::SetMotion(), so the delay does not shift the
1159/// trajectory.
1160
1162{
1163 if (fConnList.empty())
1164 return;
1165
1166 for (auto &conn : fConnList)
1167 if (!fWebWindow->CanSend(conn.fId, true))
1168 return;
1169
1170 nlohmann::json arr = nlohmann::json::array();
1171
1173 for (auto &el : fScenes->RefChildren()) {
1174 auto s = dynamic_cast<REveScene *>(el);
1175 if (s)
1176 s->StreamMotionChanges(arr);
1177 }
1178
1179 if (arr.empty())
1180 return;
1181
1182 nlohmann::json msg = {};
1183 // clang-format off
1184 msg["content"] = "Motion";
1185 msg["els"] = arr;
1186 // clang-format on
1187
1188 std::string data = msg.dump();
1189
1190 for (auto &conn : fConnList)
1191 fWebWindow->Send(conn.fId, data);
1192}
1193
1194////////////////////////////////////////////////////////////////////////////////
1195// Send json and binary data to scene's connections
1197{
1198 // send begin message
1199 nlohmann::json jobj = {};
1200 jobj["content"] = "BeginChanges";
1201 SendToAllConnections(jobj.dump());
1202
1203 // send the change json
1205
1206 for (auto &el : fScenes->RefChildren())
1207 {
1208 REveScene* s = dynamic_cast<REveScene*>(el);
1210 }
1211
1212 // send end changes message and log messages
1213 jobj["content"] = "EndChanges";
1214
1215 if (!gEveLogEntries.empty()) {
1216 constexpr static int numLevels = static_cast<int>(ELogLevel::kDebug) + 1;
1217 constexpr static std::array<const char *, numLevels> sTag{
1218 {"{unset-error-level please report}", "FATAL", "Error", "Warning", "Info", "Debug"}};
1219
1220 jobj["log"] = nlohmann::json::array();
1221 std::stringstream strm;
1222 for (auto entry : gEveLogEntries) {
1223 strm.str("");
1224 nlohmann::json item = {};
1225 item["lvl"] = entry.fLevel;
1226 int cappedLevel = std::min(static_cast<int>(entry.fLevel), numLevels - 1);
1227 strm << "Server " << sTag[cappedLevel] << ":";
1228
1229 if (!entry.fLocation.fFuncName.empty())
1230 strm << " " << entry.fLocation.fFuncName;
1231 strm << " " << entry.fMessage;
1232 item["msg"] = strm.str();
1233 jobj["log"].push_back(item);
1234 }
1235 gEveLogEntries.clear();
1236 }
1237 SendToAllConnections(jobj.dump());
1238}
1239
1240//
1241//____________________________________________________________________
1243{
1244#if defined(R__LINUX)
1245 pthread_setname_np(pthread_self(), "mir_exec");
1246#endif
1247 while (true)
1248 {
1249 std::unique_lock<std::mutex> lock(fServerState.fMutex);
1250 underlock:
1252 {
1253 fServerState.fCV.wait(lock);
1254 goto underlock;
1255 }
1256 else
1257 {
1258 // set server state and update the queue under lock
1259 //
1261 std::shared_ptr<MIR> mir = fMIRqueue.front();
1262
1263 // reset local thread related data
1264 gMIRData.reset();
1265 fMIRqueue.pop();
1266
1267 lock.unlock();
1268
1269 // Ideally, as in gled, MIR execution would be steered by scenes themselves.
1270 // But this requires alpha/beta/gamma MIR elements and scene dependenices,
1271 // so dependent scenes can be locked, too.
1272 // On top of that, one could also implements authorization framework, as in gled.
1273
1276
1277 ExecuteMIR(mir);
1278
1281
1283
1284 // send changes (need to access client connection list) and set the state under lock
1285 //
1286 lock.lock();
1287
1288 // disconnect requested scene from clients
1289 for (auto &scene : gMIRData.removedWatch)
1290 scene->RemoveSubscriber(mir->fConnId);
1291
1292
1293 // connect and stream scenes to new clients
1294 for (auto &scene : gMIRData.addedWatch) {
1295 scene->AddSubscriber(std::make_unique<REveClient>(mir->fConnId, fWebWindow));
1296 scene->StreamElements();
1297 Send(mir->fConnId, scene->fOutputJson);
1298 if (scene->fTotalBinarySize > 0)
1299 SendBinary(mir->fConnId, &scene->fOutputBinary[0], scene->fTotalBinarySize);
1300 }
1301
1303
1305 fServerState.fCV.notify_all();
1306 }
1307 }
1308}
1309
1310//____________________________________________________________________
1312{
1313 for (auto &c : view->RefChildren()) {
1314 REveSceneInfo *sinfo = dynamic_cast<REveSceneInfo *>(c);
1315 std::cout << "Disconnect scee " << sinfo->GetScene()->GetName();
1316 gMIRData.removedWatch.push_back(sinfo->GetScene());
1317 }
1318}
1319//____________________________________________________________________
1321{
1322 view->StampObjProps();
1323 for (auto &c : view->RefChildren()) {
1324 REveSceneInfo *sinfo = dynamic_cast<REveSceneInfo *>(c);
1325 std::cout << "Connect scene " << sinfo->GetScene()->GetName();
1326 gMIRData.addedWatch.push_back(sinfo->GetScene());
1327 }
1328}
1329
1330//____________________________________________________________________
1332{
1333 for (auto &conn : fConnList) {
1334 fWebWindow->Send(conn.fId, data);
1335 }
1336}
1337
1338void REveManager::Send(unsigned connid, const std::string &data)
1339{
1340 fWebWindow->Send(connid, data);
1341}
1342
1343void REveManager::SendBinary(unsigned connid, const void *data, std::size_t len)
1344{
1345 fWebWindow->SendBinary(connid, data, len);
1346}
1347
1348////////////////////////////////////////////////////////////////////////////////
1349/// Is there anything stamped and not yet streamed?
1350
1352{
1353 if (fWorld->IsChanged())
1354 return true;
1355
1356 for (auto &el : fScenes->RefChildren()) {
1357 auto s = dynamic_cast<REveScene *>(el);
1358 if (s && s->IsChanged())
1359 return true;
1360 }
1361 return false;
1362}
1363
1364////////////////////////////////////////////////////////////////////////////////
1365
1367{
1368 for (auto &conn : fConnList) {
1369 if (conn.fState != Conn::Free)
1370 return false;
1371 }
1372
1373 return true;
1374}
1375
1376// called from REveScene::SendChangesToSubscribers
1378{
1379 for (auto &conn : fConnList) {
1380 if (conn.fId == cinnId)
1381 {
1382 conn.fState = Conn::WaitingResponse;
1383 break;
1384 }
1385 }
1386}
1387
1388//////////////////////////////////////////////////////////////////
1389/// Show eve manager in specified browser.
1390
1391/// If rootrc variable WebEve.DisableShow is set, HTTP server will be
1392/// started and access URL printed on stdout.
1393
1395{
1396 if (gEnv->GetValue("WebEve.DisableShow", 0) != 0) {
1397 std::string url = fWebWindow->GetUrl(true);
1398 printf("EVE URL %s\n", url.c_str());
1399 } else {
1400 fWebWindow->Show(args);
1401 }
1402}
1403
1404
1405//____________________________________________________________________
1407{
1408 // set server state and tag scenes to begin accepting changees
1409 {
1410 std::unique_lock<std::mutex> lock(fServerState.fMutex);
1412 fServerState.fCV.wait(lock);
1413 }
1415 }
1418}
1419
1420//____________________________________________________________________
1421/// Stop accepting changes and stream them. If the clients have not yet
1422/// acknowledged the previous changes, keep the stamps and let the last
1423/// acknowledgement in WindowData() flush them. Stamps coalesce per element.
1424/// Motion changes are sent in either case when the connections can take a
1425/// direct send, see SendMotionChanges(). Changes made by a MIR are not held
1426/// back.
1427
1429{
1430 // tag scene to disable accepting chages, write the change json
1433
1434 std::unique_lock<std::mutex> lock(fServerState.fMutex);
1435
1436 // Motion is outside the change cycle, so it is sent even when changes
1437 // are held. What cannot be sent now stays stamped and goes with them.
1439
1440 if (!fConnList.empty() && !ClientConnectionsFree()) {
1441 // Previous changes not yet acknowledged. Leave everything stamped.
1442 if (AnySceneChanged())
1443 fPendingSceneChanges = true;
1444
1446 fServerState.fCV.notify_all();
1447 return;
1448 }
1449
1452 fPendingSceneChanges = false;
1453
1455 fServerState.fCV.notify_all();
1456}
1457
1458//____________________________________________________________________
1460{
1461 std::unique_lock<std::mutex> lock(fServerState.fMutex);
1463#if defined(_MSC_VER)
1464 std::timespec_get(&fServerStatus.fTReport, TIME_UTC);
1465#else
1466 fServerStatus.fTReport = std::time_t(nullptr);
1467#endif
1468 st = fServerStatus;
1469}
1470
1471/** \class REveManager::ChangeGuard
1472\ingroup REve
1473RAII guard for locking Eve manager (ctor) and processing changes (dtor).
1474*/
1475
1476//////////////////////////////////////////////////////////////////////
1477//
1478// Helper struct to guard update mechanism
1479//
1484
1489
1490// gInterpreter error handlder
1491void REveManager::ErrorHandler(Int_t level, Bool_t abort, const char * location, const char *msg)
1492{
1493 if (level >= kError)
1494 {
1496 entry.fMessage = msg;
1497 gEveLogEntries.emplace_back(entry);
1498 }
1499 ::DefaultErrorHandler(level, abort, location, msg);
1500}
1501
1502/** \class REveManager::RExceptionHandler
1503\ingroup REve
1504Exception handler for Eve exceptions.
1505*/
1506
1507////////////////////////////////////////////////////////////////////////////////
1508/// Handle exceptions deriving from REveException.
1509
1511{
1512 REveException *ex = dynamic_cast<REveException *>(&exc);
1513 if (ex) {
1514 Info("Handle", "Exception %s", ex->what());
1515 // REX::gEve->SetStatusLine(ex->Data());
1516 gSystem->Beep();
1517 return kSEHandled;
1518 }
1519 return kSEProceed;
1520}
1521
1522
1523////////////////////////////////////////////////////////////////////////////////
1524/// Utility to stream loggs to client.
1525/// Return false to supress further emission
1526
1528{
1529 gEveLogEntries.emplace_back(entry);
1530 return false;
1531}
1532
1533
1534////////////////////////////////////////////////////////////////////////////////
1535/// Restrict functionality for this server when open to public
1536
1538{
1539 R__LOG_INFO(REveLog()) << "Set public mode to " << x <<".";
1540 fHttpPublic = x;
1541}
thread_local std::vector< ROOT::RLogEntry > gEveLogEntries
thread_local MIR_TL_Data_t gMIRData
#define R__LOG_ERROR(...)
Definition RLogger.hxx:356
#define R__LOG_INFO(...)
Definition RLogger.hxx:358
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define g(i)
Definition RSha256.hxx:105
#define e(i)
Definition RSha256.hxx:103
static void update(gsl_integration_workspace *workspace, double a1, double b1, double area1, double error1, double a2, double b2, double area2, double error2)
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
@ kRed
Definition Rtypes.h:66
@ kGreen
Definition Rtypes.h:66
@ kCyan
Definition Rtypes.h:66
@ kViolet
Definition Rtypes.h:67
R__EXTERN TApplication * gApplication
R__EXTERN TEnv * gEnv
Definition TEnv.h:126
void DefaultErrorHandler(Int_t level, Bool_t abort_bool, const char *location, const char *msg)
The default error handler function.
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:241
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:208
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
Definition TError.cxx:252
ErrorHandlerFunc_t SetErrorHandler(ErrorHandlerFunc_t newhandler)
Set an errorhandler function. Returns the old handler.
Definition TError.cxx:92
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t dest
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t sel
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize id
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t attr
char name[80]
Definition TGX11.cxx:142
R__EXTERN TGeoManager * gGeoManager
R__EXTERN TGeoIdentity * gGeoIdentity
Definition TGeoMatrix.h:538
R__EXTERN TVirtualMutex * gInterpreterMutex
#define R__LOCKGUARD_CLING(mutex)
#define gInterpreter
Int_t gDebug
Global variable setting the debug level. Set to 0 to disable, increase it in steps of 1 to increase t...
Definition TROOT.cxx:792
#define gROOT
Definition TROOT.h:417
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2571
R__EXTERN TVirtualMutex * gSystemMutex
Definition TSystem.h:254
R__EXTERN TSystem * gSystem
Definition TSystem.h:582
#define R__LOCKGUARD2(mutex)
void DecDenyDestroy()
Decreases the deny-destroy count of the element.
const std::string & GetName() const
void SaveVizParams(std::ostream &out, const TString &tag, const TString &var)
Save visualization parameters for this element with given tag.
const char * GetCTitle() const
const char * GetCName() const
virtual void AddElement(REveElement *el)
Add el to the list of children.
static thread_local int stlMirError
virtual void DestroyElements()
Destroy all children of this element.
REveElement * FirstChild() const
Returns the first child element or 0 if the list is empty.
static void SetMirContext(REveElement *el)
void IncDenyDestroy()
Increases the deny-destroy count of the element.
static thread_local std::string stlMirErrorString
virtual void CopyVizParams(const REveElement *el)
Copy visualization parameters from element el.
void SetVizModel(REveElement *model)
Set visualization-parameter model element.
virtual void RemoveElement(REveElement *el)
Remove el from the list of children.
virtual void PropagateVizParamsToProjecteds()
Propagate visualization parameters to dependent elements.
REveException Exception-type thrown by Eve classes.
Definition REveTypes.hxx:42
void SetChannel(unsigned connid, int chid)
bool Emit(const RLogEntry &entry) override
Utility to stream loggs to client.
EStatus Handle(std::exception &exc) override
Handle exceptions deriving from REveException.
void DisconnectEveViewer(REveViewer *)
void ScheduleMIR(const std::string &cmd, ElementId_t i, const std::string &ctype, unsigned connid)
void ClearROOTClassSaved()
Work-around uber ugly hack used in SavePrimitive and co.
void StreamToNewConnection(unsigned connid)
Register new connection and stream the world and the mandatory scenes to it.
void SendToAllConnections(const std::string &data)
std::shared_ptr< ROOT::RWebWindow > fWebWindow
void RegisterGeometryAlias(const TString &alias, const TString &filename)
Register 'name' as an alias for geometry file 'filename'.
void PreDeleteElement(REveElement *element)
Called from REveElement prior to its destruction so the framework components (like object editor) can...
void ExecuteMIR(std::shared_ptr< MIR > mir)
REveSceneList * GetScenes() const
void ClearAllSelections()
Clear all selection objects.
RExceptionHandler * fExcHandler
!< exception handler
void AssignElementId(REveElement *element)
Assign a unique ElementId to given element.
TGeoManager * GetDefaultGeometry()
Get the default geometry.
static void ExecuteInMainThread(std::function< void()> func)
void GrabImages(std::string_view event_id, std::string_view url="", int scale=1, const std::vector< std::string > &viewers={})
Ask every connected client to grab its GL viewers and POST each image to an image collector.
void GetServerStatus(REveServerStatus &)
void SetDefaultHtmlPage(const std::string &path)
Set content of default window HTML page.
void AddLocation(const std::string &name, const std::string &path)
Register new directory to THttpServer.
void Send(unsigned connid, const std::string &data)
static void Terminate()
Properly terminate global REveManager.
REveElement * FindElementById(ElementId_t id) const
Lookup ElementId in element map and return corresponding REveElement*.
void SaveVizDB(const TString &filename)
Save visualization-parameter database to file filename.
void EndChange()
Stop accepting changes and stream them.
TGeoManager * GetGeometryByAlias(const TString &alias)
Get geometry with given alias.
bool AnySceneChanged() const
Is there anything stamped and not yet streamed?
std::unordered_map< ElementId_t, REveElement * > fElementIdMap
static REveManager * Create()
If global REveManager* REX::gEve is not set initialize it.
std::unordered_map< std::string, std::shared_ptr< TMethodCall > > fMethCallMap
void WindowConnect(unsigned connid)
Process new connection from web window.
void AllowMultipleRemoteConnections(bool loopBack=true, bool useAuthKey=true)
Utility function to allow remote RWebWindow connections.
void SendMotionChanges()
Send transformation-only changes on the motion channel: the same websocket, outside the BeginChanges/...
REveElement * FindVizDBEntry(const TString &tag)
Find a visualization-parameter database entry corresponding to tag.
TGeoManager * GetGeometry(const TString &filename)
Get geometry with given filename.
void ConnectEveViewer(REveViewer *)
static void ErrorHandler(Int_t level, Bool_t abort, const char *location, const char *msg)
bool fPendingSceneChanges
Changes are stamped but not yet streamed, because the clients had not acknowledged the previous scene...
std::queue< std::shared_ptr< MIR > > fMIRqueue
void LoadVizDB(const TString &filename, Bool_t replace, Bool_t update)
Load visualization-parameter database from file filename.
void DoRedraw3D()
Perform 3D redraw of scenes and viewers whose contents has changed.
void SendBinary(unsigned connid, const void *data, std::size_t len)
void AddElement(REveElement *element, REveElement *parent=nullptr)
Add an element.
void SetClientVersion(const std::string &version)
Set client version, used as prefix in scripts URL When changed, web browser will reload all related J...
void AddGlobalElement(REveElement *element, REveElement *parent=nullptr)
Add a global element, i.e.
void Redraw3D(Bool_t resetCameras=kFALSE, Bool_t dropLogicals=kFALSE)
void SceneSubscriberWaitingResponse(unsigned cinnId)
REveScene * SpawnNewScene(const char *name, const char *title="")
Create a new scene.
void SetHttpPublic(bool)
Restrict functionality for this server when open to public.
void RemoveElement(REveElement *element, REveElement *parent)
Remove element from parent.
virtual ~REveManager()
Destructor.
void WindowDisconnect(unsigned connid)
Process disconnect of web window.
void FullRedraw3D(Bool_t resetCameras=kFALSE, Bool_t dropLogicals=kFALSE)
Perform 3D redraw of all scenes and viewers.
REveViewer * SpawnNewViewer(const char *name, const char *title="")
Create a new GL viewer.
Bool_t InsertVizDBEntry(const TString &tag, REveElement *model, Bool_t replace, Bool_t update)
Insert a new visualization-parameter database entry.
REveViewer * GetDefaultViewer() const
Get the default viewer.
void BrowseElement(ElementId_t id)
Activate EVE browser (summary view) for specified element id.
void WindowData(unsigned connid, const std::string &arg)
Process data from web window.
void Show(const RWebDisplayArgs &args="")
Show eve manager in specified browser.
REveSceneInfo Scene in a viewer.
void BeginAcceptingChanges()
Loop-wrapers over Scene children, element type checked on insertion.
void DestroyScenes()
Destroy all scenes and their contents.
void AddSubscriber(std::unique_ptr< REveClient > &&sub)
Definition REveScene.cxx:69
std::vector< char > fOutputBinary
!
Definition REveScene.hxx:76
void StreamRepresentationChanges()
Prepare data for sending element changes.
void StreamMotionChanges(nlohmann::json &arr)
Move every element whose only pending change is kCBTransBBox from the change list into arr,...
void RemoveSubscriber(unsigned int)
Definition REveScene.cxx:80
REveSelection Container for selected and highlighted elements.
static void Macro(const char *mac)
Execute macro 'mac'. Do not reload the macro.
Definition REveUtil.cxx:109
REveViewerList List of Viewers providing common operations on REveViewer collections.
void AddElement(REveElement *el) override
Call base-class implementation.
REveViewer Reve representation of TGLViewer.
A diagnostic that can be emitted by the RLogManager.
Definition RLogger.hxx:174
std::string fMessage
Definition RLogger.hxx:177
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
static std::shared_ptr< RWebWindow > Create()
Create new RWebWindow Using default RWebWindowsManager.
static bool EmbedFileDialog(const std::shared_ptr< RWebWindow > &window, unsigned connid, const std::string &args)
Create dialog instance to use as embedded dialog inside provided widget Loads libROOTBrowserv7 and tr...
static bool IsFileDialogMessage(const std::string &msg)
Check if this could be the message send by client to start new file dialog If returns true,...
static void SetSingleConnMode(bool on=true)
Enable or disable single connection mode (default on) If enabled, one connection only with any web wi...
static void SetLoopbackMode(bool on=true)
Set loopback mode for THttpServer used for web widgets By default is on.
virtual void Terminate(Int_t status=0)
Terminate the application by call TSystem::Exit() unless application has been told to return from Run...
virtual Color_t GetLineColor() const
Return the line color.
Definition TAttLine.h:36
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
void * DynamicCast(const TClass *base, void *obj, Bool_t up=kTRUE)
Cast obj of this class type up to baseclass cl if up is true.
Definition TClass.cxx:5036
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition TClass.cxx:4505
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2999
The color creation and management class.
Definition TColor.h:22
virtual void GetRGB(Float_t &r, Float_t &g, Float_t &b) const
Definition TColor.h:55
static Int_t GetColor(const char *hexcolor)
Static method returning color number for color specified by hex color string of form: "#rrggbb",...
Definition TColor.cxx:1939
static void SetColorThreshold(Float_t t)
This method specifies the color threshold used by GetColor to retrieve a color.
Definition TColor.cxx:2008
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:511
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
An identity transformation.
Definition TGeoMatrix.h:407
The manager class for any TGeo geometry.
Definition TGeoManager.h:46
static void UnlockGeometry()
Unlock current geometry.
TObjArray * GetListOfVolumes() const
TObjArray * GetListOfMatrices() const
static Bool_t IsLocked()
Check lock state.
static TGeoManager * Import(const char *filename, const char *name="", Option_t *option="")
static function Import a geometry from a gdml or ROOT file
static void LockGeometry()
Lock current geometry so that no other geometry can be imported.
TGeoVolume * GetTopVolume() const
TGeoVolume, TGeoVolumeMulti, TGeoVolumeAssembly are the volume classes.
Definition TGeoVolume.h:45
void VisibleDaughters(Bool_t vis=kTRUE)
set visibility for daughters
void SetLineColor(Color_t lcolor) override
Set the line color.
TMap implements an associative array of (key,value) pairs using a THashTable for efficient retrieval ...
Definition TMap.h:40
void Add(TObject *obj) override
This function may not be used (but we need to provide it since it is a pure virtual in TCollection).
Definition TMap.cxx:53
virtual void SetOwnerKeyValue(Bool_t ownkeys=kTRUE, Bool_t ownvals=kTRUE)
Set ownership for keys and values.
Definition TMap.cxx:351
TObject * FindObject(const char *keyname) const override
Check if a (key,value) pair exists with keyname as name of the key.
Definition TMap.cxx:214
TObject * GetValue(const char *keyname) const
Returns a pointer to the value associated with keyname as name of the key.
Definition TMap.cxx:235
Each ROOT class (see TClass) has a linked list of methods.
Definition TMethod.h:38
An array of TObjects.
Definition TObjArray.h:31
TObject * At(Int_t idx) const override
Definition TObjArray.h:170
Collectable string class.
Definition TObjString.h:28
TString & String()
Definition TObjString.h:48
Mother of all ROOT objects.
Definition TObject.h:42
Wrapper for PCRE library (Perl Compatible Regular Expressions).
Definition TPRegexp.h:97
Class used by TMap to store (key,value) pairs.
Definition TMap.h:103
void SetValue(TObject *val)
Definition TMap.h:123
TObject * Value() const
Definition TMap.h:122
Basic string class.
Definition TString.h:137
const char * Data() const
Definition TString.h:385
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition TString.cxx:2438
void Beep(Int_t freq=-1, Int_t duration=-1, Bool_t setDefault=kFALSE)
Beep for duration milliseconds with a tone of frequency freq.
Definition TSystem.cxx:327
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition TSystem.cxx:1296
virtual int GetPid()
Get process id.
Definition TSystem.cxx:721
virtual void AddTimer(TTimer *t)
Add timer to list of system timers.
Definition TSystem.cxx:474
virtual int GetProcInfo(ProcInfo_t *info) const
Returns cpu and memory used by this process into the ProcInfo_t structure.
Definition TSystem.cxx:2516
virtual TTimer * RemoveTimer(TTimer *t)
Remove timer from list of system timers.
Definition TSystem.cxx:484
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
Double_t ex[n]
Definition legend1.C:17
Namespace for ROOT features in testing.
Definition TROOT.h:100
ROOT::RLogChannel & REveLog()
Log channel for Eve diagnostics.
Definition REveTypes.cxx:52
R__EXTERN REveManager * gEve
@ kDebug
Debug information; only useful for developers; can have added verbosity up to 255-kDebug.
@ kError
An error.
std::vector< REveScene * > removedWatch
std::vector< REveScene * > addedWatch
TMarker m
Definition textangle.C:8