diff --git a/BUILDING.md b/BUILDING.md index 3ab466e0..cbb68451 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,140 +1,125 @@ General ---------------------------------------------------------------------------------- If you can, you should use precompiled packages for your distribution. But if you cannot use them, or they are not available, please read this information before compiling. After your binary is successfully compiled, you need to copy bin/ folder from git to specific directory by your system you compiled for. On Linux, you can easily do it by running make install. If you are unsure where is the right place, you can check it directly from Falkon by clicking from Help Menu on Configuration Information, then in Path section. You may want to build Falkon with debugging symbols (for generating backtrace of crash) as easily as adding one line to src/defines.pri: CONFIG += debug Falkon requires Qt (>= 5.8) and QtWebEngine (at least version included in Qt 5.8) Microsoft Windows ---------------------------------------------------------------------------------- You need Microsoft Visual C++ Compiler, Qt Libraries 5.8 or higher and openssl libraries. in order to build Falkon. Linux / Unix ---------------------------------------------------------------------------------- You need to have Qt 5 (>= 5.8) with QtWebEngine. Next compulsory requirement is OpenSSL (libcrypto). xcb libraries are also required unless you specify NO_X11 build option. To build KWallet plugin, you need: - KF5 KWallet To build Gnome-Keyring plugin, you need - libgnome-keyring-dev installed For debug build, gdb is required by qmake. MAC OS X ---------------------------------------------------------------------------------- You need to have Xcode from the Apple App Store installed in Applications, [Command Line Tools for the same Xcode version](https://developer.apple.com/) may be included depending on the version, [Homebrew](http://brew.sh/), and `$ brew install openssl` for openssl. Next compulsory requirement is Qt 5 (>= 5.8) with QtWebEngine. After successful compilation, you need to build the application bundle. You will do it with following command: $ make bundle FreeBSD ---------------------------------------------------------------------------------- You may need to set few sysctls to get Falkon running with raster graphics system. For more informations, please see FAQ. Available Defines ---------------------------------------------------------------------------------- You can set define directly in file (src/defines.pri) or set environment variable by $ export NAME="value" General: - PORTABLE_BUILD Falkon won't write any data outside of path of execution. + PORTABLE_BUILD Falkon won't write any data outside of path of execution. It will also disable plugins by default. (disabled by default) example: $ export PORTABLE_BUILD="true" - - NONBLOCK_JS_DIALOGS Enable non-blocking JavaScript dialogs from alert() prompt() - and confirm() functions. They are shown inside page and are not - blocking application window. - However, due to synchronous API, there is a possible crash when - closing browser windows with opened dialogs. - If you can take this risk and/or make sure you aren't closing browser - with opened dialogs, you may enable this option. - These dialogs are much more beautiful than normal QDialogs. - (disabled by default) - - example: - $ export NONBLOCK_JS_DIALOGS="true" - - Windows specific defines: W7API Enable Windows 7 API support Requires linking against libraries from Microsoft Visual C++ Compiler 2010 (enabled by default) Linux / Unix specific defines: NO_X11 Disable all X11 calls. Enable this when building for Wayland-only. All X11 calls are guarded by runtime X11 platform check even without this option. example: $ export NO_X11="true" NO_SYSTEM_DATAPATH By default, Falkon is using /usr/share/falkon/ path for storing themes and translations. By setting this define, Falkon will use path of execution. (disabled by default) example: $ export NO_SYSTEM_DATAPATH="true" FALKON_PREFIX You can define different prefix. Falkon binary will then be moved to PREFIX/bin/, use PREFIX/share/falkon/ as datadir, PREFIX/share/applications for desktop launcher and PREFIX/share/pixmaps for icon. (default prefix is "/usr") example: $ export FALKON_PREFIX="/usr" SHARE_FOLDER You can define the path of the share folder, i.e. /usr/share Falkon will then use SHARE_FOLDER/falkon as datadir, SHARE_FOLDER/applications for desktop launcher and SHARE_FOLDER/pixmaps for the icon. By default it is not defined and files will be installed as described above. (default share folder is "/usr/share") example: $ export SHARE_FOLDER="/usr/share" DISABLE_DBUS Build without QtDBus module. Native desktop notifications will be disabled. example: $ export DISABLE_DBUS="true" diff --git a/CMakeLists.txt b/CMakeLists.txt index 19790b74..2e1cee5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,175 +1,171 @@ # CMake version required. This must be the very first line, because it sets default policies affecting everything else cmake_minimum_required(VERSION 3.1) # Project name and version project(Falkon VERSION 2.1.99) # Find ECM, with nice error handling in case of failure include(FeatureSummary) find_package(ECM 5.27.0 CONFIG) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/frameworks/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # Many includes from ECM, to get all the nice cmake functions and settings include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMAddAppIcon) include(ECMQtDeclareLoggingCategory) # Output dirs (like ECM 5.38 does) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") if (UNIX AND NOT APPLE) set(FALKON_INSTALL_PLUGINDIR "${KDE_INSTALL_PLUGINDIR}/falkon") else() set(FALKON_INSTALL_PLUGINDIR "${KDE_INSTALL_PLUGINDIR}") endif() if (IS_ABSOLUTE ${FALKON_INSTALL_PLUGINDIR}) add_definitions(-DPLUGIN_PATH=\"${FALKON_INSTALL_PLUGINDIR}\") else() add_definitions(-DPLUGIN_PATH=\"${CMAKE_INSTALL_PREFIX}/${FALKON_INSTALL_PLUGINDIR}\") endif() # Version (TODO: move to a generated header once qmake support is dropped, to avoid full recompilations when changing this add_definitions(-DFALKON_VERSION=\"${PROJECT_VERSION}\") # Defines that are always set add_definitions(-DQT_NO_URL_CAST_FROM_STRING -DQT_USE_QSTRINGBUILDER -DQT_NO_CAST_TO_ASCII) # Configurable options (TODO: move all defines to a generated header) option(NO_SYSTEM_DATAPATH "TODO" OFF) if (NO_SYSTEM_DATAPATH) add_definitions(-DNO_SYSTEM_DATAPATH) endif() option(NO_X11 "TODO" OFF) if (NO_X11) add_definitions(-DNO_X11) endif() option(PORTABLE_BUILD "TODO" OFF) if (PORTABLE_BUILD) add_definitions(-DPORTABLE_BUILD) endif() -option(NONBLOCK_JS_DIALOGS "TODO" OFF) -if (NONBLOCK_JS_DIALOGS) - add_definitions(-DNONBLOCK_JS_DIALOGS) -endif() option(DISABLE_DBUS "TODO" OFF) if (DISABLE_DBUS) add_definitions(-DDISABLE_DBUS) endif() option(DISABLE_UPDATES_CHECK "TODO" OFF) if (DISABLE_UPDATES_CHECK) add_definitions(-DDISABLE_UPDATES_CHECK) endif() # Note: the old qmake option DEBUG_BUILD is now -DCMAKE_BUILD_TYPE=Debug, and FALKON_PREFIX is now -DCMAKE_INSTALL_PREFIX # SHARE_FOLDER is now auto-detected. # Mandatory: Qt5 set(QT_MIN_VERSION "5.8.0") find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Widgets Network Sql QuickWidgets PrintSupport WebEngineWidgets WebChannel Test) if (NOT DISABLE_DBUS) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS DBus) endif() if (UNIX AND NOT APPLE AND NOT NO_X11) find_package(X11) if (X11_FOUND) add_definitions(-DQZ_WS_X11) endif() find_package(XCB COMPONENTS XCB) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS X11Extras) endif() if (WIN32) add_definitions(-DW7API) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS WinExtras) # taken from https://stackoverflow.com/a/40217291 macro(get_WIN32_WINNT version) if (CMAKE_SYSTEM_VERSION) set(ver ${CMAKE_SYSTEM_VERSION}) string(REGEX MATCH "^([0-9]+).([0-9])" ver ${ver}) string(REGEX MATCH "^([0-9]+)" verMajor ${ver}) # Check for Windows 10, b/c we'll need to convert to hex 'A'. if ("${verMajor}" MATCHES "10") set(verMajor "A") string(REGEX REPLACE "^([0-9]+)" ${verMajor} ver ${ver}) endif ("${verMajor}" MATCHES "10") # Remove all remaining '.' characters. string(REPLACE "." "" ver ${ver}) # Prepend each digit with a zero. string(REGEX REPLACE "([0-9A-Z])" "0\\1" ver ${ver}) set(${version} "0x${ver}") endif(CMAKE_SYSTEM_VERSION) endmacro(get_WIN32_WINNT) get_WIN32_WINNT(ver) add_definitions(-D_WIN32_WINNT=${ver}) endif() # Optional: GnomeKeyring find_package(PkgConfig) if (PKG_CONFIG_FOUND) option(BUILD_KEYRING "Gnome keyring password plugin" ON) if (BUILD_KEYRING) pkg_check_modules(GNOME_KEYRING gnome-keyring-1) endif() endif() # Optional: KWallet set(KF5_MIN_VERSION "5.27.0") find_package(KF5Wallet ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Wallet PROPERTIES DESCRIPTION "KWallet password backend plugin" TYPE OPTIONAL) # Git revision if (EXISTS "${CMAKE_SOURCE_DIR}/.git") find_package(Git QUIET) if(GIT_FOUND) execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_REVISION ) string(REGEX REPLACE "\n" "" GIT_REVISION "${GIT_REVISION}") add_definitions(-DGIT_REVISION=\"${GIT_REVISION}\") else() message(STATUS "Git revision could not be determined") endif() endif() # Include dirs used everywhere include_directories( ${CMAKE_SOURCE_DIR}/src/lib/3rdparty ${CMAKE_SOURCE_DIR}/src/lib/adblock ${CMAKE_SOURCE_DIR}/src/lib/app ${CMAKE_SOURCE_DIR}/src/lib/autofill ${CMAKE_SOURCE_DIR}/src/lib/bookmarks ${CMAKE_SOURCE_DIR}/src/lib/cookies ${CMAKE_SOURCE_DIR}/src/lib/downloads ${CMAKE_SOURCE_DIR}/src/lib/history ${CMAKE_SOURCE_DIR}/src/lib/navigation ${CMAKE_SOURCE_DIR}/src/lib/network ${CMAKE_SOURCE_DIR}/src/lib/notifications ${CMAKE_SOURCE_DIR}/src/lib/opensearch ${CMAKE_SOURCE_DIR}/src/lib/other ${CMAKE_SOURCE_DIR}/src/lib/plugins ${CMAKE_SOURCE_DIR}/src/lib/popupwindow ${CMAKE_SOURCE_DIR}/src/lib/preferences ${CMAKE_SOURCE_DIR}/src/lib/session ${CMAKE_SOURCE_DIR}/src/lib/sidebar ${CMAKE_SOURCE_DIR}/src/lib/tabwidget ${CMAKE_SOURCE_DIR}/src/lib/tools ${CMAKE_SOURCE_DIR}/src/lib/webengine ${CMAKE_SOURCE_DIR}/src/lib/webtab ) # Finally, go into the subdirs add_subdirectory(src) add_subdirectory(tests/autotests) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/src/lib/webengine/webpage.cpp b/src/lib/webengine/webpage.cpp index 8314f41e..3e0cb693 100644 --- a/src/lib/webengine/webpage.cpp +++ b/src/lib/webengine/webpage.cpp @@ -1,648 +1,642 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #include "webpage.h" #include "tabbedwebview.h" #include "browserwindow.h" #include "pluginproxy.h" #include "downloadmanager.h" #include "mainapplication.h" #include "checkboxdialog.h" #include "widget.h" #include "qztools.h" #include "speeddial.h" #include "autofill.h" #include "popupwebview.h" #include "popupwindow.h" #include "iconprovider.h" #include "qzsettings.h" #include "useragentmanager.h" #include "delayedfilewatcher.h" #include "searchenginesmanager.h" #include "html5permissions/html5permissionsmanager.h" #include "javascript/externaljsobject.h" #include "tabwidget.h" #include "networkmanager.h" #include "webhittestresult.h" #include "adblock/adblockmanager.h" - -#ifdef NONBLOCK_JS_DIALOGS #include "ui_jsconfirm.h" #include "ui_jsalert.h" #include "ui_jsprompt.h" -#include -#endif - #include #include #include #include #include #include #include #include #include #include #include +#include QString WebPage::s_lastUploadLocation = QDir::homePath(); QUrl WebPage::s_lastUnsupportedUrl; QTime WebPage::s_lastUnsupportedUrlTime; static const bool kEnableJsOutput = qEnvironmentVariableIsSet("QUPZILLA_ENABLE_JS_OUTPUT"); +static const bool kEnableJsNonBlockDialogs = qEnvironmentVariableIsSet("QUPZILLA_ENABLE_JS_NONBLOCK_DIALOGS"); WebPage::WebPage(QObject* parent) : QWebEnginePage(mApp->webProfile(), parent) , m_fileWatcher(0) , m_runningLoop(0) , m_loadProgress(-1) , m_blockAlerts(false) , m_secureStatus(false) { QWebChannel *channel = new QWebChannel(this); ExternalJsObject::setupWebChannel(channel, this); setWebChannel(channel); connect(this, &QWebEnginePage::loadProgress, this, &WebPage::progress); connect(this, &QWebEnginePage::loadFinished, this, &WebPage::finished); connect(this, &QWebEnginePage::urlChanged, this, &WebPage::urlChanged); connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::featurePermissionRequested); connect(this, &QWebEnginePage::windowCloseRequested, this, &WebPage::windowCloseRequested); connect(this, &QWebEnginePage::fullScreenRequested, this, &WebPage::fullScreenRequested); connect(this, &QWebEnginePage::renderProcessTerminated, this, &WebPage::renderProcessTerminated); connect(this, &QWebEnginePage::authenticationRequired, this, [this](const QUrl &url, QAuthenticator *auth) { mApp->networkManager()->authentication(url, auth, view()); }); connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, [this](const QUrl &, QAuthenticator *auth, const QString &proxyHost) { mApp->networkManager()->proxyAuthentication(proxyHost, auth, view()); }); // Workaround QWebEnginePage not scrolling to anchors when opened in background tab m_contentsResizedConnection = connect(this, &QWebEnginePage::contentsSizeChanged, this, [this]() { const QString fragment = url().fragment(); if (!fragment.isEmpty()) { const QString src = QSL("var els = document.querySelectorAll(\"[name='%1']\"); if (els.length) els[0].scrollIntoView();"); runJavaScript(src.arg(fragment)); } disconnect(m_contentsResizedConnection); }); } WebPage::~WebPage() { mApp->plugins()->emitWebPageDeleted(this); if (m_runningLoop) { m_runningLoop->exit(1); m_runningLoop = 0; } } WebView *WebPage::view() const { return static_cast(QWebEnginePage::view()); } bool WebPage::execPrintPage(QPrinter *printer, int timeout) { QPointer loop = new QEventLoop; bool result = false; QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit); print(printer, [loop, &result](bool res) { if (loop && loop->isRunning()) { result = res; loop->quit(); } }); loop->exec(); delete loop; return result; } QVariant WebPage::execJavaScript(const QString &scriptSource, quint32 worldId, int timeout) { QPointer loop = new QEventLoop; QVariant result; QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit); runJavaScript(scriptSource, worldId, [loop, &result](const QVariant &res) { if (loop && loop->isRunning()) { result = res; loop->quit(); } }); loop->exec(QEventLoop::ExcludeUserInputEvents); delete loop; return result; } QPointF WebPage::mapToViewport(const QPointF &pos) const { return QPointF(pos.x() / zoomFactor(), pos.y() / zoomFactor()); } WebHitTestResult WebPage::hitTestContent(const QPoint &pos) const { return WebHitTestResult(this, pos); } void WebPage::scroll(int x, int y) { runJavaScript(QSL("window.scrollTo(window.scrollX + %1, window.scrollY + %2)").arg(x).arg(y), WebPage::SafeJsWorld); } void WebPage::setScrollPosition(const QPointF &pos) { const QPointF v = mapToViewport(pos.toPoint()); runJavaScript(QSL("window.scrollTo(%1, %2)").arg(v.x()).arg(v.y()), WebPage::SafeJsWorld); } bool WebPage::isRunningLoop() { return m_runningLoop; } bool WebPage::isLoading() const { return m_loadProgress < 100; } void WebPage::urlChanged(const QUrl &url) { Q_UNUSED(url) if (isLoading()) { m_blockAlerts = false; } } void WebPage::progress(int prog) { m_loadProgress = prog; bool secStatus = url().scheme() == QL1S("https"); if (secStatus != m_secureStatus) { m_secureStatus = secStatus; emit privacyChanged(secStatus); } } void WebPage::finished() { progress(100); // File scheme watcher if (url().scheme() == QLatin1String("file")) { QFileInfo info(url().toLocalFile()); if (info.isFile()) { if (!m_fileWatcher) { m_fileWatcher = new DelayedFileWatcher(this); connect(m_fileWatcher, SIGNAL(delayedFileChanged(QString)), this, SLOT(watchedFileChanged(QString))); } const QString filePath = url().toLocalFile(); if (QFile::exists(filePath) && !m_fileWatcher->files().contains(filePath)) { m_fileWatcher->addPath(filePath); } } } else if (m_fileWatcher && !m_fileWatcher->files().isEmpty()) { m_fileWatcher->removePaths(m_fileWatcher->files()); } // AutoFill m_passwordEntries = mApp->autoFill()->completePage(this, url()); } void WebPage::watchedFileChanged(const QString &file) { if (url().toLocalFile() == file) { triggerAction(QWebEnginePage::Reload); } } void WebPage::handleUnknownProtocol(const QUrl &url) { const QString protocol = url.scheme(); if (protocol == QLatin1String("mailto")) { desktopServicesOpen(url); return; } if (qzSettings->blockedProtocols.contains(protocol)) { qDebug() << "WebPage::handleUnknownProtocol Protocol" << protocol << "is blocked!"; return; } if (qzSettings->autoOpenProtocols.contains(protocol)) { desktopServicesOpen(url); return; } CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, view()); dialog.setDefaultButton(QMessageBox::Yes); const QString wrappedUrl = QzTools::alignTextToWidth(url.toString(), "
", dialog.fontMetrics(), 450); const QString text = tr("Falkon cannot handle %1: links. The requested link " "is
  • %2
Do you want Falkon to try " "open this link in system application?").arg(protocol, wrappedUrl); dialog.setText(text); dialog.setCheckBoxText(tr("Remember my choice for this protocol")); dialog.setWindowTitle(tr("External Protocol Request")); dialog.setIcon(QMessageBox::Question); switch (dialog.exec()) { case QMessageBox::Yes: if (dialog.isChecked()) { qzSettings->autoOpenProtocols.append(protocol); qzSettings->saveSettings(); } QDesktopServices::openUrl(url); break; case QMessageBox::No: if (dialog.isChecked()) { qzSettings->blockedProtocols.append(protocol); qzSettings->saveSettings(); } break; default: break; } } void WebPage::desktopServicesOpen(const QUrl &url) { // Open same url only once in 2 secs const int sameUrlTimeout = 2 * 1000; if (s_lastUnsupportedUrl != url || s_lastUnsupportedUrlTime.isNull() || s_lastUnsupportedUrlTime.elapsed() > sameUrlTimeout) { s_lastUnsupportedUrl = url; s_lastUnsupportedUrlTime.restart(); QDesktopServices::openUrl(url); } else { qWarning() << "WebPage::desktopServicesOpen Url" << url << "has already been opened!\n" "Ignoring it to prevent infinite loop!"; } } void WebPage::windowCloseRequested() { if (!view()) return; view()->closeView(); } void WebPage::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) { view()->requestFullScreen(fullScreenRequest.toggleOn()); const bool accepted = fullScreenRequest.toggleOn() == view()->isFullScreen(); if (accepted) fullScreenRequest.accept(); else fullScreenRequest.reject(); } void WebPage::featurePermissionRequested(const QUrl &origin, const QWebEnginePage::Feature &feature) { if (feature == MouseLock && view()->isFullScreen()) setFeaturePermission(origin, feature, PermissionGrantedByUser); else mApp->html5PermissionsManager()->requestPermissions(this, origin, feature); } void WebPage::renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode) { Q_UNUSED(exitCode) if (terminationStatus == NormalTerminationStatus) return; QTimer::singleShot(0, this, [this]() { QString page = QzTools::readAllFileContents(":html/tabcrash.html"); page.replace(QL1S("%IMAGE%"), QzTools::pixmapToDataUrl(IconProvider::standardIcon(QStyle::SP_MessageBoxWarning).pixmap(45)).toString()); page.replace(QL1S("%TITLE%"), tr("Failed loading page")); page.replace(QL1S("%HEADING%"), tr("Failed loading page")); page.replace(QL1S("%LI-1%"), tr("Something went wrong while loading this page.")); page.replace(QL1S("%LI-2%"), tr("Try reloading the page or closing some tabs to make more memory available.")); page.replace(QL1S("%RELOAD-PAGE%"), tr("Reload page")); page = QzTools::applyDirectionToPage(page); load(url()); // Workaround for QtWebEngine crash setHtml(page.toUtf8(), url()); }); } bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) { if (!mApp->plugins()->acceptNavigationRequest(this, url, type, isMainFrame)) return false; // AdBlock AdBlockManager *manager = AdBlockManager::instance(); if (isMainFrame) { manager->clearBlockedRequestsForUrl(WebPage::url()); } if (url.scheme() == QL1S("abp") && AdBlockManager::instance()->addSubscriptionFromUrl(url)) { return false; } return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); } bool WebPage::certificateError(const QWebEngineCertificateError &error) { return mApp->networkManager()->certificateError(error, view()); } QStringList WebPage::chooseFiles(QWebEnginePage::FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) { Q_UNUSED(acceptedMimeTypes); QStringList files; QString suggestedFileName = s_lastUploadLocation; if (!oldFiles.isEmpty()) suggestedFileName = oldFiles.at(0); switch (mode) { case FileSelectOpen: files = QStringList(QzTools::getOpenFileName("WebPage-ChooseFile", view(), tr("Choose file..."), suggestedFileName)); break; case FileSelectOpenMultiple: files = QzTools::getOpenFileNames("WebPage-ChooseFile", view(), tr("Choose files..."), suggestedFileName); break; default: files = QWebEnginePage::chooseFiles(mode, oldFiles, acceptedMimeTypes); break; } if (!files.isEmpty()) s_lastUploadLocation = files.at(0); return files; } bool WebPage::hasMultipleUsernames() const { return m_passwordEntries.count() > 1; } QVector WebPage::autoFillData() const { return m_passwordEntries; } bool WebPage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result) { - Q_UNUSED(securityOrigin) + if (!kEnableJsNonBlockDialogs) { + return QWebEnginePage::javaScriptPrompt(securityOrigin, msg, defaultValue, result); + } -#ifndef NONBLOCK_JS_DIALOGS - return QWebEnginePage::javaScriptPrompt(securityOrigin, msg, defaultValue, result); -#else if (m_runningLoop) { return false; } ResizableFrame* widget = new ResizableFrame(view()->overlayWidget()); widget->setObjectName("jsFrame"); Ui_jsPrompt* ui = new Ui_jsPrompt(); ui->setupUi(widget); ui->message->setText(msg); ui->lineEdit->setText(defaultValue); ui->lineEdit->setFocus(); widget->resize(view()->size()); widget->show(); connect(view(), SIGNAL(viewportResized(QSize)), widget, SLOT(slotResize(QSize))); connect(ui->lineEdit, SIGNAL(returnPressed()), ui->buttonBox->button(QDialogButtonBox::Ok), SLOT(animateClick())); QEventLoop eLoop; m_runningLoop = &eLoop; connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), &eLoop, SLOT(quit())); if (eLoop.exec() == 1) { return result; } m_runningLoop = 0; QString x = ui->lineEdit->text(); bool _result = ui->buttonBox->clickedButtonRole() == QDialogButtonBox::AcceptRole; *result = x; delete widget; view()->setFocus(); return _result; -#endif } bool WebPage::javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) { - Q_UNUSED(securityOrigin) + if (!kEnableJsNonBlockDialogs) { + return QWebEnginePage::javaScriptConfirm(securityOrigin, msg); + } -#ifndef NONBLOCK_JS_DIALOGS - return QWebEnginePage::javaScriptConfirm(securityOrigin, msg); -#else if (m_runningLoop) { return false; } ResizableFrame* widget = new ResizableFrame(view()->overlayWidget()); widget->setObjectName("jsFrame"); Ui_jsConfirm* ui = new Ui_jsConfirm(); ui->setupUi(widget); ui->message->setText(msg); ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); widget->resize(view()->size()); widget->show(); connect(view(), SIGNAL(viewportResized(QSize)), widget, SLOT(slotResize(QSize))); QEventLoop eLoop; m_runningLoop = &eLoop; connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), &eLoop, SLOT(quit())); if (eLoop.exec() == 1) { return false; } m_runningLoop = 0; bool result = ui->buttonBox->clickedButtonRole() == QDialogButtonBox::AcceptRole; delete widget; view()->setFocus(); return result; -#endif } void WebPage::javaScriptAlert(const QUrl &securityOrigin, const QString &msg) { Q_UNUSED(securityOrigin) if (m_blockAlerts || m_runningLoop) { return; } -#ifndef NONBLOCK_JS_DIALOGS - QString title = tr("JavaScript alert"); - if (!url().host().isEmpty()) { - title.append(QString(" - %1").arg(url().host())); - } + if (!kEnableJsNonBlockDialogs) { + QString title = tr("JavaScript alert"); + if (!url().host().isEmpty()) { + title.append(QString(" - %1").arg(url().host())); + } - CheckBoxDialog dialog(QMessageBox::Ok, view()); - dialog.setDefaultButton(QMessageBox::Ok); - dialog.setWindowTitle(title); - dialog.setText(msg); - dialog.setCheckBoxText(tr("Prevent this page from creating additional dialogs")); - dialog.setIcon(QMessageBox::Information); - dialog.exec(); + CheckBoxDialog dialog(QMessageBox::Ok, view()); + dialog.setDefaultButton(QMessageBox::Ok); + dialog.setWindowTitle(title); + dialog.setText(msg); + dialog.setCheckBoxText(tr("Prevent this page from creating additional dialogs")); + dialog.setIcon(QMessageBox::Information); + dialog.exec(); + + m_blockAlerts = dialog.isChecked(); + return; + } - m_blockAlerts = dialog.isChecked(); -#else ResizableFrame* widget = new ResizableFrame(view()->overlayWidget()); widget->setObjectName("jsFrame"); Ui_jsAlert* ui = new Ui_jsAlert(); ui->setupUi(widget); ui->message->setText(msg); ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); widget->resize(view()->size()); widget->show(); connect(view(), SIGNAL(viewportResized(QSize)), widget, SLOT(slotResize(QSize))); QEventLoop eLoop; m_runningLoop = &eLoop; connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), &eLoop, SLOT(quit())); if (eLoop.exec() == 1) { return; } m_runningLoop = 0; m_blockAlerts = ui->preventAlerts->isChecked(); delete widget; view()->setFocus(); -#endif } void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) { if (!kEnableJsOutput) { return; } switch (level) { case InfoMessageLevel: std::cout << "[I] "; break; case WarningMessageLevel: std::cout << "[W] "; break; case ErrorMessageLevel: std::cout << "[E] "; break; } std::cout << qPrintable(sourceID) << ":" << lineNumber << " " << qPrintable(message); } void WebPage::setJavaScriptEnabled(bool enabled) { settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, enabled); } QWebEnginePage* WebPage::createWindow(QWebEnginePage::WebWindowType type) { TabbedWebView *tView = qobject_cast(view()); BrowserWindow *window = tView ? tView->browserWindow() : mApp->getWindow(); auto createTab = [=](Qz::NewTabPositionFlags pos) { int index = window->tabWidget()->addView(QUrl(), pos); TabbedWebView* view = window->weView(index); view->setPage(new WebPage); // Workaround focus issue when creating tab if (pos.testFlag(Qz::NT_SelectedTab)) { QPointer pview = view; QTimer::singleShot(0, this, [pview]() { if (pview && pview->webTab()->isCurrentTab()) { pview->setFocus(); } }); } return view->page(); }; switch (type) { case QWebEnginePage::WebBrowserWindow: { BrowserWindow *window = mApp->createWindow(Qz::BW_NewWindow); WebPage *page = new WebPage; window->setStartPage(page); return page; } case QWebEnginePage::WebDialog: if (!qzSettings->openPopupsInTabs) { PopupWebView* view = new PopupWebView; view->setPage(new WebPage); PopupWindow* popup = new PopupWindow(view); popup->show(); window->addDeleteOnCloseWidget(popup); return view->page(); } // else fallthrough case QWebEnginePage::WebBrowserTab: return createTab(Qz::NT_CleanSelectedTab); case QWebEnginePage::WebBrowserBackgroundTab: return createTab(Qz::NT_CleanNotSelectedTab); default: break; } return Q_NULLPTR; }