21#include "RConfigure.h"
39using namespace std::string_literals;
46 static std::map<std::string, std::unique_ptr<ROOT::Experimental::RWebDisplayHandle::Creator>> sMap;
59 auto search =
m.find(
name);
60 if (search ==
m.end()) {
62 if (libname ==
"ChromeCreator") {
63 m.emplace(
name, std::make_unique<ChromeCreator>());
64 }
else if (libname ==
"FirefoxCreator") {
65 m.emplace(
name, std::make_unique<FirefoxCreator>());
66 }
else if (libname ==
"BrowserCreator") {
67 m.emplace(
name, std::make_unique<BrowserCreator>(
false));
68 }
else if (!libname.empty()) {
72 search =
m.find(
name);
75 if (search !=
m.end())
76 return search->second;
78 static std::unique_ptr<ROOT::Experimental::RWebDisplayHandle::Creator>
dummy;
83namespace Experimental {
92 typedef int browser_process_id;
94 typedef pid_t browser_process_id;
98 browser_process_id fPid;
101 RWebBrowserHandle(
const std::string &url,
const std::string &tmpdir) : RWebDisplayHandle(url), fTmpDir(tmpdir) {}
103 RWebBrowserHandle(
const std::string &url,
const std::string &tmpdir, browser_process_id pid)
104 : RWebDisplayHandle(url), fTmpDir(tmpdir), fHasPid(true), fPid(pid)
108 virtual ~RWebBrowserHandle()
112 gSystem->
Exec((
"taskkill /F /PID "s + std::to_string(fPid)).c_str());
113 std::string rmdir =
"rmdir /S /Q ";
117 std::string rmdir =
"rm -rf ";
119 if (!fTmpDir.empty())
135 if (exec.find(
"$url") == std::string::npos) {
138 fExec = exec +
" $url";
140 fExec = exec +
" $url &";
144 auto pos = exec.find(
" ");
145 if (pos != std::string::npos)
146 fProg = exec.substr(0, pos);
149 fExec =
"open \'$url\'";
151 fExec =
"start $url";
153 fExec =
"xdg-open \'$url\' &";
162 if (nexttry.empty() || !fProg.empty())
167 fProg = std::regex_replace(nexttry, std::regex(
"%20"),
" ");
174 if (!check_std_paths)
179 auto pos = ProgramFiles.find(
" (x86)");
180 if (pos != std::string::npos)
181 ProgramFiles.erase(pos, 6);
182 std::string ProgramFilesx86 =
gSystem->
Getenv(
"ProgramFiles(x86)");
184 if (!ProgramFiles.empty())
185 TestProg(ProgramFiles + nexttry,
false);
186 if (!ProgramFilesx86.empty())
187 TestProg(ProgramFilesx86 + nexttry,
false);
194std::unique_ptr<ROOT::Experimental::RWebDisplayHandle>
210 exec =
"$prog $url &";
216 std::string swidth = std::to_string(args.
GetWidth() > 0 ? args.
GetWidth() : 800),
218 sposx = std::to_string(args.
GetX() >= 0 ? args.
GetX() : 0),
219 sposy = std::to_string(args.
GetY() >= 0 ? args.
GetY() : 0);
221 ProcessGeometry(exec, args);
223 std::string rmdir = MakeProfile(exec, args.
IsHeadless());
225 exec = std::regex_replace(exec, std::regex(
"\\$url"), url);
226 exec = std::regex_replace(exec, std::regex(
"\\$width"), swidth);
227 exec = std::regex_replace(exec, std::regex(
"\\$height"), sheight);
228 exec = std::regex_replace(exec, std::regex(
"\\$posx"), sposx);
229 exec = std::regex_replace(exec, std::regex(
"\\$posy"), sposy);
231 if (exec.compare(0,5,
"fork:") == 0) {
233 R__ERROR_HERE(
"WebDisplay") <<
"Fork instruction without executable";
242 if (!fargs || (fargs->GetLast()<=0)) {
247 std::vector<char *> argv;
248 argv.push_back((
char *) fProg.c_str());
249 for (
Int_t n = 0;
n <= fargs->GetLast(); ++
n)
250 argv.push_back((
char *)fargs->At(
n)->GetName());
251 argv.push_back(
nullptr);
253 R__DEBUG_HERE(
"WebDisplay") <<
"Show web window in browser with posix_spawn:\n" << fProg <<
" " << exec;
256 int status = posix_spawn(&pid, argv[0],
nullptr,
nullptr, argv.data(),
nullptr);
264 return std::make_unique<RWebBrowserHandle>(url, rmdir, pid);
272 if (!fProg.empty()) {
273 exec =
"wmic process call create \""s + fProg + exec;
275 R__ERROR_HERE(
"WebDisplay") <<
"No Web browser found in Program Files!";
278 exec.append(
"\" | find \"ProcessId\" ");
280 std::stringstream ss(process_id);
281 ss >> tmp >>
c >> pid;
284 return std::make_unique<RWebBrowserHandle>(url, rmdir, pid);
291 std::vector<char *> argv;
292 std::string firstarg = fProg;
293 auto slashpos = firstarg.rfind(
"\\");
294 if (slashpos != std::string::npos)
295 firstarg.erase(0, slashpos + 1);
296 slashpos = firstarg.rfind(
"/");
297 if (slashpos != std::string::npos)
298 firstarg.erase(0, slashpos + 1);
299 argv.push_back((
char *)firstarg.c_str());
302 for (
Int_t n = 1;
n <= fargs->GetLast(); ++
n)
303 argv.push_back((
char *)fargs->At(
n)->GetName());
304 argv.push_back(
nullptr);
306 R__DEBUG_HERE(
"WebDisplay") <<
"Showing web window in " << fProg <<
" with:\n" << exec;
308 _spawnv(_P_NOWAIT, fProg.c_str(), argv.data());
313 std::string prog = std::regex_replace(fProg, std::regex(
" "),
"\\ ");
315 std::string prog = fProg;
318 exec = std::regex_replace(exec, std::regex(
"\\$prog"), prog);
320 R__DEBUG_HERE(
"WebDisplay") <<
"Showing web window in browser with:\n" << exec;
326 return std::make_unique<RWebBrowserHandle>(url, rmdir);
337 TestProg(
"\\Google\\Chrome\\Application\\chrome.exe",
true);
340 TestProg(
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome");
344 TestProg(
"/usr/bin/chromium-browser");
345 TestProg(
"/usr/bin/chrome-browser");
350 fExec =
gEnv->
GetValue(
"WebGui.ChromeInteractive",
"$prog $geometry --no-first-run --app=$url");
353 fExec =
gEnv->
GetValue(
"WebGui.ChromeInteractive",
"$prog $geometry --no-first-run --incognito --app=\'$url\' &");
359 std::string size, pos;
361 size =
"--window-size="s + std::to_string(args.
GetWidth() > 0 ? args.
GetWidth() : 800) +
","s +
363 if ((args.
GetX() >= 0) || (args.
GetY() >= 0))
364 pos =
" --window-position="s + std::to_string(args.
GetX() >= 0 ? args.
GetX() : 0) +
","s +
365 std::to_string(args.
GetY() >= 0 ? args.
GetY() : 0);
367 exec = std::regex_replace(exec, std::regex(
"\\$geometry"), size + pos);
376 std::string rmdir, profile_arg;
378 if (exec.find(
"$profile") == std::string::npos)
381 const char *chrome_profile =
gEnv->
GetValue(
"WebGui.ChromeProfile",
"");
382 if (chrome_profile && *chrome_profile) {
383 profile_arg = chrome_profile;
389 exec = std::regex_replace(exec, std::regex(
"\\$profile"), profile_arg);
403 TestProg(
"\\Mozilla Firefox\\firefox.exe",
true);
406 TestProg(
"/Applications/Firefox.app/Contents/MacOS/firefox");
416 fExec =
gEnv->
GetValue(
"WebGui.FirefoxInteractive",
"$prog -no-remote $profile $url");
418 fBatchExec =
gEnv->
GetValue(
"WebGui.FirefoxBatch",
"fork:--headless --private-window --no-remote $profile $url");
419 fExec =
gEnv->
GetValue(
"WebGui.FirefoxInteractive",
"$prog --private-window \'$url\' &");
428 std::string rmdir, profile_arg;
430 if (exec.find(
"$profile") == std::string::npos)
433 const char *ff_profile =
gEnv->
GetValue(
"WebGui.FirefoxProfile",
"");
434 const char *ff_profilepath =
gEnv->
GetValue(
"WebGui.FirefoxProfilePath",
"");
436 if (ff_profile && *ff_profile) {
437 profile_arg =
"-P "s + ff_profile;
438 }
else if (ff_profilepath && *ff_profilepath) {
439 profile_arg =
"-profile "s + ff_profilepath;
440 }
else if ((ff_randomprofile > 0) || (batch_mode && (ff_randomprofile >= 0))) {
443 std::string rnd_profile =
"root_ff_profile_"s + std::to_string(
gRandom->
Integer(0x100000));
446 profile_arg =
"-profile "s + profile_dir;
451 R__ERROR_HERE(
"WebDisplay") <<
"Cannot create Firefox profile directory " << profile_dir;
455 exec = std::regex_replace(exec, std::regex(
"\\$profile"), profile_arg);
469 std::unique_ptr<RWebDisplayHandle> handle;
471 auto try_creator = [&](std::unique_ptr<Creator> &creator) {
472 if (!creator || !creator->IsActive())
474 handle = creator->Display(args);
475 return handle ? true :
false;
479 if (try_creator(
FindCreator(
"cef",
"libROOTCefDisplay")))
484 if (try_creator(
FindCreator(
"qt5",
"libROOTQt5WebDisplay")))
489 R__ERROR_HERE(
"WebDisplay") <<
"Neither Qt5 nor CEF libraries were found to provide local display";
494 if (try_creator(
FindCreator(
"chrome",
"ChromeCreator")))
499 if (try_creator(
FindCreator(
"firefox",
"FirefoxCreator")))
504 R__ERROR_HERE(
"WebDisplay") <<
"Neither Chrome nor Firefox browser cannot be started to provide display";
509 std::unique_ptr<Creator> creator = std::make_unique<BrowserCreator>(
false, args.
GetCustomExec());
510 try_creator(creator);
512 try_creator(
FindCreator(
"browser",
"BrowserCreator"));
#define R__ERROR_HERE(GROUP)
#define R__DEBUG_HERE(GROUP)
static RooMathCoreReg dummy
R__EXTERN TRandom * gRandom
R__EXTERN TSystem * gSystem
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
std::string GetCustomExec() const
returns custom executable to start web browser
bool IsHeadless() const
returns headless mode
RWebDisplayArgs & SetUrl(const std::string &url)
set window url
int GetHeight() const
returns preferable web window height
std::string GetFullUrl() const
returns window url with append options
EBrowserKind GetBrowserKind() const
returns configured browser kind, see EBrowserKind for supported values
void SetStandalone(bool on=true)
Set standalone mode for running browser, default on When disabled, normal browser window (or just tab...
bool IsStandalone() const
Return true if browser should runs in standalone mode.
bool IsLocalDisplay() const
returns true if local display like CEF or Qt5 QWebEngine should be used
@ kFirefox
Mozilla Firefox browser.
@ kCEF
Chromium Embedded Framework - local display with CEF libs.
@ kChrome
Google Chrome browser.
@ kCustom
custom web browser, execution string should be provided
@ kNative
either Chrome or Firefox - both support major functionality
@ kLocal
either CEF or Qt5 - both runs on local display without real http server
@ kQt5
QWebEngine libraries - Chrome code packed in qt5.
int GetY() const
set preferable web window y position
int GetX() const
set preferable web window x position
int GetWidth() const
returns preferable web window width
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.
std::string fBatchExec
batch execute line
BrowserCreator(bool custom=true, const std::string &exec="")
Class to handle starting of web-browsers like Chrome or Firefox.
std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args) override
Display given URL in web browser.
ChromeCreator()
Constructor.
void ProcessGeometry(std::string &, const RWebDisplayArgs &args) override
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.
static bool DisplayUrl(const std::string &url)
Display provided url in configured web browser.
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 std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args)
Create web display.
static std::map< std::string, std::unique_ptr< Creator > > & GetMap()
!< URL used to launch display
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
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.
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 Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
virtual TString GetFromPipe(const char *command)
Execute command and return output in TString.
virtual const char * TempDirectory() const
Return a user configured or systemwide directory to create temporary files in.
static constexpr double s