Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
rootqt5.cpp
Go to the documentation of this file.
1// Author: Sergey Linev <S.Linev@gsi.de>
2// Date: 2017-06-29
3// Warning: This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback is welcome!
4
5/*************************************************************************
6 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
7 * All rights reserved. *
8 * *
9 * For the licensing terms see $ROOTSYS/LICENSE. *
10 * For the list of contributors see $ROOTSYS/README/CREDITS. *
11 *************************************************************************/
12
13#include <QApplication>
14#include <QWebEngineView>
15#include <qtwebengineglobal.h>
16#include <QWebEngineDownloadItem>
17
18#include <QThread>
19#include <QWebEngineSettings>
20#include <QWebEngineProfile>
21#include <QtGlobal>
22
23#if QT_VERSION >= 0x050C00
24#include <QWebEngineUrlScheme>
25#endif
26
27#include "TROOT.h"
28#include "TApplication.h"
29#include "TTimer.h"
30#include "TEnv.h"
31#include "TThread.h"
32#include "THttpServer.h"
33#include "TSystem.h"
34
35#include "rootwebview.h"
36#include "rootwebpage.h"
38
39#include <memory>
40
42#include <ROOT/RLogger.hxx>
43
44/** \class TQt5Timer
45\ingroup qt5webdisplay
46*/
47
48class TQt5Timer : public TTimer {
49public:
50 TQt5Timer(Long_t milliSec, Bool_t mode) : TTimer(milliSec, mode) {}
51
52 /// timeout handler
53 /// used to process all qt5 events in main ROOT thread
54 void Timeout() override
55 {
56 QApplication::sendPostedEvents();
57 QApplication::processEvents();
58 }
59};
60
61namespace ROOT {
62namespace Experimental {
63
64/** \class RQt5WebDisplayHandle
65\ingroup qt5webdisplay
66*/
67
69protected:
70
71 RootWebView *fView{nullptr}; ///< pointer on widget, need to release when handle is destroyed
72
73 class Qt5Creator : public Creator {
74 int fCounter{0}; ///< counter used to number handlers
75 QApplication *qapp{nullptr}; ///< created QApplication
76 int qargc{1}; ///< arg counter
77 char *qargv[2]; ///< arg values
78 std::unique_ptr<TQt5Timer> fTimer; ///< timer to process ROOT events
79 std::unique_ptr<RootUrlSchemeHandler> fHandler; ///< specialized handler
80 public:
81
82 Qt5Creator() = default;
83
84 virtual ~Qt5Creator()
85 {
86 /** Code executed during exit and sometime crashes.
87 * Disable it, while not clear if defaultProfile can be still used - seems to be not */
88 // if (fHandler)
89 // QWebEngineProfile::defaultProfile()->removeUrlSchemeHandler(fHandler.get());
90
91 // do not try to destroy objects during exit
92 fHandler.release();
93 fTimer.release();
94 }
95
96 std::unique_ptr<RWebDisplayHandle> Display(const RWebDisplayArgs &args) override
97 {
98 if (!qapp && !QApplication::instance()) {
99
100 if (!gApplication) {
101 R__LOG_ERROR(QtWebDisplayLog()) << "Not found gApplication to create QApplication";
102 return nullptr;
103 }
104
105 // initialize web engine only before creating QApplication
106 QtWebEngine::initialize();
107
108 #if QT_VERSION >= 0x050C00
109 QWebEngineUrlScheme scheme("rootscheme");
110 scheme.setSyntax(QWebEngineUrlScheme::Syntax::HostAndPort);
111 scheme.setDefaultPort(2345);
112 scheme.setFlags(QWebEngineUrlScheme::SecureScheme);
113 QWebEngineUrlScheme::registerScheme(scheme);
114 #endif
115
116 qargv[0] = gApplication->Argv(0);
117 qargv[1] = nullptr;
118
119 qapp = new QApplication(qargc, qargv);
120 }
121
122 // create timer to process Qt events from inside ROOT process events
123 // very much improve performance, even when Qt even loop runs by QApplication normally
124 if (!fTimer && !args.IsHeadless()) {
125 Int_t interval = gEnv->GetValue("WebGui.Qt5Timer", 1);
126 if (interval > 0) {
127 fTimer = std::make_unique<TQt5Timer>(interval, kTRUE);
128 fTimer->TurnOn();
129 }
130 }
131
132 QString fullurl = QString(args.GetFullUrl().c_str());
133
134 // if no server provided - normal HTTP will be allowed to use
135 if (args.GetHttpServer()) {
136 if (!fHandler) {
137 fHandler = std::make_unique<RootUrlSchemeHandler>();
138 QWebEngineProfile::defaultProfile()->installUrlSchemeHandler("rootscheme", fHandler.get());
139 QWebEngineProfile::defaultProfile()->connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
140 [](QWebEngineDownloadItem *item) { item->accept(); });
141 }
142
143 fullurl = fHandler->MakeFullUrl(args.GetHttpServer(), fullurl);
144 }
145
146 QWidget *qparent = static_cast<QWidget *>(args.GetDriverData());
147
148 auto handle = std::make_unique<RQt5WebDisplayHandle>(fullurl.toLatin1().constData());
149
150 RootWebView *view = new RootWebView(qparent, args.GetWidth(), args.GetHeight(), args.GetX(), args.GetY());
151
152 if (!args.IsHeadless()) {
153 if (!qparent) handle->fView = view;
154 view->load(QUrl(fullurl));
155 view->show();
156 } else {
157
158 int tmout_sec = 30, expired = tmout_sec * 100;
159 bool load_finished = false, did_try = false, get_content = false, is_error = false;
160 std::string content, pdffile;
161
162 if (!args.GetExtraArgs().empty() && (args.GetExtraArgs().find("--print-to-pdf=")==0))
163 pdffile = args.GetExtraArgs().substr(15);
164
165 QObject::connect(view, &RootWebView::loadFinished, [&load_finished, &is_error](bool is_ok) {
166 load_finished = true; is_error = !is_ok;
167 });
168
169 #if QT_VERSION >= 0x050900
170 if (!pdffile.empty())
171 QObject::connect(view->page(), &RootWebPage::pdfPrintingFinished, [&expired, &is_error](const QString &, bool is_ok) {
172 expired = 0; is_error = !is_ok;
173 });
174 #endif
175
176 const std::string &page_content = args.GetPageContent();
177 if (page_content.empty())
178 view->load(QUrl(fullurl));
179 else
180 view->setHtml(QString::fromUtf8(page_content.data(), page_content.size()), QUrl("file:///batch_page.html"));
181
182 // loop here until content is configured
183 while ((--expired > 0) && !get_content && !is_error) {
184
185 if (gSystem->ProcessEvents()) break; // interrupted, has to return
186
187 QApplication::sendPostedEvents();
188 QApplication::processEvents();
189
190 if (load_finished && !did_try) {
191 did_try = true;
192
193 if (pdffile.empty()) {
194 view->page()->toHtml([&get_content, &content](const QString& res) {
195 get_content = true;
196 content = res.toLatin1().constData();
197 });
198 } else {
199 view->page()->printToPdf(QString::fromUtf8(pdffile.data(), pdffile.size()));
200 #if QT_VERSION < 0x050900
201 expired = 5; // no signal will be produced, just wait short time and break loop
202 #endif
203 }
204 }
205
206 gSystem->Sleep(10); // only 10 ms sleep
207 }
208
209 if(get_content)
210 handle->SetContent(content);
211
212 // delete view and process events
213 delete view;
214
215 for (expired=0;expired<100;++expired) {
216 QApplication::sendPostedEvents();
217 QApplication::processEvents();
218 }
219
220 }
221
222 return handle;
223 }
224
225 };
226
227public:
228 RQt5WebDisplayHandle(const std::string &url) : RWebDisplayHandle(url) {}
229
231 {
232 // now view can be safely destroyed
233 if (fView) {
234 delete fView;
235 fView = nullptr;
236 }
237 }
238
239 static void AddCreator()
240 {
241 auto &entry = FindCreator("qt5");
242 if (!entry)
243 GetMap().emplace("qt5", std::make_unique<Qt5Creator>());
244 }
245
246};
247
251
252}
253}
#define R__LOG_ERROR(...)
Definition RLogger.hxx:362
long Long_t
Definition RtypesCore.h:54
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
R__EXTERN TApplication * gApplication
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
Option_t Option_t TPoint TPoint const char mode
R__EXTERN TSystem * gSystem
Definition TSystem.h:560
QApplication * qapp
created QApplication
Definition rootqt5.cpp:75
std::unique_ptr< TQt5Timer > fTimer
timer to process ROOT events
Definition rootqt5.cpp:78
int fCounter
counter used to number handlers
Definition rootqt5.cpp:74
std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args) override
Definition rootqt5.cpp:96
std::unique_ptr< RootUrlSchemeHandler > fHandler
specialized handler
Definition rootqt5.cpp:79
RootWebView * fView
pointer on widget, need to release when handle is destroyed
Definition rootqt5.cpp:71
RQt5WebDisplayHandle(const std::string &url)
Definition rootqt5.cpp:228
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
bool IsHeadless() const
returns headless mode
int GetHeight() const
returns preferable web window height
const std::string & GetExtraArgs() const
get extra command line arguments for starting web browser command
std::string GetFullUrl() const
returns window url with append options
THttpServer * GetHttpServer() const
returns http server instance, used for window display
const std::string & GetPageContent() const
returns window url
void * GetDriverData() const
[internal] returns web-driver data, used to start window
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
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 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.
char ** Argv() const
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:491
TQt5Timer(Long_t milliSec, Bool_t mode)
Definition rootqt5.cpp:50
void Timeout() override
timeout handler used to process all qt5 events in main ROOT thread
Definition rootqt5.cpp:54
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:440
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:419
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
struct ROOT::Experimental::RQt5CreatorReg newRQt5CreatorReg
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
ROOT::Experimental::RLogChannel & QtWebDisplayLog()