Logo ROOT  
Reference Guide
rootqt6.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 <qtwebenginecoreglobal.h>
16#include <QWebEngineDownloadRequest>
17// #include <qtwebenginequickglobal.h>
18
19#include <QThread>
20#include <QWebEngineSettings>
21#include <QWebEngineProfile>
22#include <QtGlobal>
23
24#include <QWebEngineUrlScheme>
25
26#include "TROOT.h"
27#include "TApplication.h"
28#include "TTimer.h"
29#include "TEnv.h"
30#include "TThread.h"
31#include "THttpServer.h"
32#include "TSystem.h"
33
34#include "../qt5webdisplay/rootwebview.h"
35#include "../qt5webdisplay/rootwebpage.h"
36#include "../qt5webdisplay/rooturlschemehandler.h"
37
38#include <memory>
39
41#include <ROOT/RLogger.hxx>
42
43/** \class TQt6Timer
44\ingroup qt6webdisplay
45*/
46
47class TQt6Timer : public TTimer {
48public:
49 TQt6Timer(Long_t milliSec, Bool_t mode) : TTimer(milliSec, mode) {}
50
51 /// timeout handler
52 /// used to process all qt6 events in main ROOT thread
53 void Timeout() override
54 {
55 QApplication::sendPostedEvents();
56 QApplication::processEvents();
57 }
58};
59
60namespace ROOT {
61namespace Experimental {
62
63/** \class RQt6WebDisplayHandle
64\ingroup qt6webdisplay
65*/
66
68protected:
69
70 RootWebView *fView{nullptr}; ///< pointer on widget, need to release when handle is destroyed
71
72 class Qt6Creator : public Creator {
73 int fCounter{0}; ///< counter used to number handlers
74 QApplication *qapp{nullptr}; ///< created QApplication
75 int qargc{1}; ///< arg counter
76 char *qargv[2]; ///< arg values
77 std::unique_ptr<TQt6Timer> fTimer; ///< timer to process ROOT events
78 std::unique_ptr<RootUrlSchemeHandler> fHandler; ///< specialized handler
79 public:
80
81 Qt6Creator() = default;
82
83 virtual ~Qt6Creator()
84 {
85 /** Code executed during exit and sometime crashes.
86 * Disable it, while not clear if defaultProfile can be still used - seems to be not */
87 // if (fHandler)
88 // QWebEngineProfile::defaultProfile()->removeUrlSchemeHandler(fHandler.get());
89
90 R__LOG_DEBUG(0, QtWebDisplayLog()) << "Deleting Qt6Creator";
91 }
92
93 std::unique_ptr<RWebDisplayHandle> Display(const RWebDisplayArgs &args) override
94 {
95 if (!qapp && !QApplication::instance()) {
96
97 if (!gApplication) {
98 R__LOG_ERROR(QtWebDisplayLog()) << "Not found gApplication to create QApplication";
99 return nullptr;
100 }
101
102 // initialize web engine only before creating QApplication
103 // QtWebEngineQuick::initialize();
104
105 QWebEngineUrlScheme scheme("rootscheme");
106 scheme.setSyntax(QWebEngineUrlScheme::Syntax::HostAndPort);
107 scheme.setDefaultPort(2345);
108 scheme.setFlags(QWebEngineUrlScheme::SecureScheme);
109 QWebEngineUrlScheme::registerScheme(scheme);
110
111 qargv[0] = gApplication->Argv(0);
112 qargv[1] = nullptr;
113
114 qapp = new QApplication(qargc, qargv);
115 }
116
117 // create timer to process Qt events from inside ROOT process events
118 // very much improve performance, even when Qt even loop runs by QApplication normally
119 if (!fTimer && !args.IsHeadless()) {
120 Int_t interval = gEnv->GetValue("WebGui.Qt5Timer", 1);
121 if (interval > 0) {
122 fTimer = std::make_unique<TQt6Timer>(interval, kTRUE);
123 fTimer->TurnOn();
124 }
125 }
126
127 QString fullurl = QString(args.GetFullUrl().c_str());
128
129 // if no server provided - normal HTTP will be allowed to use
130 if (args.GetHttpServer()) {
131 if (!fHandler) {
132 fHandler = std::make_unique<RootUrlSchemeHandler>();
133 QWebEngineProfile::defaultProfile()->installUrlSchemeHandler("rootscheme", fHandler.get());
134 QWebEngineProfile::defaultProfile()->connect(QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
135 [](QWebEngineDownloadRequest *request) { request->accept(); });
136 }
137
138 fullurl = fHandler->MakeFullUrl(args.GetHttpServer(), fullurl);
139 }
140
141 QWidget *qparent = static_cast<QWidget *>(args.GetDriverData());
142
143 auto handle = std::make_unique<RQt6WebDisplayHandle>(fullurl.toLatin1().constData());
144
145 RootWebView *view = new RootWebView(qparent, args.GetWidth(), args.GetHeight(), args.GetX(), args.GetY());
146
147 if (!args.IsHeadless()) {
148 if (!qparent) handle->fView = view;
149 view->load(QUrl(fullurl));
150 view->show();
151 } else {
152
153 int tmout_sec = 30, expired = tmout_sec * 100;
154 bool load_finished = false, did_try = false, get_content = false, is_error = false;
155 std::string content, pdffile;
156
157 if (!args.GetExtraArgs().empty() && (args.GetExtraArgs().find("--print-to-pdf=")==0))
158 pdffile = args.GetExtraArgs().substr(15);
159
160 QObject::connect(view, &RootWebView::loadFinished, [&load_finished, &is_error](bool is_ok) {
161 load_finished = true; is_error = !is_ok;
162 });
163
164 if (!pdffile.empty())
165 QObject::connect(view->page(), &RootWebPage::pdfPrintingFinished, [&expired, &is_error](const QString &, bool is_ok) {
166 expired = 0; is_error = !is_ok;
167 });
168
169 const std::string &page_content = args.GetPageContent();
170 if (page_content.empty())
171 view->load(QUrl(fullurl));
172 else
173 view->setHtml(QString::fromUtf8(page_content.data(), page_content.size()), QUrl("file:///batch_page.html"));
174
175 // loop here until content is configured
176 while ((--expired > 0) && !get_content && !is_error) {
177
178 if (gSystem->ProcessEvents()) break; // interrupted, has to return
179
180 QApplication::sendPostedEvents();
181 QApplication::processEvents();
182
183 if (load_finished && !did_try) {
184 did_try = true;
185
186 if (pdffile.empty()) {
187 view->page()->toHtml([&get_content, &content](const QString& res) {
188 get_content = true;
189 content = res.toLatin1().constData();
190 });
191 } else {
192 view->page()->printToPdf(QString::fromUtf8(pdffile.data(), pdffile.size()));
193 #if QT_VERSION < 0x050900
194 expired = 5; // no signal will be produced, just wait short time and break loop
195 #endif
196 }
197 }
198
199 gSystem->Sleep(10); // only 10 ms sleep
200 }
201
202 if(get_content)
203 handle->SetContent(content);
204
205 // delete view and process events
206 delete view;
207
208 for (expired=0;expired<100;++expired) {
209 QApplication::sendPostedEvents();
210 QApplication::processEvents();
211 }
212
213 }
214
215 return handle;
216 }
217
218 };
219
220public:
221 RQt6WebDisplayHandle(const std::string &url) : RWebDisplayHandle(url) {}
222
224 {
225 // now view can be safely destroyed
226 if (fView) {
227 delete fView;
228 fView = nullptr;
229 }
230 }
231
232 static void AddCreator()
233 {
234 auto &entry = FindCreator("qt6");
235 if (!entry)
236 GetMap().emplace("qt6", std::make_unique<Qt6Creator>());
237 }
238
239};
240
244
245}
246}
#define R__LOG_ERROR(...)
Definition: RLogger.hxx:362
#define R__LOG_DEBUG(DEBUGLEVEL,...)
Definition: RLogger.hxx:365
long Long_t
Definition: RtypesCore.h:54
const Bool_t kTRUE
Definition: RtypesCore.h:100
R__EXTERN TApplication * gApplication
Definition: TApplication.h:165
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: rootqt6.cpp:74
std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args) override
Definition: rootqt6.cpp:93
int fCounter
counter used to number handlers
Definition: rootqt6.cpp:73
std::unique_ptr< RootUrlSchemeHandler > fHandler
specialized handler
Definition: rootqt6.cpp:78
std::unique_ptr< TQt6Timer > fTimer
timer to process ROOT events
Definition: rootqt6.cpp:77
RQt6WebDisplayHandle(const std::string &url)
Definition: rootqt6.cpp:221
RootWebView * fView
pointer on widget, need to release when handle is destroyed
Definition: rootqt6.cpp:70
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
Definition: TApplication.h:136
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition: TEnv.cxx:491
TQt6Timer(Long_t milliSec, Bool_t mode)
Definition: rootqt6.cpp:49
void Timeout() override
timeout handler used to process all qt6 events in main ROOT thread
Definition: rootqt6.cpp:53
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::RQt6CreatorReg newRQt6CreatorReg
This file contains a specialised ROOT message handler to test for diagnostic in unit tests.
static Roo_reg_AGKInteg1D instance
ROOT::Experimental::RLogChannel & QtWebDisplayLog()
Definition: rootwebpage.cpp:20