33 using namespace std::string_literals;
39 ROOT::Experimental::RWebWindow::WebConn::~WebConn()
42 fHold->SetTextContent(
"console.log('execute holder script'); if (window) setTimeout (window.close, 1000); if (window) window.close();");
43 fHold->NotifyCondition();
72 ROOT::Experimental::RWebWindow::RWebWindow() =
default;
78 ROOT::Experimental::RWebWindow::~RWebWindow()
81 fMaster->RemoveEmbedWindow(fMasterConnId, fMasterChannel);
84 fWSHandler->SetDisabled();
89 auto lst = GetConnections();
93 std::lock_guard<std::mutex> grd(fConnMutex);
98 for (
auto &conn : lst) {
99 conn->fActive =
false;
100 for (
auto &elem: conn->fEmbed)
101 elem.second->fMaster.reset();
104 fMgr->Unregister(*
this);
113 void ROOT::Experimental::RWebWindow::SetPanelName(
const std::string &name)
116 std::lock_guard<std::mutex> grd(fConnMutex);
117 if (!fConn.empty()) {
118 R__ERROR_HERE(
"webgui") <<
"Cannot configure panel when connection exists";
124 SetDefaultPage(
"file:rootui5sys/panel/panel.html");
130 std::shared_ptr<ROOT::Experimental::RWebWindowWSHandler>
131 ROOT::Experimental::RWebWindow::CreateWSHandler(std::shared_ptr<RWebWindowsManager> mgr,
unsigned id,
double tmout)
135 fOperationTmout = tmout;
137 fSendMT = fMgr->IsUseSenderThreads();
138 fWSHandler = std::make_shared<RWebWindowWSHandler>(*
this, Form(
"win%u", GetId()));
147 std::string ROOT::Experimental::RWebWindow::GetUrl(
bool remote)
149 return fMgr->GetUrl(*
this, remote);
155 THttpServer *ROOT::Experimental::RWebWindow::GetServer()
157 return fMgr->GetServer();
165 unsigned ROOT::Experimental::RWebWindow::Show(
const RWebDisplayArgs &args)
167 return fMgr->ShowWindow(*
this,
false, args);
176 unsigned ROOT::Experimental::RWebWindow::MakeBatch(
bool create_new,
const RWebDisplayArgs &args)
180 connid = FindBatch();
182 connid = fMgr->ShowWindow(*
this,
true, args);
191 unsigned ROOT::Experimental::RWebWindow::FindBatch()
193 std::lock_guard<std::mutex> grd(fConnMutex);
195 for (
auto &entry : fPendingConn) {
196 if (entry->fBatchMode)
197 return entry->fConnId;
200 for (
auto &conn : fConn) {
201 if (conn->fBatchMode)
202 return conn->fConnId;
214 unsigned ROOT::Experimental::RWebWindow::GetDisplayConnection()
const
216 std::lock_guard<std::mutex> grd(fConnMutex);
218 for (
auto &entry : fPendingConn) {
219 if (!entry->fBatchMode)
220 return entry->fConnId;
223 for (
auto &conn : fConn) {
224 if (!conn->fBatchMode)
225 return conn->fConnId;
235 std::shared_ptr<ROOT::Experimental::RWebWindow::WebConn> ROOT::Experimental::RWebWindow::FindOrCreateConnection(
unsigned wsid,
bool make_new,
const char *query)
237 std::lock_guard<std::mutex> grd(fConnMutex);
239 for (
auto &conn : fConn) {
240 if (conn->fWSId == wsid)
248 std::shared_ptr<WebConn> key;
249 std::string keyvalue;
253 url.SetOptions(query);
254 if (url.HasOption(
"key"))
255 keyvalue = url.GetValueFromOptions(
"key");
258 if (!keyvalue.empty())
259 for (
size_t n = 0; n < fPendingConn.size(); ++n)
260 if (fPendingConn[n]->fKey == keyvalue) {
261 key = std::move(fPendingConn[n]);
262 fPendingConn.erase(fPendingConn.begin() + n);
270 fConn.emplace_back(key);
272 fConn.emplace_back(std::make_shared<WebConn>(++fConnCnt, wsid));
282 std::shared_ptr<ROOT::Experimental::RWebWindow::WebConn> ROOT::Experimental::RWebWindow::RemoveConnection(
unsigned wsid)
285 std::shared_ptr<WebConn> res;
288 std::lock_guard<std::mutex> grd(fConnMutex);
290 for (
size_t n = 0; n < fConn.size(); ++n)
291 if (fConn[n]->fWSId == wsid) {
292 res = std::move(fConn[n]);
293 fConn.erase(fConn.begin() + n);
294 res->fActive =
false;
300 for (
auto &elem: res->fEmbed)
301 elem.second->fMaster.reset();
311 bool ROOT::Experimental::RWebWindow::ProcessBatchHolder(std::shared_ptr<THttpCallArg> &arg)
313 std::string query = arg->GetQuery();
315 if (query.compare(0, 4,
"key=") != 0)
318 std::string key = query.substr(4);
320 std::shared_ptr<THttpCallArg> prev;
322 bool found_key =
false;
326 std::lock_guard<std::mutex> grd(fConnMutex);
327 for (
auto &entry : fPendingConn) {
328 if (entry->fKey == key) {
331 prev = std::move(entry->fHold);
337 for (
auto &conn : fConn) {
338 if (conn->fKey == key) {
340 prev = std::move(conn->fHold);
348 prev->SetTextContent(
"console.log('execute holder script'); if (window) window.close();");
349 prev->NotifyCondition();
359 void ROOT::Experimental::RWebWindow::ProvideQueueEntry(
unsigned connid, EQueueEntryKind kind, std::string &&arg)
362 std::lock_guard<std::mutex> grd(fInputQueueMutex);
363 fInputQueue.emplace(connid, kind, std::move(arg));
373 void ROOT::Experimental::RWebWindow::InvokeCallbacks(
bool force)
375 if (fCallbacksThrdIdSet && (fCallbacksThrdId != std::this_thread::get_id()) && !force)
380 EQueueEntryKind kind;
384 std::lock_guard<std::mutex> grd(fInputQueueMutex);
385 if (fInputQueue.size() == 0)
387 auto &entry = fInputQueue.front();
388 connid = entry.fConnId;
390 arg = std::move(entry.fData);
395 case kind_None:
break;
398 fConnCallback(connid);
402 fDataCallback(connid, arg);
404 case kind_Disconnect:
405 if (fDisconnCallback)
406 fDisconnCallback(connid);
417 unsigned ROOT::Experimental::RWebWindow::AddDisplayHandle(
bool batch_mode,
const std::string &key, std::unique_ptr<RWebDisplayHandle> &handle)
419 std::lock_guard<std::mutex> grd(fConnMutex);
423 auto conn = std::make_shared<WebConn>(fConnCnt, batch_mode, key);
425 std::swap(conn->fDisplayHandle, handle);
427 fPendingConn.emplace_back(conn);
435 bool ROOT::Experimental::RWebWindow::HasKey(
const std::string &key)
const
437 std::lock_guard<std::mutex> grd(fConnMutex);
439 for (
auto &entry : fPendingConn) {
440 if (entry->fKey == key)
444 for (
auto &conn : fConn) {
445 if (conn->fKey == key)
456 void ROOT::Experimental::RWebWindow::CheckPendingConnections()
460 timestamp_t stamp = std::chrono::system_clock::now();
462 float tmout = fMgr->GetLaunchTmout();
464 ConnectionsList_t selected;
467 std::lock_guard<std::mutex> grd(fConnMutex);
469 auto pred = [&](std::shared_ptr<WebConn> &e) {
470 std::chrono::duration<double> diff = stamp - e->fSendStamp;
472 if (diff.count() > tmout) {
473 R__DEBUG_HERE(
"webgui") <<
"Halt process after " << diff.count() <<
" sec";
474 selected.emplace_back(e);
481 fPendingConn.erase(std::remove_if(fPendingConn.begin(), fPendingConn.end(), pred), fPendingConn.end());
491 void ROOT::Experimental::RWebWindow::CheckInactiveConnections()
493 timestamp_t stamp = std::chrono::system_clock::now();
495 double batch_tmout = 20.;
497 std::vector<std::shared_ptr<WebConn>> clr;
500 std::lock_guard<std::mutex> grd(fConnMutex);
502 auto pred = [&](std::shared_ptr<WebConn> &conn) {
503 std::chrono::duration<double> diff = stamp - conn->fSendStamp;
505 if ((diff.count() > batch_tmout) && conn->fBatchMode) {
506 conn->fActive =
false;
507 clr.emplace_back(conn);
513 fConn.erase(std::remove_if(fConn.begin(), fConn.end(), pred), fConn.end());
516 for (
auto &entry : clr)
517 ProvideQueueEntry(entry->fConnId, kind_Disconnect,
""s);
525 bool ROOT::Experimental::RWebWindow::ProcessWS(THttpCallArg &arg)
527 if (arg.GetWSId() == 0)
530 if (arg.IsMethod(
"WS_CONNECT")) {
532 std::lock_guard<std::mutex> grd(fConnMutex);
535 if (fConnLimit && (fConn.size() >= fConnLimit))
541 if (arg.IsMethod(
"WS_READY")) {
543 auto conn = FindOrCreateConnection(arg.GetWSId(),
true, arg.GetQuery());
546 R__ERROR_HERE(
"webgui") <<
"WSHandle with given websocket id " << arg.GetWSId() <<
" already exists";
553 if (arg.IsMethod(
"WS_CLOSE")) {
556 auto conn = RemoveConnection(arg.GetWSId());
559 ProvideQueueEntry(conn->fConnId, kind_Disconnect,
""s);
564 if (!arg.IsMethod(
"WS_DATA")) {
565 R__ERROR_HERE(
"webgui") <<
"only WS_DATA request expected!";
569 auto conn = FindConnection(arg.GetWSId());
572 R__ERROR_HERE(
"webgui") <<
"Get websocket data without valid connection - ignore!!!";
576 if (arg.GetPostDataLength() <= 0)
582 const char *buf = (
const char *)arg.GetPostData();
583 char *str_end =
nullptr;
585 unsigned long ackn_oper = std::strtoul(buf, &str_end, 10);
586 if (!str_end || *str_end !=
':') {
587 R__ERROR_HERE(
"webgui") <<
"missing number of acknowledged operations";
591 unsigned long can_send = std::strtoul(str_end + 1, &str_end, 10);
592 if (!str_end || *str_end !=
':') {
593 R__ERROR_HERE(
"webgui") <<
"missing can_send counter";
597 unsigned long nchannel = std::strtoul(str_end + 1, &str_end, 10);
598 if (!str_end || *str_end !=
':') {
599 R__ERROR_HERE(
"webgui") <<
"missing channel number";
603 Long_t processed_len = (str_end + 1 - buf);
605 if (processed_len > arg.GetPostDataLength()) {
606 R__ERROR_HERE(
"webgui") <<
"corrupted buffer";
610 std::string cdata(str_end + 1, arg.GetPostDataLength() - processed_len);
612 timestamp_t stamp = std::chrono::system_clock::now();
615 std::lock_guard<std::mutex> grd(conn->fMutex);
617 conn->fSendCredits += ackn_oper;
619 conn->fClientCredits = (int)can_send;
620 conn->fRecvStamp = stamp;
623 if (fProtocolCnt >= 0)
624 if (!fProtocolConnId || (conn->fConnId == fProtocolConnId)) {
625 fProtocolConnId = conn->fConnId;
628 if ((nchannel != 0) || (cdata.find(
"READY=") == 0)) {
629 if (fProtocol.length() > 2)
630 fProtocol.insert(fProtocol.length() - 1,
",");
631 fProtocol.insert(fProtocol.length() - 1,
"\"send\"");
633 std::ofstream pfs(fProtocolFileName);
634 pfs.write(fProtocol.c_str(), fProtocol.length());
641 if ((cdata.find(
"READY=") == 0) && !conn->fReady) {
642 std::string key = cdata.substr(6);
644 if (key.empty() && IsNativeOnlyConn()) {
645 RemoveConnection(conn->fWSId);
649 if (!key.empty() && !conn->fKey.empty() && (conn->fKey != key)) {
650 R__ERROR_HERE(
"webgui") <<
"Key mismatch after established connection " << key <<
" != " << conn->fKey;
651 RemoveConnection(conn->fWSId);
655 if (!fPanelName.empty()) {
657 Send(conn->fConnId,
"SHOWPANEL:"s + fPanelName);
660 ProvideQueueEntry(conn->fConnId, kind_Connect,
""s);
663 }
else if (cdata.compare(0,8,
"CLOSECH=") == 0) {
664 int channel = std::stoi(cdata.substr(8));
665 auto iter = conn->fEmbed.find(channel);
666 if (iter != conn->fEmbed.end()) {
667 iter->second->ProvideQueueEntry(conn->fConnId, kind_Disconnect,
""s);
668 conn->fEmbed.erase(iter);
671 }
else if (fPanelName.length() && (conn->fReady < 10)) {
672 if (cdata ==
"PANEL_READY") {
673 R__DEBUG_HERE(
"webgui") <<
"Get panel ready " << fPanelName;
674 ProvideQueueEntry(conn->fConnId, kind_Connect,
""s);
677 ProvideQueueEntry(conn->fConnId, kind_Disconnect,
""s);
678 RemoveConnection(conn->fWSId);
680 }
else if (nchannel == 1) {
681 ProvideQueueEntry(conn->fConnId, kind_Data, std::move(cdata));
682 }
else if (nchannel > 1) {
684 auto embed_window = conn->fEmbed[nchannel];
686 embed_window->ProvideQueueEntry(conn->fConnId, kind_Data, std::move(cdata));
694 void ROOT::Experimental::RWebWindow::CompleteWSSend(
unsigned wsid)
696 auto conn = FindConnection(wsid);
702 std::lock_guard<std::mutex> grd(conn->fMutex);
703 conn->fDoingSend =
false;
706 CheckDataToSend(conn);
713 std::string ROOT::Experimental::RWebWindow::_MakeSendHeader(std::shared_ptr<WebConn> &conn,
bool txt,
const std::string &data,
int chid)
717 if (!conn->fWSId || !fWSHandler) {
718 R__ERROR_HERE(
"webgui") <<
"try to send text data when connection not established";
722 if (conn->fSendCredits <= 0) {
723 R__ERROR_HERE(
"webgui") <<
"No credits to send text data via connection";
727 if (conn->fDoingSend) {
728 R__ERROR_HERE(
"webgui") <<
"Previous send operation not completed yet";
733 buf.reserve(data.length() + 100);
735 buf.append(std::to_string(conn->fRecvCount));
737 buf.append(std::to_string(conn->fSendCredits));
739 conn->fRecvCount = 0;
740 conn->fSendCredits--;
742 buf.append(std::to_string(chid));
747 }
else if (data.length()==0) {
748 buf.append(
"$$nullbinary$$");
750 buf.append(
"$$binary$$");
760 bool ROOT::Experimental::RWebWindow::CheckDataToSend(std::shared_ptr<WebConn> &conn)
762 std::string hdr, data;
765 std::lock_guard<std::mutex> grd(conn->fMutex);
767 if (!conn->fActive || (conn->fSendCredits <= 0) || conn->fDoingSend)
return false;
769 if (!conn->fQueue.empty()) {
770 QueueItem &item = conn->fQueue.front();
771 hdr = _MakeSendHeader(conn, item.fText, item.fData, item.fChID);
772 if (!hdr.empty() && !item.fText)
773 data = std::move(item.fData);
775 }
else if ((conn->fClientCredits < 3) && (conn->fRecvCount > 1)) {
777 hdr = _MakeSendHeader(conn,
true,
"KEEPALIVE", 0);
780 if (hdr.empty())
return false;
782 conn->fDoingSend =
true;
788 res = fWSHandler->SendCharStarWS(conn->fWSId, hdr.c_str());
790 res = fWSHandler->SendHeaderWS(conn->fWSId, hdr.c_str(), data.data(), data.length());
794 if (res >=0)
return true;
798 std::lock_guard<std::mutex> grd(conn->fMutex);
799 conn->fDoingSend =
false;
808 void ROOT::Experimental::RWebWindow::CheckDataToSend(
bool only_once)
811 auto arr = GetConnections(0,
true);
816 for (
auto &conn : arr)
817 if (CheckDataToSend(conn))
822 }
while (!only_once);
828 void ROOT::Experimental::RWebWindow::Sync()
834 CheckPendingConnections();
836 CheckInactiveConnections();
842 std::string ROOT::Experimental::RWebWindow::GetAddr()
const
844 return fWSHandler->GetName();
852 std::string ROOT::Experimental::RWebWindow::GetRelativeAddr(
const std::shared_ptr<RWebWindow> &win)
const
854 if (fMgr != win->fMgr) {
855 R__ERROR_HERE(
"WebDisplay") <<
"Same web window manager should be used";
859 std::string res(
"../");
860 res.append(win->GetAddr());
871 void ROOT::Experimental::RWebWindow::SetClientVersion(
const std::string &vers)
873 std::lock_guard<std::mutex> grd(fConnMutex);
874 fClientVersion = vers;
880 std::string ROOT::Experimental::RWebWindow::GetClientVersion()
const
882 std::lock_guard<std::mutex> grd(fConnMutex);
883 return fClientVersion;
891 void ROOT::Experimental::RWebWindow::SetUserArgs(
const std::string &args)
893 std::lock_guard<std::mutex> grd(fConnMutex);
901 std::string ROOT::Experimental::RWebWindow::GetUserArgs()
const
903 std::lock_guard<std::mutex> grd(fConnMutex);
910 int ROOT::Experimental::RWebWindow::NumConnections(
bool with_pending)
const
912 std::lock_guard<std::mutex> grd(fConnMutex);
913 auto sz = fConn.size();
915 sz += fPendingConn.size();
927 void ROOT::Experimental::RWebWindow::RecordData(
const std::string &fname,
const std::string &fprefix)
929 fProtocolFileName = fname;
930 fProtocolCnt = fProtocolFileName.empty() ? -1 : 0;
931 fProtocolConnId = fProtocolFileName.empty() ? 0 : GetConnectionId(0);
932 fProtocolPrefix = fprefix;
941 unsigned ROOT::Experimental::RWebWindow::GetConnectionId(
int num)
const
943 std::lock_guard<std::mutex> grd(fConnMutex);
944 return ((num >= 0) && (num < (
int)fConn.size()) && fConn[num]->fActive) ? fConn[num]->fConnId : 0;
952 bool ROOT::Experimental::RWebWindow::HasConnection(
unsigned connid,
bool only_active)
const
954 std::lock_guard<std::mutex> grd(fConnMutex);
956 for (
auto &conn : fConn) {
957 if (connid && (conn->fConnId != connid))
959 if (conn->fActive || !only_active)
964 for (
auto &conn : fPendingConn) {
965 if (!connid || (conn->fConnId == connid))
977 void ROOT::Experimental::RWebWindow::CloseConnections()
979 SubmitData(0,
true,
"CLOSE", 0);
986 void ROOT::Experimental::RWebWindow::CloseConnection(
unsigned connid)
989 SubmitData(connid,
true,
"CLOSE", 0);
995 ROOT::Experimental::RWebWindow::ConnectionsList_t ROOT::Experimental::RWebWindow::GetConnections(
unsigned connid,
bool only_active)
const
997 ConnectionsList_t arr;
1000 std::lock_guard<std::mutex> grd(fConnMutex);
1002 for (
auto &conn : fConn) {
1003 if ((conn->fActive || !only_active) && (!connid || (conn->fConnId == connid)))
1004 arr.push_back(conn);
1008 for (
auto &conn : fPendingConn)
1009 if (!connid || (conn->fConnId == connid))
1010 arr.push_back(conn);
1021 bool ROOT::Experimental::RWebWindow::CanSend(
unsigned connid,
bool direct)
const
1023 auto arr = GetConnections(connid, direct);
1025 auto maxqlen = GetMaxQueueLength();
1027 for (
auto &conn : arr) {
1029 std::lock_guard<std::mutex> grd(conn->fMutex);
1031 if (direct && (!conn->fQueue.empty() || (conn->fSendCredits == 0) || conn->fDoingSend))
1034 if (conn->fQueue.size() >= maxqlen)
1046 int ROOT::Experimental::RWebWindow::GetSendQueueLength(
unsigned connid)
const
1050 for (
auto &conn : GetConnections(connid)) {
1051 std::lock_guard<std::mutex> grd(conn->fMutex);
1052 int len = conn->fQueue.size();
1053 if (len > maxq) maxq = len;
1065 void ROOT::Experimental::RWebWindow::SubmitData(
unsigned connid,
bool txt, std::string &&data,
int chid)
1068 return fMaster->SubmitData(fMasterConnId, txt, std::move(data), fMasterChannel);
1070 auto arr = GetConnections(connid);
1071 auto cnt = arr.size();
1072 auto maxqlen = GetMaxQueueLength();
1074 timestamp_t stamp = std::chrono::system_clock::now();
1076 for (
auto &conn : arr) {
1078 if (fProtocolCnt >= 0)
1079 if (!fProtocolConnId || (conn->fConnId == fProtocolConnId)) {
1080 fProtocolConnId = conn->fConnId;
1081 std::string fname = fProtocolPrefix;
1082 fname.append(
"msg");
1083 fname.append(std::to_string(fProtocolCnt++));
1084 fname.append(txt ?
".txt" :
".bin");
1086 std::ofstream ofs(fname);
1087 ofs.write(data.c_str(), data.length());
1090 if (fProtocol.length() > 2)
1091 fProtocol.insert(fProtocol.length() - 1,
",");
1092 fProtocol.insert(fProtocol.length() - 1,
"\""s + fname +
"\""s);
1094 std::ofstream pfs(fProtocolFileName);
1095 pfs.write(fProtocol.c_str(), fProtocol.length());
1099 conn->fSendStamp = stamp;
1101 std::lock_guard<std::mutex> grd(conn->fMutex);
1103 if (conn->fQueue.size() < maxqlen) {
1105 conn->fQueue.emplace(chid, txt, std::string(data));
1107 conn->fQueue.emplace(chid, txt, std::move(data));
1109 R__ERROR_HERE(
"webgui") <<
"Maximum queue length achieved";
1120 void ROOT::Experimental::RWebWindow::Send(
unsigned connid,
const std::string &data)
1122 SubmitData(connid,
true, std::string(data), 1);
1129 void ROOT::Experimental::RWebWindow::SendBinary(
unsigned connid, std::string &&data)
1131 SubmitData(connid,
false, std::move(data), 1);
1138 void ROOT::Experimental::RWebWindow::SendBinary(
unsigned connid,
const void *data, std::size_t len)
1142 std::copy((
const char *)data, (
const char *)data + len, buf.begin());
1143 SubmitData(connid,
false, std::move(buf), 1);
1149 void ROOT::Experimental::RWebWindow::AssignCallbackThreadId()
1151 fCallbacksThrdIdSet =
true;
1152 fCallbacksThrdId = std::this_thread::get_id();
1153 if (!RWebWindowsManager::IsMainThrd()) {
1155 }
else if (fMgr->IsUseHttpThread()) {
1157 R__ERROR_HERE(
"webgui") <<
"create web window from main thread when THttpServer created with special thread - not supported";
1182 void ROOT::Experimental::RWebWindow::SetDataCallBack(WebWindowDataCallback_t func)
1184 AssignCallbackThreadId();
1185 fDataCallback = func;
1191 void ROOT::Experimental::RWebWindow::SetConnectCallBack(WebWindowConnectCallback_t func)
1193 AssignCallbackThreadId();
1194 fConnCallback = func;
1200 void ROOT::Experimental::RWebWindow::SetDisconnectCallBack(WebWindowConnectCallback_t func)
1202 AssignCallbackThreadId();
1203 fDisconnCallback = func;
1209 void ROOT::Experimental::RWebWindow::SetCallBacks(WebWindowConnectCallback_t conn, WebWindowDataCallback_t data, WebWindowConnectCallback_t disconn)
1211 AssignCallbackThreadId();
1212 fConnCallback = conn;
1213 fDataCallback = data;
1214 fDisconnCallback = disconn;
1225 int ROOT::Experimental::RWebWindow::WaitFor(WebWindowWaitFunc_t check)
1227 return fMgr->WaitFor(*
this, check);
1239 int ROOT::Experimental::RWebWindow::WaitForTimed(WebWindowWaitFunc_t check)
1241 return fMgr->WaitFor(*
this, check,
true, GetOperationTmout());
1253 int ROOT::Experimental::RWebWindow::WaitForTimed(WebWindowWaitFunc_t check,
double duration)
1255 return fMgr->WaitFor(*
this, check,
true, duration);
1263 void ROOT::Experimental::RWebWindow::Run(
double tm)
1265 if (!fCallbacksThrdIdSet || (fCallbacksThrdId != std::this_thread::get_id())) {
1266 R__WARNING_HERE(
"webgui") <<
"Change thread id where RWebWindow is executed";
1267 fCallbacksThrdIdSet =
true;
1268 fCallbacksThrdId = std::this_thread::get_id();
1274 WaitForTimed([](
double) {
return 0; }, tm);
1282 unsigned ROOT::Experimental::RWebWindow::AddEmbedWindow(std::shared_ptr<RWebWindow> window,
int channel)
1287 auto arr = GetConnections(0,
true);
1288 if (arr.size() == 0)
1292 if (arr[0]->fEmbed.find(channel) != arr[0]->fEmbed.end())
1295 arr[0]->fEmbed[channel] = window;
1297 return arr[0]->fConnId;
1303 void ROOT::Experimental::RWebWindow::RemoveEmbedWindow(
unsigned connid,
int channel)
1305 auto arr = GetConnections(connid);
1307 for (
auto &conn : arr) {
1308 auto iter = conn->fEmbed.find(channel);
1309 if (iter != conn->fEmbed.end())
1310 conn->fEmbed.erase(iter);
1319 std::shared_ptr<ROOT::Experimental::RWebWindow> ROOT::Experimental::RWebWindow::Create()
1321 return ROOT::Experimental::RWebWindowsManager::Instance()->CreateWindow();
1329 void ROOT::Experimental::RWebWindow::TerminateROOT()
1339 unsigned ROOT::Experimental::RWebWindow::ShowWindow(std::shared_ptr<RWebWindow> window,
const RWebDisplayArgs &args)
1344 if (args.GetBrowserKind() == RWebDisplayArgs::kEmbedded) {
1345 unsigned connid = args.fMaster ? args.fMaster->AddEmbedWindow(window, args.fMasterChannel) : 0;
1348 window->fMaster = args.fMaster;
1349 window->fMasterConnId = connid;
1350 window->fMasterChannel = args.fMasterChannel;
1353 args.fMaster->SubmitData(connid,
true,
"EMBED_DONE"s, args.fMasterChannel);
1356 window->ProvideQueueEntry(connid, kind_Connect,
""s);
1362 return window->Show(args);