17#include "RConfigure.h" 
   45using namespace std::string_literals;
 
   61   static std::map<std::string, std::unique_ptr<RWebDisplayHandle::Creator>> 
sMap;
 
 
   77      if (
libname == 
"ChromeCreator") {
 
   78         m.emplace(
name, std::make_unique<ChromeCreator>(
name == 
"edge"));
 
   79      } 
else if (
libname == 
"FirefoxCreator") {
 
   80         m.emplace(
name, std::make_unique<FirefoxCreator>());
 
   81      } 
else if (
libname == 
"BrowserCreator") {
 
   82         m.emplace(
name, std::make_unique<BrowserCreator>(
false));
 
   93   static std::unique_ptr<RWebDisplayHandle::Creator> dummy;
 
 
  131         gSystem->
Exec((
"taskkill /F /PID "s + std::to_string(
fPid) + 
" >NUL 2>NUL").c_str());
 
  132      std::string rmdir = 
"rmdir /S /Q ", 
rmfile = 
"del /F ";
 
  136      std::string rmdir = 
"rm -rf ", 
rmfile = 
"rm -f ";
 
 
 
  156      if (exec.find(
"$url") == std::string::npos) {
 
  159         fExec = exec + 
" $url";
 
  161         fExec = exec + 
" $url &";
 
  165         auto pos = exec.find(
" ");
 
  166         if (pos != std::string::npos)
 
  167            fProg = exec.substr(0, pos);
 
  170      fExec = 
"open \'$url\'";
 
  172      fExec = 
"start $url";
 
  174      fExec = 
"xdg-open \'$url\' &";
 
 
  183   if (
nexttry.empty() || !fProg.empty())
 
  188      fProg = std::regex_replace(
nexttry, std::regex(
"%20"), 
" ");
 
  201   if (pos != std::string::npos)
 
 
  215std::unique_ptr<RWebDisplayHandle>
 
  223      std::cout << 
"New web window: " << 
url << std::endl;
 
  224      return std::make_unique<RWebBrowserHandle>(
url, 
"", 
"", 
"");
 
  231      exec = fHeadlessExec;
 
  235      exec = 
"$prog $url &";
 
  245   ProcessGeometry(exec, args);
 
  252   if (((
url.find(
"token=") != std::string::npos) || (
url.find(
"key=") != std::string::npos)) && !args.
IsBatchMode() && !args.
IsHeadless()) {
 
  262         std::string 
content = std::regex_replace(
 
  264            "<html lang=\"en\">\n" 
  266            "   <meta charset=\"utf-8\">\n" 
  267            "   <meta http-equiv=\"refresh\" content=\"0;url=$url\"/>\n" 
  268            "   <title>Opening ROOT widget</title>\n" 
  272            "  This page should redirect you to a ROOT widget. If it doesn't,\n" 
  273            "  <a href=\"$url\">click here to go to ROOT</a>.\n" 
  276            "</html>\n", std::regex(
"\\$url"), 
url);
 
  297   exec = std::regex_replace(exec, std::regex(
"\\$rootetcdir"), 
TROOT::GetEtcDir().Data());
 
  298   exec = std::regex_replace(exec, std::regex(
"\\$url"), 
url);
 
  299   exec = std::regex_replace(exec, std::regex(
"\\$width"), 
swidth);
 
  300   exec = std::regex_replace(exec, std::regex(
"\\$height"), 
sheight);
 
  301   exec = std::regex_replace(exec, std::regex(
"\\$posx"), 
sposx);
 
  302   exec = std::regex_replace(exec, std::regex(
"\\$posy"), 
sposy);
 
  304   if (exec.compare(0,5,
"fork:") == 0) {
 
  324      std::vector<char *> 
argv;
 
  325      argv.push_back((
char *) fProg.c_str());
 
  327         argv.push_back((
char *)
fargs->At(
n)->GetName());
 
  328      argv.push_back(
nullptr);
 
  330      R__LOG_DEBUG(0, 
WebGUILog()) << 
"Show web window in browser with posix_spawn:\n" << fProg << 
" " << exec;
 
  343      return std::make_unique<RWebBrowserHandle>(
url, rmdir, 
tmpfile, pid);
 
  355      exec = 
"wmic process call create '"s + 
gSystem->
UnixPathName(fProg.c_str()) + exec + 
"' | find \"ProcessId\" "s;
 
  361      ss >> tmp >> 
c >> pid;
 
  371      return std::make_unique<RWebBrowserHandle>(
url, rmdir, 
tmpfile, pid);
 
  377   if (exec.rfind(
"&") == exec.length() - 1) {
 
  380      exec.resize(exec.length() - 1);
 
  382      std::vector<char *> 
argv;
 
  391         argv.push_back((
char *)
fargs->At(
n)->GetName());
 
  392      argv.push_back(
nullptr);
 
  398      return std::make_unique<RWebBrowserHandle>(
url, rmdir, 
tmpfile, 
""s);
 
  406   std::string 
prog = std::regex_replace(fProg, std::regex(
" "), 
"\\ ");
 
  408   std::string 
prog = fProg;
 
  413   exec = std::regex_replace(exec, std::regex(
"\\$prog"), 
prog);
 
  418      auto p = exec.length();
 
  419      if (exec.rfind(
"&") == 
p-1) --
p;
 
 
  453      TestProg(
"\\Microsoft\\Edge\\Application\\msedge.exe", 
true);
 
  455      TestProg(
"\\Google\\Chrome\\Application\\chrome.exe", 
true);
 
  458   TestProg(
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
 
  462   TestProg(
"/usr/bin/chromium-browser");
 
  463   TestProg(
"/usr/bin/chrome-browser");
 
  464   TestProg(
"/usr/bin/google-chrome-stable");
 
  480      fBatchExec = 
gEnv->
GetValue((
fEnvPrefix + 
"Batch").c_str(), 
"$prog --headless --no-sandbox --no-zygote --disable-extensions --disable-gpu --disable-audio-output $geometry $url");
 
  481      fHeadlessExec = 
gEnv->
GetValue((
fEnvPrefix + 
"Headless").c_str(), 
"$prog --headless --no-sandbox --no-zygote --disable-extensions --disable-gpu --disable-audio-output $geometry \'$url\' --dump-dom >/dev/null &");
 
  484      fBatchExec = 
gEnv->
GetValue((
fEnvPrefix + 
"Batch").c_str(), 
"$prog --headless=new --no-sandbox --no-zygote --disable-extensions --disable-gpu --disable-audio-output $geometry $url");
 
  485      fHeadlessExec = 
gEnv->
GetValue((
fEnvPrefix + 
"Headless").c_str(), 
"$prog --headless=new --no-sandbox --no-zygote --disable-extensions --disable-gpu --disable-audio-output $geometry \'$url\' &");
 
  487   fExec = 
gEnv->
GetValue((
fEnvPrefix + 
"Interactive").c_str(), 
"$prog $geometry --new-window --app=\'$url\' >/dev/null 2>/dev/null &");
 
 
  506      geometry.append(
"--window-position="s + std::to_string(args.
GetX() >= 0 ? args.
GetX() : 0) + 
","s +
 
  507                                           std::to_string(args.
GetY() >= 0 ? args.
GetY() : 0));
 
  515   exec = std::regex_replace(exec, std::regex(
"\\$geometry"), 
geometry);
 
 
  526   if (exec.find(
"$profile") == std::string::npos)
 
  547   exec = std::regex_replace(exec, std::regex(
"\\$profile"), 
profile_arg);
 
 
  561   TestProg(
"\\Mozilla Firefox\\firefox.exe", 
true);
 
  564   TestProg(
"/Applications/Firefox.app/Contents/MacOS/firefox");
 
  576   fExec = 
gEnv->
GetValue(
"WebGui.FirefoxInteractive", 
"$prog -no-remote $profile $geometry $url &");
 
  578   fBatchExec = 
gEnv->
GetValue(
"WebGui.FirefoxBatch", 
"$prog --headless --private-window -no-remote $profile $url");
 
  580   fExec = 
gEnv->
GetValue(
"WebGui.FirefoxInteractive", 
"$rootetcdir/runfirefox.sh $cleanup_profile $prog -no-remote $profile $geometry -url \'$url\' &");
 
 
  593   exec = std::regex_replace(exec, std::regex(
"\\$geometry"), 
geometry);
 
 
  603   if (exec.find(
"$profile") == std::string::npos)
 
  635         user_js << 
"user_pref(\"datareporting.policy.dataSubmissionPolicyAcceptedVersion\", 2);" << std::endl;
 
  636         user_js << 
"user_pref(\"datareporting.policy.dataSubmissionPolicyNotifiedTime\", \"1635760572813\");" << std::endl;
 
  639         user_js << 
"user_pref(\"browser.tabs.closeWindowWithLastTab\", true);" << std::endl;
 
  640         user_js << 
"user_pref(\"dom.allow_scripts_to_close_windows\", true);" << std::endl;
 
  641         user_js << 
"user_pref(\"browser.sessionstore.resume_from_crash\", false);" << std::endl;
 
  645            user_js << 
"user_pref(\"browser.dom.window.dump.enabled\", true);" << std::endl;
 
  648            user_js << 
"user_pref(\"datareporting.policy.firstRunURL\", \"\");" << std::endl;
 
  650            user_js << 
"user_pref(\"toolkit.legacyUserProfileCustomizations.stylesheets\", true);" << std::endl;
 
  652            user_js << 
"user_pref(\"browser.tabs.inTitlebar\", 0);" << std::endl;
 
  656            times_json << 
"   \"created\": 1699968480952," << std::endl;
 
  657            times_json << 
"   \"firstUse\": null" << std::endl;
 
  660               std::ofstream 
style(
profile_dir + 
"/chrome/userChrome.css", std::ios::trunc);
 
  662               style << 
"#TabsToolbar { visibility: collapse; }" << std::endl;
 
  664               style << 
"#nav-bar, #urlbar-container, #searchbar { visibility: collapse !important; }" << std::endl;
 
  673   exec = std::regex_replace(exec, std::regex(
"\\$profile"), 
profile_arg);
 
  675   if (exec.find(
"$cleanup_profile") != std::string::npos) {
 
  676      if (rmdir.empty()) rmdir = 
"<dummy>";
 
  677      exec = std::regex_replace(exec, std::regex(
"\\$cleanup_profile"), rmdir);
 
 
  699      if (
qt6 && 
qt6->IsActive())
 
  704      if (
qt5 && 
qt5->IsActive())
 
  709      if (
cef && 
cef->IsActive())
 
 
  726   std::unique_ptr<RWebDisplayHandle> handle;
 
  731   auto try_creator = [&](std::unique_ptr<Creator> &creator) {
 
  732      if (!creator || !creator->IsActive())
 
  734      handle = creator->Display(args);
 
  735      return handle ? 
true : 
false;
 
  801      std::unique_ptr<Creator> creator = std::make_unique<BrowserCreator>(
false, args.
GetCustomExec());
 
 
  845      if (
h1 && 
h1->IsActive()) {
 
  851         auto &h2 = 
FindCreator(
"firefox", 
"FirefoxCreator");
 
  852         if (h2 && h2->IsActive()) {
 
  861         if (h3 && h3->IsActive()) {
 
  872      return h1 && 
h1->IsActive();
 
  876      auto &h2 = 
FindCreator(
"firefox", 
"FirefoxCreator");
 
  877      return h2 && h2->IsActive();
 
  883      return h3 && h3->IsActive();
 
 
  917   auto EndsWith = [&
fname](
const std::string &
suffix) {
 
  923   std::vector<std::string> 
fnames;
 
  925   if (!EndsWith(
".pdf")) {
 
  935      for (
unsigned n = 0; 
n < 
jsons.size(); 
n++) {
 
  945   if (EndsWith(
".json")) {
 
  946      for (
unsigned n = 0; 
n < 
jsons.size(); ++
n) {
 
  975   if (EndsWith(
".pdf"))
 
  977   else if (EndsWith(
"shot.png") && (
jsons.size() == 1))
 
  979   else if (EndsWith(
".svg"))
 
  981   else if (EndsWith(
".png"))
 
  983   else if (EndsWith(
".jpg") || EndsWith(
".jpeg"))
 
  985   else if (EndsWith(
".webp"))
 
 1050      fputs(
"placeholder", df);
 
 1094         std::ofstream ofs(
html_name.Data(), std::ofstream::out);
 
 1125      if (EndsWith(
".pdf"))
 
 1165      auto dumpcont = handle->GetContent();
 
 1181         std::string::size_type 
p = 0;
 
 1187            std::ofstream ofs(
fn);
 
 1188            if ((
p1 != std::string::npos) && (
p2 != std::string::npos) && (
p1 < 
p2)) {
 
 1190               ::Info(
"ProduceImage", 
"SVG file %s size %d bytes has been created", 
fn.c_str(), (
int) (
p2-
p1+6));
 
 1199         std::string::size_type 
p = 0;
 
 1207            if ((
p1 != std::string::npos) && (
p2 != std::string::npos) && (
p1 < 
p2)) {
 
 1212               std::ofstream ofs(
fn, std::ios::binary);
 
 1215               ::Info(
"ProduceImage", 
"Image file %s size %d bytes has been created", 
fn.c_str(), (
int) 
binary.Length());
 
 1223   } 
else if (EndsWith(
".pdf")) {
 
 1224      ::Info(
"ProduceImage", 
"PDF file %s with %d pages has been created", 
fname.c_str(), (
int) 
jsons.size());
 
 
#define R__LOG_ERROR(...)
 
#define R__LOG_DEBUG(DEBUGLEVEL,...)
 
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
 
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
 
winID h TVirtualViewer3D TVirtualGLPainter p
 
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
 
R__EXTERN TRandom * gRandom
 
R__EXTERN TSystem * gSystem
 
const_iterator begin() const
 
const_iterator end() const
 
Specialized handle to hold information about running browser process Used to correctly cleanup all pr...
 
RWebBrowserHandle(const std::string &url, const std::string &tmpdir, const std::string &tmpfile, browser_process_id pid)
 
std::string fTmpDir
temporary directory to delete at the end
 
RWebBrowserHandle(const std::string &url, const std::string &tmpdir, const std::string &tmpfile, const std::string &dump)
 
std::string fTmpFile
temporary file to remove
 
~RWebBrowserHandle() override
 
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
 
std::string GetBrowserName() const
Returns configured browser name.
 
EBrowserKind GetBrowserKind() const
returns configured browser kind, see EBrowserKind for supported values
 
const std::string & GetRedirectOutput() const
get file name to which web browser output should be redirected
 
void SetStandalone(bool on=true)
Set standalone mode for running browser, default on When disabled, normal browser window (or just tab...
 
void SetBatchMode(bool on=true)
set batch mode
 
RWebDisplayArgs & SetSize(int w, int h)
set preferable web window width and height
 
RWebDisplayArgs & SetUrl(const std::string &url)
set window url
 
int GetWidth() const
returns preferable web window width
 
RWebDisplayArgs & SetPageContent(const std::string &cont)
set window url
 
int GetY() const
set preferable web window y position
 
std::string GetFullUrl() const
returns window url with append options
 
bool IsStandalone() const
Return true if browser should runs in standalone mode.
 
int GetHeight() const
returns preferable web window height
 
RWebDisplayArgs & SetBrowserKind(const std::string &kind)
Set browser kind as string argument.
 
std::string GetCustomExec() const
returns custom executable to start web browser
 
void SetExtraArgs(const std::string &args)
set extra command line arguments for starting web browser command
 
bool IsBatchMode() const
returns batch mode
 
bool IsHeadless() const
returns headless mode
 
@ kOn
web display enable, first try use embed displays like Qt or CEF, then native browsers and at the end ...
 
@ kFirefox
Mozilla Firefox browser.
 
@ kNative
either Chrome or Firefox - both support major functionality
 
@ kLocal
either CEF or Qt5 - both runs on local display without real http server
 
@ kServer
indicates that ROOT runs as server and just printouts window URL, browser should be started by the us...
 
@ kOff
disable web display, do not start any browser
 
@ kCEF
Chromium Embedded Framework - local display with CEF libs.
 
@ kQt5
Qt5 QWebEngine libraries - Chromium code packed in qt5.
 
@ kQt6
Qt6 QWebEngine libraries - Chromium code packed in qt6.
 
@ kCustom
custom web browser, execution string should be provided
 
@ kChrome
Google Chrome browser.
 
@ kEdge
Microsoft Edge browser (Windows only)
 
void SetRedirectOutput(const std::string &fname="")
specify file name to which web browser output should be redirected
 
void SetHeadless(bool on=true)
set headless mode
 
const std::string & GetExtraArgs() const
get extra command line arguments for starting web browser command
 
int GetX() const
set preferable web window x position
 
bool IsLocalDisplay() const
returns true if local display like CEF or Qt5 QWebEngine should be used
 
std::string fProg
browser executable
 
std::string fBatchExec
batch execute line
 
std::string fHeadlessExec
headless execute line
 
std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args) override
Display given URL in web browser.
 
std::string fExec
standard execute line
 
void TestProg(const std::string &nexttry, bool check_std_paths=false)
Check if browser executable exists and can be used.
 
BrowserCreator(bool custom=true, const std::string &exec="")
Class to handle starting of web-browsers like Chrome or Firefox.
 
ChromeCreator(bool is_edge=false)
Constructor.
 
void ProcessGeometry(std::string &, const RWebDisplayArgs &) override
Replace $geometry placeholder with geometry settings Also RWebDisplayArgs::GetExtraArgs() are appende...
 
std::string MakeProfile(std::string &exec, bool) override
Handle profile argument.
 
FirefoxCreator()
Constructor.
 
std::string MakeProfile(std::string &exec, bool batch) override
Create Firefox profile to run independent browser window.
 
void ProcessGeometry(std::string &, const RWebDisplayArgs &) override
Process window geometry for Firefox.
 
Handle of created web-based display Depending from type of web display, holds handle of started brows...
 
static std::map< std::string, std::unique_ptr< Creator > > & GetMap()
Static holder of registered creators of web displays.
 
static bool CheckIfCanProduceImages(RWebDisplayArgs &args)
Checks if configured browser can be used for image production.
 
static bool ProduceImages(const std::string &fname, const std::vector< std::string > &jsons, const std::vector< int > &widths, const std::vector< int > &heights, const char *batch_file=nullptr)
Produce image file(s) using JSON data as source Invokes JSROOT drawing functionality in headless brow...
 
void SetContent(const std::string &cont)
set content
 
static bool ProduceImage(const std::string &fname, const std::string &json, int width=800, int height=600, const char *batch_file=nullptr)
Produce image file using JSON data as source Invokes JSROOT drawing functionality in headless browser...
 
static bool CanProduceImages(const std::string &browser="")
Returns true if image production for specified browser kind is supported If browser not specified - u...
 
static bool NeedHttpServer(const RWebDisplayArgs &args)
Check if http server required for display.
 
static bool DisplayUrl(const std::string &url)
Display provided url in configured web browser.
 
static std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args)
Create web display.
 
static std::unique_ptr< Creator > & FindCreator(const std::string &name, const std::string &libname="")
Search for specific browser creator If not found, try to add one.
 
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
 
static TString ToJSON(const T *obj, Int_t compact=0, const char *member_name=nullptr)
 
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
 
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
 
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
 
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
 
static const TString & GetEtcDir()
Get the sysconfig directory in the installation. Static utility function.
 
static const TString & GetDataDir()
Get the data directory in the installation. Static utility function.
 
virtual void SetSeed(ULong_t seed=0)
Set the random generator seed.
 
virtual UInt_t Integer(UInt_t imax)
Returns a random integer uniformly distributed on the interval [ 0, imax-1 ].
 
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
 
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
 
virtual FILE * TempFileName(TString &base, const char *dir=nullptr, const char *suffix=nullptr)
Create a secure temporary file by appending a unique 6 letter string to base.
 
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
 
virtual const char * Getenv(const char *env)
Get environment variable.
 
virtual int mkdir(const char *name, Bool_t recursive=kFALSE)
Make a file system directory.
 
virtual Int_t Exec(const char *shellcmd)
Execute a command.
 
virtual int Load(const char *module, const char *entry="", Bool_t system=kFALSE)
Load a shared library.
 
virtual const char * PrependPathName(const char *dir, TString &name)
Concatenate a directory and a file name.
 
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
 
virtual std::string GetHomeDirectory(const char *userName=nullptr) const
Return the user's home directory.
 
virtual const char * UnixPathName(const char *unixpathname)
Convert from a local pathname to a Unix pathname.
 
virtual int Rename(const char *from, const char *to)
Rename a file.
 
virtual TString GetFromPipe(const char *command)
Execute command and return output in TString.
 
virtual Bool_t IsAbsoluteFileName(const char *dir)
Return true if dir is an absolute pathname.
 
virtual const char * WorkingDirectory()
Return working directory.
 
virtual int Unlink(const char *name)
Unlink, i.e.
 
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
 
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
 
ROOT::Experimental::RLogChannel & WebGUILog()
Log channel for WebGUI diagnostics.