diff --git a/CMakeLists.txt b/CMakeLists.txt index da8aca46..ca7c9b0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,187 +1,185 @@ # 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 3.0.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) include(ECMPoQmTools) # 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}) set(PLUGIN_PATH "${FALKON_INSTALL_PLUGINDIR}") else() set(PLUGIN_PATH "${CMAKE_INSTALL_PREFIX}/${FALKON_INSTALL_PLUGINDIR}") endif() if (NOT WIN32) set(FALKON_PLUGIN_PATH "${PLUGIN_PATH}" CACHE PATH "Default plugin search path") endif() # Defines that are always set add_definitions(-DQT_NO_URL_CAST_FROM_STRING -DQT_USE_QSTRINGBUILDER -DQT_NO_CAST_TO_ASCII) # Mandatory: Qt5 set(QT_MIN_VERSION "5.9.0") -find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Widgets Network Sql QuickWidgets PrintSupport WebEngineWidgets WebChannel) +find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Core Widgets Network Sql QuickWidgets PrintSupport WebEngine WebEngineWidgets WebChannel) if (BUILD_TESTING) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Test) endif() if (NOT DISABLE_DBUS) find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS DBus) endif() if (UNIX AND NOT APPLE AND NOT NO_X11) add_definitions(-DQZ_WS_X11) find_package(XCB REQUIRED COMPONENTS XCB UTIL) 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() -set(HAVE_QTWEBENGINE_5_10 NOT Qt5WebEngineWidgets_VERSION VERSION_LESS 5.10.0) - # Mandatory: OpenSSL find_package(OpenSSL REQUIRED) # KF5I18n: Mandatory with downloaded translations (only for ki18n_install) if (EXISTS "${CMAKE_SOURCE_DIR}/po") find_package(KF5I18n REQUIRED) 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, KIO, KCrash, KCoreAddons set(KF5_MIN_VERSION "5.27.0") find_package(KF5Wallet ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Wallet PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) find_package(KF5KIO ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5KIO PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) find_package(KF5Crash ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Crash PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) find_package(KF5CoreAddons ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5CoreAddons PROPERTIES DESCRIPTION "KDE Frameworks Integration plugin" TYPE OPTIONAL) if (KF5Wallet_FOUND AND KF5KIO_FOUND AND KF5Crash_FOUND AND KF5CoreAddons_FOUND) set(ENABLE_KDE_FRAMEWORKS_INTEGRATION_PLUGIN TRUE) endif() # Optional: PySide2 find_package(PySide2 "2.0.0") find_package(Shiboken2 "2.0.0") find_package(PythonLibs "3.0") set_package_properties(PySide2 PROPERTIES DESCRIPTION "Python plugins (experimental)" TYPE OPTIONAL) set_package_properties(Shiboken2 PROPERTIES DESCRIPTION "Python plugins (experimental)" TYPE OPTIONAL) set_package_properties(PythonLibs PROPERTIES DESCRIPTION "Python plugins (experimental)" TYPE OPTIONAL) if (PySide2_FOUND AND Shiboken2_FOUND AND PythonLibs_FOUND) set(ENABLE_PYTHON_PLUGINS TRUE) endif() # 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}") set(FALKON_GIT_REVISION "${GIT_REVISION}") else() message(STATUS "Git revision could not be determined") endif() endif() configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config.h) # 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) if (BUILD_TESTING) add_subdirectory(autotests) add_subdirectory(tests/benchmarks) endif() # Tell releaseme that po is already taken care of # SKIP_PO_INSTALL feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/config.h.cmake b/config.h.cmake index 3cc5d348..d35648e5 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -1,14 +1,11 @@ /* config.h. Generated by cmake from config.h.cmake */ #define FALKON_VERSION "${PROJECT_VERSION}" #cmakedefine FALKON_PLUGIN_PATH "${FALKON_PLUGIN_PATH}" #cmakedefine FALKON_GIT_REVISION "${FALKON_GIT_REVISION}" /* Enable portable build */ #cmakedefine PORTABLE_BUILD /* Disable DBus support */ #cmakedefine DISABLE_DBUS - -/* QtWebEngine is at least version 5.10 */ -#cmakedefine01 HAVE_QTWEBENGINE_5_10 diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 81cc5c8a..ee82c94e 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,326 +1,329 @@ add_definitions(-DFALKON_SHAREDLIBRARY) set(CMAKE_CXX_STANDARD 14) # Enable C++14, with cmake >= 3.1 set(CMAKE_CXX_EXTENSIONS OFF) # Don't enable gcc-specific extensions set(SRCS 3rdparty/qtsingleapplication/qtsingleapplication.cpp 3rdparty/qtsingleapplication/qtlocalpeer.cpp ) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(SRCS ${SRCS} ${CMAKE_SOURCE_DIR}/tests/modeltest/modeltest.cpp) include_directories(${CMAKE_SOURCE_DIR}/tests/modeltest) endif() include_directories( 3rdparty adblock app autofill bookmarks cookies downloads history navigation network notifications opensearch other plugins popupwindow preferences session sidebar tabwidget tools webengine webtab ) include_directories(${OPENSSL_INCLUDE_DIR}) set(SRCS ${SRCS} 3rdparty/fancytabwidget.cpp 3rdparty/lineedit.cpp 3rdparty/processinfo.cpp 3rdparty/squeezelabelv1.cpp 3rdparty/squeezelabelv2.cpp 3rdparty/stylehelper.cpp adblock/adblockaddsubscriptiondialog.cpp adblock/adblockurlinterceptor.cpp adblock/adblockdialog.cpp adblock/adblockicon.cpp adblock/adblockmanager.cpp adblock/adblockmatcher.cpp adblock/adblockrule.cpp adblock/adblocksearchtree.cpp adblock/adblocksubscription.cpp adblock/adblocktreewidget.cpp adblock/adblockplugin.cpp app/autosaver.cpp app/browserwindow.cpp app/commandlineoptions.cpp app/datapaths.cpp app/mainapplication.cpp app/mainmenu.cpp app/profilemanager.cpp app/proxystyle.cpp app/qzcommon.cpp app/settings.cpp autofill/autofill.cpp autofill/autofillicon.cpp autofill/autofillnotification.cpp autofill/autofillwidget.cpp autofill/passwordbackends/databaseencryptedpasswordbackend.cpp autofill/passwordbackends/databasepasswordbackend.cpp autofill/passwordbackends/passwordbackend.cpp autofill/passwordmanager.cpp bookmarks/bookmarkitem.cpp bookmarks/bookmarks.cpp bookmarks/bookmarksexport/bookmarksexportdialog.cpp bookmarks/bookmarksexport/bookmarksexporter.cpp bookmarks/bookmarksexport/htmlexporter.cpp bookmarks/bookmarksicon.cpp bookmarks/bookmarksimport/bookmarksimportdialog.cpp bookmarks/bookmarksimport/bookmarksimporter.cpp bookmarks/bookmarksimport/firefoximporter.cpp bookmarks/bookmarksimport/htmlimporter.cpp bookmarks/bookmarksimport/chromeimporter.cpp bookmarks/bookmarksimport/ieimporter.cpp bookmarks/bookmarksimport/operaimporter.cpp bookmarks/bookmarksitemdelegate.cpp bookmarks/bookmarksmanager.cpp bookmarks/bookmarksmenu.cpp bookmarks/bookmarksmodel.cpp bookmarks/bookmarkstoolbarbutton.cpp bookmarks/bookmarkstoolbar.cpp bookmarks/bookmarkstools.cpp bookmarks/bookmarkstreeview.cpp bookmarks/bookmarkswidget.cpp cookies/cookiejar.cpp cookies/cookiemanager.cpp downloads/downloaditem.cpp downloads/downloadmanager.cpp downloads/downloadoptionsdialog.cpp downloads/downloadsbutton.cpp history/history.cpp history/historyitem.cpp history/historymanager.cpp history/historymenu.cpp history/historymodel.cpp history/historytreeview.cpp navigation/completer/locationcompleter.cpp navigation/completer/locationcompleterdelegate.cpp navigation/completer/locationcompletermodel.cpp navigation/completer/locationcompleterrefreshjob.cpp navigation/completer/locationcompleterview.cpp navigation/downicon.cpp navigation/goicon.cpp navigation/locationbar.cpp navigation/locationbarpopup.cpp navigation/navigationbar.cpp navigation/navigationbartoolbutton.cpp navigation/navigationbarconfigdialog.cpp navigation/navigationcontainer.cpp navigation/reloadstopbutton.cpp navigation/siteicon.cpp navigation/websearchbar.cpp network/networkmanager.cpp network/networkurlinterceptor.cpp network/schemehandlers/extensionschemehandler.cpp network/schemehandlers/falkonschemehandler.cpp network/sslerrordialog.cpp notifications/desktopnotification.cpp notifications/desktopnotificationsfactory.cpp opensearch/editsearchengine.cpp opensearch/opensearchengine.cpp opensearch/opensearchenginedelegate.cpp opensearch/opensearchreader.cpp opensearch/searchenginesdialog.cpp opensearch/searchenginesmanager.cpp other/aboutdialog.cpp other/browsinglibrary.cpp other/clearprivatedata.cpp other/checkboxdialog.cpp other/iconchooser.cpp other/licenseviewer.cpp other/qzsettings.cpp other/siteinfo.cpp other/siteinfowidget.cpp other/statusbar.cpp other/updater.cpp other/useragentmanager.cpp plugins/pluginproxy.cpp plugins/plugins.cpp plugins/speeddial.cpp popupwindow/popuplocationbar.cpp popupwindow/popupstatusbarmessage.cpp popupwindow/popupwebview.cpp popupwindow/popupwindow.cpp preferences/acceptlanguage.cpp preferences/autofillmanager.cpp preferences/jsoptions.cpp preferences/pluginlistdelegate.cpp preferences/pluginsmanager.cpp preferences/preferences.cpp preferences/thememanager.cpp preferences/useragentdialog.cpp session/recoveryjsobject.cpp session/restoremanager.cpp session/sessionmanager.cpp session/sessionmanagerdialog.cpp sidebar/bookmarkssidebar.cpp sidebar/historysidebar.cpp sidebar/sidebar.cpp tabwidget/combotabbar.cpp tabwidget/tabbar.cpp tabwidget/tabicon.cpp tabwidget/tabmodel.cpp tabwidget/tabmrumodel.cpp tabwidget/tabtreemodel.cpp tabwidget/tabstackedwidget.cpp tabwidget/tabwidget.cpp tabwidget/tabcontextmenu.cpp tools/abstractbuttoninterface.cpp tools/aesinterface.cpp tools/animatedwidget.cpp tools/buttonwithmenu.cpp tools/certificateinfowidget.cpp tools/clickablelabel.cpp tools/closedtabsmanager.cpp tools/closedwindowsmanager.cpp tools/colors.cpp tools/delayedfilewatcher.cpp tools/desktopfile.cpp tools/docktitlebarwidget.cpp tools/enhancedmenu.cpp tools/focusselectlineedit.cpp tools/headerview.cpp tools/horizontallistwidget.cpp tools/html5permissions/html5permissionsdialog.cpp tools/html5permissions/html5permissionsmanager.cpp tools/html5permissions/html5permissionsnotification.cpp tools/iconprovider.cpp tools/listitemdelegate.cpp tools/mactoolbutton.cpp tools/menubar.cpp tools/pagethumbnailer.cpp tools/progressbar.cpp tools/qztools.cpp tools/removeitemfocusdelegate.cpp tools/scripts.cpp tools/sqldatabase.cpp tools/toolbutton.cpp tools/treewidget.cpp tools/wheelhelper.cpp webengine/javascript/autofilljsobject.cpp webengine/javascript/externaljsobject.cpp webengine/loadrequest.cpp webengine/webhittestresult.cpp webengine/webinspector.cpp webengine/webpage.cpp webengine/webview.cpp webengine/webscrollbar.cpp webengine/webscrollbarmanager.cpp webtab/searchtoolbar.cpp webtab/tabbedwebview.cpp webtab/webtab.cpp ) if (WIN32) set(SRCS ${SRCS} other/registerqappassociation.cpp) endif() if (APPLE) set(SRCS ${SRCS} tools/disablewindowtabbbing.mm) endif() # TODO: use ki18n_wrap_ui? qt5_wrap_ui(SRCS adblock/adblockaddsubscriptiondialog.ui adblock/adblockdialog.ui autofill/autofillnotification.ui autofill/autofillwidget.ui autofill/passwordbackends/masterpassworddialog.ui bookmarks/bookmarksexport/bookmarksexportdialog.ui bookmarks/bookmarksimport/bookmarksimportdialog.ui bookmarks/bookmarksmanager.ui bookmarks/bookmarkswidget.ui cookies/cookiemanager.ui downloads/downloaditem.ui downloads/downloadmanager.ui downloads/downloadoptionsdialog.ui history/historymanager.ui navigation/navigationbarconfigdialog.ui network/sslerrordialog.ui notifications/desktopnotification.ui opensearch/editsearchengine.ui opensearch/searchenginesdialog.ui other/aboutdialog.ui other/browsinglibrary.ui other/clearprivatedata.ui other/iconchooser.ui other/siteinfo.ui other/siteinfowidget.ui preferences/acceptlanguage.ui preferences/addacceptlanguage.ui preferences/autofillmanager.ui preferences/jsoptions.ui preferences/pluginslist.ui preferences/preferences.ui preferences/thememanager.ui preferences/useragentdialog.ui session/sessionmanagerdialog.ui sidebar/bookmarkssidebar.ui sidebar/historysidebar.ui tools/certificateinfowidget.ui tools/docktitlebarwidget.ui tools/html5permissions/html5permissionsdialog.ui tools/html5permissions/html5permissionsnotification.ui webengine/jsalert.ui webengine/jsconfirm.ui webengine/jsprompt.ui webtab/searchtoolbar.ui ) qt5_add_resources(SRCS data/data.qrc data/html.qrc data/icons.qrc data/breeze-fallback.qrc adblock/adblock.qrc ) add_library(FalkonPrivate SHARED ${SRCS}) +get_property(QT_WEBENGINE_INCLUDE_DIRS TARGET Qt5::WebEngine PROPERTY INTERFACE_INCLUDE_DIRECTORIES) +target_include_directories(FalkonPrivate SYSTEM PUBLIC ${QT_WEBENGINE_INCLUDE_DIRS}) + target_link_libraries(FalkonPrivate Qt5::Widgets Qt5::WebEngineWidgets Qt5::Network Qt5::Sql Qt5::PrintSupport Qt5::QuickWidgets Qt5::WebChannel ${OPENSSL_CRYPTO_LIBRARY} ) if (UNIX AND NOT APPLE) if (NOT NO_X11) target_link_libraries(FalkonPrivate XCB::XCB Qt5::X11Extras) endif() set_target_properties(FalkonPrivate PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION "3") install(TARGETS FalkonPrivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) endif() if (WIN32) target_link_libraries(FalkonPrivate Qt5::WinExtras) endif() if (APPLE) target_link_libraries(FalkonPrivate "-framework CoreServices -framework AppKit") endif() if (NOT DISABLE_DBUS) target_link_libraries(FalkonPrivate Qt5::DBus) endif() diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index 03ba6292..f9b5d94b 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -1,1229 +1,1229 @@ /* ============================================================ * 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 "mainapplication.h" #include "history.h" #include "qztools.h" #include "updater.h" #include "autofill.h" #include "settings.h" #include "autosaver.h" #include "datapaths.h" #include "tabwidget.h" #include "cookiejar.h" #include "bookmarks.h" #include "qzsettings.h" #include "proxystyle.h" #include "pluginproxy.h" #include "iconprovider.h" #include "browserwindow.h" #include "checkboxdialog.h" #include "networkmanager.h" #include "profilemanager.h" #include "restoremanager.h" #include "browsinglibrary.h" #include "downloadmanager.h" #include "clearprivatedata.h" #include "useragentmanager.h" #include "commandlineoptions.h" #include "searchenginesmanager.h" #include "desktopnotificationsfactory.h" #include "html5permissions/html5permissionsmanager.h" #include "scripts.h" #include "sessionmanager.h" #include "closedwindowsmanager.h" #include "../config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Q_OS_WIN #include #include #include #endif #include #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) #include "registerqappassociation.h" #endif static bool s_testMode = false; MainApplication::MainApplication(int &argc, char** argv) : QtSingleApplication(argc, argv) , m_isPrivate(false) , m_isPortable(false) , m_isClosing(false) , m_isStartingAfterCrash(false) , m_history(0) , m_bookmarks(0) , m_autoFill(0) , m_cookieJar(0) , m_plugins(0) , m_browsingLibrary(0) , m_networkManager(0) , m_restoreManager(0) , m_sessionManager(0) , m_downloadManager(0) , m_userAgentManager(0) , m_searchEnginesManager(0) , m_closedWindowsManager(0) , m_html5PermissionsManager(0) , m_desktopNotifications(0) , m_webProfile(0) , m_autoSaver(0) #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) , m_registerQAppAssociation(0) #endif { setAttribute(Qt::AA_UseHighDpiPixmaps); setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); setApplicationName(QLatin1String("falkon")); setOrganizationDomain(QLatin1String("org.kde")); setWindowIcon(QIcon::fromTheme(QSL("falkon"), QIcon(QSL(":icons/falkon.svg")))); setDesktopFileName(QSL("org.kde.falkon")); #ifdef GIT_REVISION setApplicationVersion(QSL("%1 (%2)").arg(Qz::VERSION, GIT_REVISION)); #else setApplicationVersion(Qz::VERSION); #endif // Set fallback icon theme (eg. on Windows/Mac) if (QIcon::fromTheme(QSL("view-refresh")).isNull()) { QIcon::setThemeName(QSL("breeze-fallback")); } // QSQLITE database plugin is required if (!QSqlDatabase::isDriverAvailable(QSL("QSQLITE"))) { QMessageBox::critical(0, QSL("Error"), QSL("Qt SQLite database plugin is not available. Please install it and restart the application.")); m_isClosing = true; return; } #ifdef Q_OS_WIN // Set default app font (needed for N'ko) int fontId = QFontDatabase::addApplicationFont(QSL("font.ttf")); if (fontId != -1) { const QStringList families = QFontDatabase::applicationFontFamilies(fontId); if (!families.empty()) setFont(QFont(families.at(0))); } #endif QUrl startUrl; QString startProfile; QStringList messages; bool noAddons = false; bool newInstance = false; if (argc > 1) { CommandLineOptions cmd; foreach (const CommandLineOptions::ActionPair &pair, cmd.getActions()) { switch (pair.action) { case Qz::CL_StartWithoutAddons: noAddons = true; break; case Qz::CL_StartWithProfile: startProfile = pair.text; break; case Qz::CL_StartPortable: m_isPortable = true; break; case Qz::CL_NewTab: messages.append(QLatin1String("ACTION:NewTab")); m_postLaunchActions.append(OpenNewTab); break; case Qz::CL_NewWindow: messages.append(QLatin1String("ACTION:NewWindow")); break; case Qz::CL_ToggleFullScreen: messages.append(QLatin1String("ACTION:ToggleFullScreen")); m_postLaunchActions.append(ToggleFullScreen); break; case Qz::CL_ShowDownloadManager: messages.append(QLatin1String("ACTION:ShowDownloadManager")); m_postLaunchActions.append(OpenDownloadManager); break; case Qz::CL_StartPrivateBrowsing: m_isPrivate = true; break; case Qz::CL_StartNewInstance: newInstance = true; break; case Qz::CL_OpenUrlInCurrentTab: startUrl = QUrl::fromUserInput(pair.text); messages.append("ACTION:OpenUrlInCurrentTab" + pair.text); break; case Qz::CL_OpenUrlInNewWindow: startUrl = QUrl::fromUserInput(pair.text); messages.append("ACTION:OpenUrlInNewWindow" + pair.text); break; case Qz::CL_OpenUrl: startUrl = QUrl::fromUserInput(pair.text); messages.append("URL:" + pair.text); break; case Qz::CL_ExitAction: m_isClosing = true; return; default: break; } } } if (!isPortable()) { QSettings falkonConf(QSL("%1/falkon.conf").arg(applicationDirPath()), QSettings::IniFormat); m_isPortable = falkonConf.value(QSL("Config/Portable")).toBool(); } if (isPortable()) { std::cout << "Falkon: Running in Portable Mode." << std::endl; DataPaths::setPortableVersion(); } // Don't start single application in private browsing if (!isPrivate()) { QString appId = QLatin1String("FalkonWebBrowser"); if (isPortable()) { appId.append(QLatin1String("Portable")); } if (isTestModeEnabled()) { appId.append(QSL("TestMode")); } if (newInstance) { if (startProfile.isEmpty() || startProfile == QLatin1String("default")) { std::cout << "New instance cannot be started with default profile!" << std::endl; } else { // Generate unique appId so it is possible to start more separate instances // of the same profile. It is dangerous to run more instances of the same profile, // but if the user wants it, we should allow it. appId.append(startProfile + QString::number(QDateTime::currentMSecsSinceEpoch())); } } setAppId(appId); } // If there is nothing to tell other instance, we need to at least wake it if (messages.isEmpty()) { messages.append(QLatin1String(" ")); } if (isRunning()) { m_isClosing = true; foreach (const QString &message, messages) { sendMessage(message); } return; } #ifdef Q_OS_MACOS setQuitOnLastWindowClosed(false); // disable tabbing issue#2261 extern void disableWindowTabbing(); disableWindowTabbing(); #else setQuitOnLastWindowClosed(true); #endif QSettings::setDefaultFormat(QSettings::IniFormat); QDesktopServices::setUrlHandler(QSL("http"), this, "addNewTab"); QDesktopServices::setUrlHandler(QSL("https"), this, "addNewTab"); QDesktopServices::setUrlHandler(QSL("ftp"), this, "addNewTab"); ProfileManager profileManager; profileManager.initConfigDir(); profileManager.initCurrentProfile(startProfile); Settings::createSettings(DataPaths::currentProfilePath() + QLatin1String("/settings.ini")); m_webProfile = isPrivate() ? new QWebEngineProfile(this) : QWebEngineProfile::defaultProfile(); connect(m_webProfile, &QWebEngineProfile::downloadRequested, this, &MainApplication::downloadRequested); m_networkManager = new NetworkManager(this); setupUserScripts(); if (!isPrivate() && !isTestModeEnabled()) { m_sessionManager = new SessionManager(this); m_autoSaver = new AutoSaver(this); connect(m_autoSaver, SIGNAL(save()), m_sessionManager, SLOT(autoSaveLastSession())); Settings settings; settings.beginGroup(QSL("SessionRestore")); const bool wasRunning = settings.value(QSL("isRunning"), false).toBool(); const bool wasRestoring = settings.value(QSL("isRestoring"), false).toBool(); settings.setValue(QSL("isRunning"), true); settings.setValue(QSL("isRestoring"), wasRunning); settings.endGroup(); settings.sync(); m_isStartingAfterCrash = wasRunning && wasRestoring; if (wasRunning) { QTimer::singleShot(60 * 1000, this, [this]() { Settings().setValue(QSL("SessionRestore/isRestoring"), false); }); } // we have to ask about startup session before creating main window if (!m_isStartingAfterCrash && afterLaunch() == SelectSession) m_restoreManager = new RestoreManager(sessionManager()->askSessionFromUser()); } loadSettings(); m_plugins = new PluginProxy(this); m_autoFill = new AutoFill(this); if (!noAddons) m_plugins->loadPlugins(); BrowserWindow* window = createWindow(Qz::BW_FirstAppWindow, startUrl); connect(window, SIGNAL(startingCompleted()), this, SLOT(restoreOverrideCursor())); connect(this, SIGNAL(focusChanged(QWidget*,QWidget*)), this, SLOT(onFocusChanged())); if (!isPrivate() && !isTestModeEnabled()) { #ifndef DISABLE_CHECK_UPDATES Settings settings; bool checkUpdates = settings.value("Web-Browser-Settings/CheckUpdates", true).toBool(); if (checkUpdates) { new Updater(window); } #endif sessionManager()->backupSavedSessions(); if (m_isStartingAfterCrash || afterLaunch() == RestoreSession) { m_restoreManager = new RestoreManager(sessionManager()->lastActiveSessionPath()); if (!m_restoreManager->isValid()) { destroyRestoreManager(); } } if (!m_isStartingAfterCrash && m_restoreManager) { restoreSession(window, m_restoreManager->restoreData()); } } QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, DataPaths::currentProfilePath()); connect(this, SIGNAL(messageReceived(QString)), this, SLOT(messageReceived(QString))); connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveSettings())); QTimer::singleShot(0, this, SLOT(postLaunch())); } MainApplication::~MainApplication() { m_isClosing = true; IconProvider::instance()->saveIconsToDatabase(); // Wait for all QtConcurrent jobs to finish QThreadPool::globalInstance()->waitForDone(); // Delete all classes that are saving data in destructor delete m_bookmarks; m_bookmarks = nullptr; delete m_cookieJar; m_cookieJar = nullptr; Settings::syncSettings(); } bool MainApplication::isClosing() const { return m_isClosing; } bool MainApplication::isPrivate() const { return m_isPrivate; } bool MainApplication::isPortable() const { #ifdef PORTABLE_BUILD return true; #else return m_isPortable; #endif } bool MainApplication::isStartingAfterCrash() const { return m_isStartingAfterCrash; } int MainApplication::windowCount() const { return m_windows.count(); } QList MainApplication::windows() const { return m_windows; } BrowserWindow* MainApplication::getWindow() const { if (m_lastActiveWindow) { return m_lastActiveWindow.data(); } return m_windows.isEmpty() ? 0 : m_windows.at(0); } BrowserWindow* MainApplication::createWindow(Qz::BrowserWindowType type, const QUrl &startUrl) { if (windowCount() == 0 && type != Qz::BW_MacFirstWindow) { type = Qz::BW_FirstAppWindow; } BrowserWindow* window = new BrowserWindow(type, startUrl); connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*))); m_windows.prepend(window); return window; } MainApplication::AfterLaunch MainApplication::afterLaunch() const { return static_cast(Settings().value(QSL("Web-URL-Settings/afterLaunch"), RestoreSession).toInt()); } void MainApplication::openSession(BrowserWindow* window, RestoreData &restoreData) { setOverrideCursor(Qt::BusyCursor); if (!window) window = createWindow(Qz::BW_OtherRestoredWindow); if (window->tabCount() != 0) { // This can only happen when recovering crashed session! // Don't restore tabs in current window as user already opened some new tabs. createWindow(Qz::BW_OtherRestoredWindow)->restoreWindow(restoreData.windows.takeAt(0)); } else { window->restoreWindow(restoreData.windows.takeAt(0)); } foreach (const BrowserWindow::SavedWindow &data, restoreData.windows) { BrowserWindow* window = createWindow(Qz::BW_OtherRestoredWindow); window->restoreWindow(data); } m_closedWindowsManager->restoreState(restoreData.closedWindows); restoreOverrideCursor(); } bool MainApplication::restoreSession(BrowserWindow* window, RestoreData restoreData) { if (m_isPrivate || !restoreData.isValid()) { return false; } openSession(window, restoreData); m_restoreManager->clearRestoreData(); destroyRestoreManager(); return true; } void MainApplication::destroyRestoreManager() { if (m_restoreManager && m_restoreManager->isValid()) { return; } delete m_restoreManager; m_restoreManager = 0; } void MainApplication::reloadSettings() { loadSettings(); emit settingsReloaded(); } QString MainApplication::styleName() const { return m_proxyStyle ? m_proxyStyle->name() : QString(); } void MainApplication::setProxyStyle(ProxyStyle *style) { m_proxyStyle = style; setStyle(style); } History* MainApplication::history() { if (!m_history) { m_history = new History(this); } return m_history; } Bookmarks* MainApplication::bookmarks() { if (!m_bookmarks) { m_bookmarks = new Bookmarks(this); } return m_bookmarks; } AutoFill* MainApplication::autoFill() { return m_autoFill; } CookieJar* MainApplication::cookieJar() { if (!m_cookieJar) { m_cookieJar = new CookieJar(this); } return m_cookieJar; } PluginProxy* MainApplication::plugins() { return m_plugins; } BrowsingLibrary* MainApplication::browsingLibrary() { if (!m_browsingLibrary) { m_browsingLibrary = new BrowsingLibrary(getWindow()); } return m_browsingLibrary; } NetworkManager *MainApplication::networkManager() { return m_networkManager; } RestoreManager* MainApplication::restoreManager() { return m_restoreManager; } SessionManager* MainApplication::sessionManager() { return m_sessionManager; } DownloadManager* MainApplication::downloadManager() { if (!m_downloadManager) { m_downloadManager = new DownloadManager(); } return m_downloadManager; } UserAgentManager* MainApplication::userAgentManager() { if (!m_userAgentManager) { m_userAgentManager = new UserAgentManager(this); } return m_userAgentManager; } SearchEnginesManager* MainApplication::searchEnginesManager() { if (!m_searchEnginesManager) { m_searchEnginesManager = new SearchEnginesManager(this); } return m_searchEnginesManager; } ClosedWindowsManager* MainApplication::closedWindowsManager() { if (!m_closedWindowsManager) { m_closedWindowsManager = new ClosedWindowsManager(this); } return m_closedWindowsManager; } HTML5PermissionsManager* MainApplication::html5PermissionsManager() { if (!m_html5PermissionsManager) { m_html5PermissionsManager = new HTML5PermissionsManager(this); } return m_html5PermissionsManager; } DesktopNotificationsFactory* MainApplication::desktopNotifications() { if (!m_desktopNotifications) { m_desktopNotifications = new DesktopNotificationsFactory(this); } return m_desktopNotifications; } QWebEngineProfile *MainApplication::webProfile() const { return m_webProfile; } QWebEngineSettings *MainApplication::webSettings() const { return m_webProfile->settings(); } // static MainApplication* MainApplication::instance() { return static_cast(QCoreApplication::instance()); } // static bool MainApplication::isTestModeEnabled() { return s_testMode; } // static void MainApplication::setTestModeEnabled(bool enabled) { s_testMode = enabled; } void MainApplication::addNewTab(const QUrl &url) { BrowserWindow* window = getWindow(); if (window) { window->tabWidget()->addView(url, url.isEmpty() ? Qz::NT_SelectedNewEmptyTab : Qz::NT_SelectedTabAtTheEnd); } } void MainApplication::startPrivateBrowsing(const QUrl &startUrl) { QUrl url = startUrl; if (QAction* act = qobject_cast(sender())) { url = act->data().toUrl(); } QStringList args; args.append(QSL("--private-browsing")); args.append(QSL("--profile=") + ProfileManager::currentProfile()); if (!url.isEmpty()) { args << url.toEncoded(); } if (!QProcess::startDetached(applicationFilePath(), args)) { qWarning() << "MainApplication: Cannot start new browser process for private browsing!" << applicationFilePath() << args; } } void MainApplication::reloadUserStyleSheet() { const QString userCssFile = Settings().value("Web-Browser-Settings/userStyleSheet", QString()).toString(); setUserStyleSheet(userCssFile); } void MainApplication::restoreOverrideCursor() { QApplication::restoreOverrideCursor(); } void MainApplication::changeOccurred() { if (m_autoSaver) m_autoSaver->changeOccurred(); } void MainApplication::quitApplication() { if (m_downloadManager && !m_downloadManager->canClose()) { m_downloadManager->show(); return; } for (BrowserWindow *window : qAsConst(m_windows)) { emit window->aboutToClose(); } if (m_sessionManager && m_windows.count() > 0) { m_sessionManager->autoSaveLastSession(); } m_isClosing = true; for (BrowserWindow *window : qAsConst(m_windows)) { window->close(); } // Saving settings in saveSettings() slot called from quit() so // everything gets saved also when quitting application in other // way than clicking Quit action in File menu or closing last window // eg. on Mac (#157) if (!isPrivate()) { removeLockFile(); } quit(); } void MainApplication::postLaunch() { if (m_postLaunchActions.contains(OpenDownloadManager)) { downloadManager()->show(); } if (m_postLaunchActions.contains(OpenNewTab)) { getWindow()->tabWidget()->addView(QUrl(), Qz::NT_SelectedNewEmptyTab); } if (m_postLaunchActions.contains(ToggleFullScreen)) { getWindow()->toggleFullScreen(); } createJumpList(); initPulseSupport(); QTimer::singleShot(5000, this, &MainApplication::runDeferredPostLaunchActions); } QByteArray MainApplication::saveState() const { RestoreData restoreData; restoreData.windows.reserve(m_windows.count()); for (BrowserWindow *window : qAsConst(m_windows)) { restoreData.windows.append(BrowserWindow::SavedWindow(window)); } if (m_restoreManager && m_restoreManager->isValid()) { QDataStream stream(&restoreData.crashedSession, QIODevice::WriteOnly); stream << m_restoreManager->restoreData(); } restoreData.closedWindows = m_closedWindowsManager->saveState(); QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); stream << Qz::sessionVersion; stream << restoreData; return data; } void MainApplication::saveSettings() { if (isPrivate()) { return; } m_isClosing = true; Settings settings; settings.beginGroup("SessionRestore"); settings.setValue("isRunning", false); settings.setValue("isRestoring", false); settings.endGroup(); settings.beginGroup("Web-Browser-Settings"); bool deleteCache = settings.value("deleteCacheOnClose", false).toBool(); bool deleteHistory = settings.value("deleteHistoryOnClose", false).toBool(); bool deleteHtml5Storage = settings.value("deleteHTML5StorageOnClose", false).toBool(); settings.endGroup(); settings.beginGroup("Cookie-Settings"); bool deleteCookies = settings.value("deleteCookiesOnClose", false).toBool(); settings.endGroup(); if (deleteHistory) { m_history->clearHistory(); } if (deleteHtml5Storage) { ClearPrivateData::clearLocalStorage(); } if (deleteCookies) { m_cookieJar->deleteAllCookies(); } if (deleteCache) { QzTools::removeRecursively(mApp->webProfile()->cachePath()); } m_searchEnginesManager->saveSettings(); m_plugins->shutdown(); m_networkManager->shutdown(); qzSettings->saveSettings(); QFile::remove(DataPaths::currentProfilePath() + QLatin1String("/WebpageIcons.db")); sessionManager()->saveSettings(); } void MainApplication::messageReceived(const QString &message) { QWidget* actWin = getWindow(); QUrl actUrl; if (message.startsWith(QLatin1String("URL:"))) { const QUrl url = QUrl::fromUserInput(message.mid(4)); addNewTab(url); actWin = getWindow(); } else if (message.startsWith(QLatin1String("ACTION:"))) { const QString text = message.mid(7); if (text == QLatin1String("NewTab")) { addNewTab(); } else if (text == QLatin1String("NewWindow")) { actWin = createWindow(Qz::BW_NewWindow); } else if (text == QLatin1String("ShowDownloadManager")) { downloadManager()->show(); actWin = downloadManager(); } else if (text == QLatin1String("ToggleFullScreen") && actWin) { BrowserWindow* qz = static_cast(actWin); qz->toggleFullScreen(); } else if (text.startsWith(QLatin1String("OpenUrlInCurrentTab"))) { actUrl = QUrl::fromUserInput(text.mid(19)); } else if (text.startsWith(QLatin1String("OpenUrlInNewWindow"))) { createWindow(Qz::BW_NewWindow, QUrl::fromUserInput(text.mid(18))); return; } } else { // User attempted to start another instance, let's open a new window actWin = createWindow(Qz::BW_NewWindow); } if (!actWin) { if (!isClosing()) { // It can only occur if download manager window was still opened createWindow(Qz::BW_NewWindow, actUrl); } return; } actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); actWin->raise(); actWin->activateWindow(); actWin->setFocus(); BrowserWindow* win = qobject_cast(actWin); if (win && !actUrl.isEmpty()) { win->loadAddress(actUrl); } } void MainApplication::windowDestroyed(QObject* window) { // qobject_cast doesn't work because QObject::destroyed is emitted from destructor Q_ASSERT(static_cast(window)); Q_ASSERT(m_windows.contains(static_cast(window))); m_windows.removeOne(static_cast(window)); } void MainApplication::onFocusChanged() { BrowserWindow* activeBrowserWindow = qobject_cast(activeWindow()); if (activeBrowserWindow) { m_lastActiveWindow = activeBrowserWindow; emit activeWindowChanged(m_lastActiveWindow); } } void MainApplication::runDeferredPostLaunchActions() { checkDefaultWebBrowser(); checkOptimizeDatabase(); } void MainApplication::downloadRequested(QWebEngineDownloadItem *download) { downloadManager()->download(download); } void MainApplication::loadSettings() { Settings settings; settings.beginGroup("Themes"); QString activeTheme = settings.value("activeTheme", DEFAULT_THEME_NAME).toString(); settings.endGroup(); loadTheme(activeTheme); QWebEngineSettings* webSettings = m_webProfile->settings(); // Web browsing settings settings.beginGroup("Web-Browser-Settings"); webSettings->setAttribute(QWebEngineSettings::LocalStorageEnabled, settings.value("HTML5StorageEnabled", true).toBool()); webSettings->setAttribute(QWebEngineSettings::PluginsEnabled, settings.value("allowPlugins", true).toBool()); webSettings->setAttribute(QWebEngineSettings::JavascriptEnabled, settings.value("allowJavaScript", true).toBool()); webSettings->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, settings.value("allowJavaScriptOpenWindow", false).toBool()); webSettings->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, settings.value("allowJavaScriptAccessClipboard", true).toBool()); webSettings->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, settings.value("IncludeLinkInFocusChain", false).toBool()); webSettings->setAttribute(QWebEngineSettings::XSSAuditingEnabled, settings.value("XSSAuditing", false).toBool()); webSettings->setAttribute(QWebEngineSettings::PrintElementBackgrounds, settings.value("PrintElementBackground", true).toBool()); webSettings->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, settings.value("SpatialNavigation", false).toBool()); webSettings->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, settings.value("AnimateScrolling", true).toBool()); webSettings->setAttribute(QWebEngineSettings::HyperlinkAuditingEnabled, false); webSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); webSettings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); webSettings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 10, 0) webSettings->setAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript, settings.value("allowJavaScriptActivateWindow", false).toBool()); #endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 11, 0) webSettings->setAttribute(QWebEngineSettings::JavascriptCanPaste, settings.value("allowJavaScriptPaste", true).toBool()); webSettings->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, settings.value("DisableVideoAutoPlay", false).toBool()); webSettings->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, settings.value("WebRTCPublicIpOnly", true).toBool()); webSettings->setUnknownUrlSchemePolicy(QWebEngineSettings::AllowAllUnknownUrlSchemes); #endif webSettings->setDefaultTextEncoding(settings.value("DefaultEncoding", webSettings->defaultTextEncoding()).toString()); setWheelScrollLines(settings.value("wheelScrollLines", wheelScrollLines()).toInt()); const QString userCss = settings.value("userStyleSheet", QString()).toString(); settings.endGroup(); setUserStyleSheet(userCss); settings.beginGroup("Browser-Fonts"); webSettings->setFontFamily(QWebEngineSettings::StandardFont, settings.value("StandardFont", webSettings->fontFamily(QWebEngineSettings::StandardFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::CursiveFont, settings.value("CursiveFont", webSettings->fontFamily(QWebEngineSettings::CursiveFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::FantasyFont, settings.value("FantasyFont", webSettings->fontFamily(QWebEngineSettings::FantasyFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::FixedFont, settings.value("FixedFont", webSettings->fontFamily(QWebEngineSettings::FixedFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::SansSerifFont, settings.value("SansSerifFont", webSettings->fontFamily(QWebEngineSettings::SansSerifFont)).toString()); webSettings->setFontFamily(QWebEngineSettings::SerifFont, settings.value("SerifFont", webSettings->fontFamily(QWebEngineSettings::SerifFont)).toString()); webSettings->setFontSize(QWebEngineSettings::DefaultFontSize, settings.value("DefaultFontSize", 15).toInt()); webSettings->setFontSize(QWebEngineSettings::DefaultFixedFontSize, settings.value("FixedFontSize", 14).toInt()); webSettings->setFontSize(QWebEngineSettings::MinimumFontSize, settings.value("MinimumFontSize", 3).toInt()); webSettings->setFontSize(QWebEngineSettings::MinimumLogicalFontSize, settings.value("MinimumLogicalFontSize", 5).toInt()); settings.endGroup(); QWebEngineProfile* profile = QWebEngineProfile::defaultProfile(); profile->setPersistentCookiesPolicy(QWebEngineProfile::AllowPersistentCookies); profile->setPersistentStoragePath(DataPaths::currentProfilePath()); QString defaultPath = DataPaths::path(DataPaths::Cache); if (!defaultPath.startsWith(DataPaths::currentProfilePath())) defaultPath.append(QLatin1Char('/') + ProfileManager::currentProfile()); const QString &cachePath = settings.value("Web-Browser-Settings/CachePath", defaultPath).toString(); profile->setCachePath(cachePath); const bool allowCache = settings.value(QSL("Web-Browser-Settings/AllowLocalCache"), true).toBool(); profile->setHttpCacheType(allowCache ? QWebEngineProfile::DiskHttpCache : QWebEngineProfile::MemoryHttpCache); const int cacheSize = settings.value(QSL("Web-Browser-Settings/LocalCacheSize"), 50).toInt() * 1000 * 1000; profile->setHttpCacheMaximumSize(cacheSize); settings.beginGroup(QSL("SpellCheck")); profile->setSpellCheckEnabled(settings.value(QSL("Enabled"), false).toBool()); profile->setSpellCheckLanguages(settings.value(QSL("Languages")).toStringList()); settings.endGroup(); if (isPrivate()) { webSettings->setAttribute(QWebEngineSettings::LocalStorageEnabled, false); history()->setSaving(false); } if (m_downloadManager) { m_downloadManager->loadSettings(); } qzSettings->loadSettings(); userAgentManager()->loadSettings(); networkManager()->loadSettings(); } void MainApplication::loadTheme(const QString &name) { QString activeThemePath = DataPaths::locate(DataPaths::Themes, name); if (activeThemePath.isEmpty()) { qWarning() << "Cannot load theme " << name; activeThemePath = QString("%1/%2").arg(DataPaths::path(DataPaths::Themes), DEFAULT_THEME_NAME); } QString qss = QzTools::readAllFileContents(activeThemePath + QLatin1String("/main.css")); #if defined(Q_OS_MACOS) qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/mac.css"))); #elif defined(Q_OS_UNIX) qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/linux.css"))); #elif defined(Q_OS_WIN) || defined(Q_OS_OS2) qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/windows.css"))); #endif if (isRightToLeft()) { qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/rtl.css"))); } if (isPrivate()) { qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/private.css"))); } qss.append(QzTools::readAllFileContents(DataPaths::currentProfilePath() + QL1S("/userChrome.css"))); QString relativePath = QDir::current().relativeFilePath(activeThemePath); qss.replace(QRegularExpression(QSL("url\\s*\\(\\s*([^\\*:\\);]+)\\s*\\)")), QString("url(%1/\\1)").arg(relativePath)); setStyleSheet(qss); } void MainApplication::checkDefaultWebBrowser() { if (isPortable()) { return; } #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) Settings settings; bool checkNow = settings.value("Web-Browser-Settings/CheckDefaultBrowser", DEFAULT_CHECK_DEFAULTBROWSER).toBool(); if (!checkNow) { return; } bool checkAgain = true; if (!associationManager()->isDefaultForAllCapabilities()) { CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, getWindow()); dialog.setDefaultButton(QMessageBox::Yes); dialog.setText(tr("Falkon is not currently your default browser. Would you like to make it your default browser?")); dialog.setCheckBoxText(tr("Always perform this check when starting Falkon.")); dialog.setDefaultCheckState(Qt::Checked); dialog.setWindowTitle(tr("Default Browser")); dialog.setIcon(QMessageBox::Warning); if (dialog.exec() == QMessageBox::Yes) { if (!mApp->associationManager()->showNativeDefaultAppSettingsUi()) mApp->associationManager()->registerAllAssociation(); } checkAgain = dialog.isChecked(); } settings.setValue("Web-Browser-Settings/CheckDefaultBrowser", checkAgain); #endif } void MainApplication::checkOptimizeDatabase() { Settings settings; settings.beginGroup(QSL("Browser")); const int numberOfRuns = settings.value(QSL("RunsWithoutOptimizeDb"), 0).toInt(); settings.setValue(QSL("RunsWithoutOptimizeDb"), numberOfRuns + 1); if (numberOfRuns > 20) { std::cout << "Optimizing database..." << std::endl; IconProvider::instance()->clearOldIconsInDatabase(); settings.setValue(QSL("RunsWithoutOptimizeDb"), 0); } settings.endGroup(); } void MainApplication::setupUserScripts() { // WebChannel for SafeJsWorld QWebEngineScript script; script.setName(QSL("_falkon_webchannel")); script.setInjectionPoint(QWebEngineScript::DocumentCreation); script.setWorldId(WebPage::SafeJsWorld); script.setRunsOnSubFrames(true); script.setSourceCode(Scripts::setupWebChannel()); m_webProfile->scripts()->insert(script); // falkon:restore QWebEngineScript falkonRestore; falkonRestore.setWorldId(WebPage::SafeJsWorld); falkonRestore.setSourceCode(QzTools::readAllFileContents(QSL(":html/restore.user.js"))); m_webProfile->scripts()->insert(falkonRestore); // falkon:speeddial QWebEngineScript falkonSpeedDial; falkonSpeedDial.setWorldId(WebPage::SafeJsWorld); falkonSpeedDial.setSourceCode(Scripts::setupSpeedDial()); m_webProfile->scripts()->insert(falkonSpeedDial); // document.window object addons QWebEngineScript documentWindowAddons; documentWindowAddons.setName(QSL("_falkon_window_object")); documentWindowAddons.setInjectionPoint(QWebEngineScript::DocumentCreation); documentWindowAddons.setWorldId(WebPage::UnsafeJsWorld); documentWindowAddons.setRunsOnSubFrames(true); documentWindowAddons.setSourceCode(Scripts::setupWindowObject()); m_webProfile->scripts()->insert(documentWindowAddons); } void MainApplication::setUserStyleSheet(const QString &filePath) { QString userCss; #if !defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) // Don't grey out selection on losing focus (to prevent graying out found text) QString highlightColor; QString highlightedTextColor; #ifdef Q_OS_MACOS highlightColor = QLatin1String("#b6d6fc"); highlightedTextColor = QLatin1String("#000"); #else QPalette pal = style()->standardPalette(); highlightColor = pal.color(QPalette::Highlight).name(); highlightedTextColor = pal.color(QPalette::HighlightedText).name(); #endif userCss += QString("::selection {background: %1; color: %2;} ").arg(highlightColor, highlightedTextColor); #endif userCss += QzTools::readAllFileContents(filePath).remove(QLatin1Char('\n')); const QString name = QStringLiteral("_falkon_userstylesheet"); QWebEngineScript oldScript = m_webProfile->scripts()->findScript(name); if (!oldScript.isNull()) { m_webProfile->scripts()->remove(oldScript); } if (userCss.isEmpty()) return; QWebEngineScript script; script.setName(name); script.setInjectionPoint(QWebEngineScript::DocumentReady); script.setWorldId(WebPage::SafeJsWorld); script.setRunsOnSubFrames(true); script.setSourceCode(Scripts::setCss(userCss)); m_webProfile->scripts()->insert(script); } void MainApplication::createJumpList() { #ifdef Q_OS_WIN QWinJumpList *jumpList = new QWinJumpList(this); jumpList->clear(); // Frequent QWinJumpListCategory *frequent = jumpList->frequent(); frequent->setVisible(true); const QVector mostList = m_history->mostVisited(7); for (const HistoryEntry &entry : mostList) { frequent->addLink(IconProvider::iconForUrl(entry.url), entry.title, applicationFilePath(), QStringList{entry.url.toEncoded()}); } // Tasks QWinJumpListCategory *tasks = jumpList->tasks(); tasks->setVisible(true); tasks->addLink(IconProvider::newTabIcon(), tr("Open new tab"), applicationFilePath(), {QSL("--new-tab")}); tasks->addLink(IconProvider::newWindowIcon(), tr("Open new window"), applicationFilePath(), {QSL("--new-window")}); tasks->addLink(IconProvider::privateBrowsingIcon(), tr("Open new private window"), applicationFilePath(), {QSL("--private-browsing")}); #endif } void MainApplication::initPulseSupport() { qputenv("PULSE_PROP_OVERRIDE_application.name", "Falkon"); qputenv("PULSE_PROP_OVERRIDE_application.icon_name", "falkon"); qputenv("PULSE_PROP_OVERRIDE_media.icon_name", "falkon"); } #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) RegisterQAppAssociation* MainApplication::associationManager() { if (!m_registerQAppAssociation) { QString desc = tr("Falkon is a new and very fast Qt web browser. Falkon is licensed under GPL version 3 or (at your option) any later version. It is based on QtWebEngine and Qt Framework."); QString fileIconPath = QApplication::applicationFilePath() + ",1"; QString appIconPath = QApplication::applicationFilePath() + ",0"; m_registerQAppAssociation = new RegisterQAppAssociation("Falkon", QApplication::applicationFilePath(), appIconPath, desc, this); m_registerQAppAssociation->addCapability(".html", "FalkonHTML", "Falkon HTML Document", fileIconPath, RegisterQAppAssociation::FileAssociation); m_registerQAppAssociation->addCapability(".htm", "FalkonHTML", "Falkon HTML Document", fileIconPath, RegisterQAppAssociation::FileAssociation); m_registerQAppAssociation->addCapability("http", "FalkonURL", "Falkon URL", appIconPath, RegisterQAppAssociation::UrlAssociation); m_registerQAppAssociation->addCapability("https", "FalkonURL", "Falkon URL", appIconPath, RegisterQAppAssociation::UrlAssociation); m_registerQAppAssociation->addCapability("ftp", "FalkonURL", "Falkon URL", appIconPath, RegisterQAppAssociation::UrlAssociation); } return m_registerQAppAssociation; } #endif #ifdef Q_OS_MACOS #include bool MainApplication::event(QEvent* e) { switch (e->type()) { case QEvent::FileOpen: { QFileOpenEvent *ev = static_cast(e); if (!ev->url().isEmpty()) { addNewTab(ev->url()); } else if (!ev->file().isEmpty()) { addNewTab(QUrl::fromLocalFile(ev->file())); } else { return false; } return true; } case QEvent::ApplicationActivate: if (!activeWindow() && m_windows.isEmpty()) createWindow(Qz::BW_NewWindow); break; default: break; } return QtSingleApplication::event(e); } #endif diff --git a/src/lib/app/qzcommon.h b/src/lib/app/qzcommon.h index fe49aff5..a6d008b9 100644 --- a/src/lib/app/qzcommon.h +++ b/src/lib/app/qzcommon.h @@ -1,138 +1,139 @@ /* ============================================================ * 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 . * ============================================================ */ #ifndef QZCOMMON_H #define QZCOMMON_H #include #include +#include #ifdef FALKON_SHAREDLIBRARY #define FALKON_EXPORT Q_DECL_EXPORT #else #define FALKON_EXPORT Q_DECL_IMPORT #endif #ifndef Q_UNLIKELY #define Q_UNLIKELY(x) x #endif #ifndef Q_LIKELY #define Q_LIKELY(x) x #endif #ifndef QSL #define QSL(x) QStringLiteral(x) #endif #ifndef QL1S #define QL1S(x) QLatin1String(x) #endif #ifndef QL1C #define QL1C(x) QLatin1Char(x) #endif namespace Qz { // Version of session.dat file extern const int sessionVersion; FALKON_EXPORT extern const char *APPNAME; FALKON_EXPORT extern const char *VERSION; FALKON_EXPORT extern const char *AUTHOR; FALKON_EXPORT extern const char *COPYRIGHT; FALKON_EXPORT extern const char *WWWADDRESS; FALKON_EXPORT extern const char *BUGSADDRESS; FALKON_EXPORT extern const char *WIKIADDRESS; enum BrowserWindowType { BW_FirstAppWindow, BW_OtherRestoredWindow, BW_NewWindow, BW_MacFirstWindow }; enum CommandLineAction { CL_NoAction, CL_OpenUrl, CL_OpenUrlInCurrentTab, CL_OpenUrlInNewWindow, CL_StartWithProfile, CL_StartWithoutAddons, CL_NewTab, CL_NewWindow, CL_ShowDownloadManager, CL_ToggleFullScreen, CL_StartPrivateBrowsing, CL_StartNewInstance, CL_StartPortable, CL_ExitAction }; enum ObjectName { ON_WebView, ON_TabBar, ON_TabWidget, ON_BrowserWindow }; enum NewTabPositionFlag { NT_SelectedTab = 1, NT_NotSelectedTab = 2, NT_CleanTab = 4, NT_TabAtTheEnd = 8, NT_NewEmptyTab = 16, NT_SelectedNewEmptyTab = NT_SelectedTab | NT_TabAtTheEnd | NT_NewEmptyTab, NT_SelectedTabAtTheEnd = NT_SelectedTab | NT_TabAtTheEnd, NT_NotSelectedTabAtTheEnd = NT_NotSelectedTab | NT_TabAtTheEnd, NT_CleanSelectedTabAtTheEnd = NT_SelectedTab | NT_TabAtTheEnd | NT_CleanTab, NT_CleanSelectedTab = NT_CleanTab | NT_SelectedTab, NT_CleanNotSelectedTab = NT_CleanTab | NT_NotSelectedTab }; Q_DECLARE_FLAGS(NewTabPositionFlags, NewTabPositionFlag) Q_DECLARE_OPERATORS_FOR_FLAGS(Qz::NewTabPositionFlags) } #if defined(Q_OS_WIN) || defined(Q_OS_OS2) #define DEFAULT_THEME_NAME "windows" #elif defined(Q_OS_MACOS) #define DEFAULT_THEME_NAME "mac" #elif defined(Q_OS_UNIX) #define DEFAULT_THEME_NAME "linux" #else #define DEFAULT_THEME_NAME "default" #endif #ifdef Q_OS_WIN #define DISABLE_CHECK_UPDATES false #else #define DISABLE_CHECK_UPDATES true #endif #define DEFAULT_CHECK_DEFAULTBROWSER false #ifdef Q_OS_WIN #define DEFAULT_DOWNLOAD_USE_NATIVE_DIALOG false #else #define DEFAULT_DOWNLOAD_USE_NATIVE_DIALOG true #endif #endif // QZCOMMON_H diff --git a/src/lib/cookies/cookiejar.cpp b/src/lib/cookies/cookiejar.cpp index ac87aa94..f8688e8e 100644 --- a/src/lib/cookies/cookiejar.cpp +++ b/src/lib/cookies/cookiejar.cpp @@ -1,208 +1,208 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2017 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 "cookiejar.h" #include "mainapplication.h" #include "datapaths.h" #include "autosaver.h" #include "settings.h" #include "qztools.h" #include #include #include #include //#define COOKIE_DEBUG CookieJar::CookieJar(QObject* parent) : QObject(parent) , m_client(mApp->webProfile()->cookieStore()) { loadSettings(); m_client->loadAllCookies(); -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 11, 0) m_client->setCookieFilter(std::bind(&CookieJar::cookieFilter, this, std::placeholders::_1)); #endif connect(m_client, &QWebEngineCookieStore::cookieAdded, this, &CookieJar::slotCookieAdded); connect(m_client, &QWebEngineCookieStore::cookieRemoved, this, &CookieJar::slotCookieRemoved); } CookieJar::~CookieJar() { -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 11, 0) m_client->setCookieFilter(nullptr); #endif } void CookieJar::loadSettings() { Settings settings; settings.beginGroup("Cookie-Settings"); m_allowCookies = settings.value("allowCookies", true).toBool(); m_filterThirdParty = settings.value("filterThirdPartyCookies", false).toBool(); m_filterTrackingCookie = settings.value("filterTrackingCookie", false).toBool(); m_whitelist = settings.value("whitelist", QStringList()).toStringList(); m_blacklist = settings.value("blacklist", QStringList()).toStringList(); settings.endGroup(); } void CookieJar::setAllowCookies(bool allow) { m_allowCookies = allow; } void CookieJar::deleteCookie(const QNetworkCookie &cookie) { m_client->deleteCookie(cookie); } QVector CookieJar::getAllCookies() const { return m_cookies; } void CookieJar::deleteAllCookies() { m_client->deleteAllCookies(); } bool CookieJar::matchDomain(QString cookieDomain, QString siteDomain) const { // According to RFC 6265 // Remove leading dot if (cookieDomain.startsWith(QLatin1Char('.'))) { cookieDomain = cookieDomain.mid(1); } if (siteDomain.startsWith(QLatin1Char('.'))) { siteDomain = siteDomain.mid(1); } return QzTools::matchDomain(cookieDomain, siteDomain); } bool CookieJar::listMatchesDomain(const QStringList &list, const QString &cookieDomain) const { foreach (const QString &d, list) { if (matchDomain(d, cookieDomain)) { return true; } } return false; } void CookieJar::slotCookieAdded(const QNetworkCookie &cookie) { if (rejectCookie(QString(), cookie, cookie.domain())) { m_client->deleteCookie(cookie); return; } m_cookies.append(cookie); emit cookieAdded(cookie); } void CookieJar::slotCookieRemoved(const QNetworkCookie &cookie) { if (m_cookies.removeOne(cookie)) emit cookieRemoved(cookie); } -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 11, 0) bool CookieJar::cookieFilter(const QWebEngineCookieStore::FilterRequest &request) const { if (!m_allowCookies) { bool result = listMatchesDomain(m_whitelist, request.origin.host()); if (!result) { #ifdef COOKIE_DEBUG qDebug() << "not in whitelist" << request.origin; #endif return false; } } if (m_allowCookies) { bool result = listMatchesDomain(m_blacklist, request.origin.host()); if (result) { #ifdef COOKIE_DEBUG qDebug() << "found in blacklist" << request.origin.host(); #endif return false; } } if (m_filterThirdParty && request.thirdParty) { #ifdef COOKIE_DEBUG qDebug() << "thirdParty" << request.firstPartyUrl << request.origin; #endif return false; } return true; } #endif bool CookieJar::rejectCookie(const QString &domain, const QNetworkCookie &cookie, const QString &cookieDomain) const { Q_UNUSED(domain) if (!m_allowCookies) { bool result = listMatchesDomain(m_whitelist, cookieDomain); if (!result) { #ifdef COOKIE_DEBUG qDebug() << "not in whitelist" << cookie; #endif return true; } } if (m_allowCookies) { bool result = listMatchesDomain(m_blacklist, cookieDomain); if (result) { #ifdef COOKIE_DEBUG qDebug() << "found in blacklist" << cookie; #endif return true; } } #ifdef QTWEBENGINE_DISABLED if (m_filterThirdParty) { bool result = matchDomain(cookieDomain, domain); if (!result) { #ifdef COOKIE_DEBUG qDebug() << "purged for domain mismatch" << cookie << cookieDomain << domain; #endif return true; } } #endif if (m_filterTrackingCookie && cookie.name().startsWith("__utm")) { #ifdef COOKIE_DEBUG qDebug() << "purged as tracking " << cookie; #endif return true; } return false; } diff --git a/src/lib/cookies/cookiejar.h b/src/lib/cookies/cookiejar.h index bbb04150..9fcde650 100644 --- a/src/lib/cookies/cookiejar.h +++ b/src/lib/cookies/cookiejar.h @@ -1,76 +1,76 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2016 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 . * ============================================================ */ #ifndef COOKIEJAR_H #define COOKIEJAR_H #include #include #include #include "qzcommon.h" class AutoSaver; class FALKON_EXPORT CookieJar : public QObject { Q_OBJECT public: explicit CookieJar(QObject* parent = 0); ~CookieJar(); void loadSettings(); void setAllowCookies(bool allow); void deleteCookie(const QNetworkCookie &cookie); QVector getAllCookies() const; void deleteAllCookies(); Q_SIGNALS: void cookieAdded(const QNetworkCookie &cookie); void cookieRemoved(const QNetworkCookie &cookie); protected: bool matchDomain(QString cookieDomain, QString siteDomain) const; bool listMatchesDomain(const QStringList &list, const QString &cookieDomain) const; private: void slotCookieAdded(const QNetworkCookie &cookie); void slotCookieRemoved(const QNetworkCookie &cookie); -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 11, 0) bool cookieFilter(const QWebEngineCookieStore::FilterRequest &request) const; #endif bool acceptCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &cookieSource) const; bool rejectCookie(const QString &domain, const QNetworkCookie &cookie, const QString &cookieDomain) const; bool m_allowCookies; bool m_filterTrackingCookie; bool m_filterThirdParty; QStringList m_whitelist; QStringList m_blacklist; QWebEngineCookieStore *m_client; QVector m_cookies; }; #endif // COOKIEJAR_H diff --git a/src/lib/cookies/cookiemanager.cpp b/src/lib/cookies/cookiemanager.cpp index dd4a65f5..96579af2 100644 --- a/src/lib/cookies/cookiemanager.cpp +++ b/src/lib/cookies/cookiemanager.cpp @@ -1,358 +1,358 @@ /* ============================================================ * 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 "cookiemanager.h" #include "ui_cookiemanager.h" #include "browserwindow.h" #include "cookiejar.h" #include "mainapplication.h" #include "qztools.h" #include "settings.h" #include "iconprovider.h" #include #include #include #include #include #include #include CookieManager::CookieManager(QWidget *parent) : QDialog(parent) , ui(new Ui::CookieManager) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); QzTools::centerWidgetOnScreen(this); if (isRightToLeft()) { ui->cookieTree->headerItem()->setTextAlignment(0, Qt::AlignRight | Qt::AlignVCenter); ui->cookieTree->headerItem()->setTextAlignment(1, Qt::AlignRight | Qt::AlignVCenter); ui->cookieTree->setLayoutDirection(Qt::LeftToRight); ui->whiteList->setLayoutDirection(Qt::LeftToRight); ui->blackList->setLayoutDirection(Qt::LeftToRight); } // Stored Cookies connect(ui->cookieTree, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*))); connect(ui->removeAll, SIGNAL(clicked()), this, SLOT(removeAll())); connect(ui->removeOne, SIGNAL(clicked()), this, SLOT(remove())); connect(ui->close, SIGNAL(clicked(QAbstractButton*)), this, SLOT(close())); connect(ui->close2, SIGNAL(clicked(QAbstractButton*)), this, SLOT(close())); connect(ui->close3, SIGNAL(clicked(QAbstractButton*)), this, SLOT(close())); connect(ui->search, SIGNAL(textChanged(QString)), this, SLOT(filterString(QString))); // Cookie Filtering connect(ui->whiteAdd, SIGNAL(clicked()), this, SLOT(addWhitelist())); connect(ui->whiteRemove, SIGNAL(clicked()), this, SLOT(removeWhitelist())); connect(ui->blackAdd, SIGNAL(clicked()), this, SLOT(addBlacklist())); connect(ui->blackRemove, SIGNAL(clicked()), this, SLOT(removeBlacklist())); // Cookie Settings Settings settings; settings.beginGroup("Cookie-Settings"); ui->saveCookies->setChecked(settings.value("allowCookies", true).toBool()); ui->filter3rdParty->setChecked(settings.value("filterThirdPartyCookies", false).toBool()); ui->filterTracking->setChecked(settings.value("filterTrackingCookie", false).toBool()); ui->deleteCookiesOnClose->setChecked(settings.value("deleteCookiesOnClose", false).toBool()); ui->whiteList->addItems(settings.value("whitelist", QStringList()).toStringList()); ui->blackList->addItems(settings.value("blacklist", QStringList()).toStringList()); settings.endGroup(); -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION < QT_VERSION_CHECK(5, 11, 0) ui->filter3rdParty->hide(); #endif ui->search->setPlaceholderText(tr("Search")); ui->cookieTree->setDefaultItemShowMode(TreeWidget::ItemsCollapsed); ui->cookieTree->sortItems(0, Qt::AscendingOrder); ui->cookieTree->header()->setDefaultSectionSize(220); ui->cookieTree->setFocus(); QShortcut* removeShortcut = new QShortcut(QKeySequence("Del"), this); connect(removeShortcut, SIGNAL(activated()), this, SLOT(deletePressed())); connect(ui->search, SIGNAL(textChanged(QString)), this, SLOT(filterString(QString))); connect(mApp->cookieJar(), &CookieJar::cookieAdded, this, &CookieManager::addCookie); connect(mApp->cookieJar(), &CookieJar::cookieRemoved, this, &CookieManager::removeCookie); // Load cookies foreach (const QNetworkCookie &cookie, mApp->cookieJar()->getAllCookies()) addCookie(cookie); QzTools::setWmClass("Cookies", this); } void CookieManager::removeAll() { QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Confirmation"), tr("Are you sure you want to delete all cookies on your computer?"), QMessageBox::Yes | QMessageBox::No); if (button != QMessageBox::Yes) { return; } mApp->cookieJar()->deleteAllCookies(); m_itemHash.clear(); m_domainHash.clear(); ui->cookieTree->clear(); } void CookieManager::remove() { QTreeWidgetItem* current = ui->cookieTree->currentItem(); if (!current) { return; } QList cookies; if (current->childCount()) { for (int i = 0; i < current->childCount(); ++i) { QTreeWidgetItem *item = current->child(i); if (item && m_itemHash.contains(item)) { cookies.append(m_itemHash.value(item)); } } } else if (m_itemHash.contains(current)) { cookies.append(m_itemHash.value(current)); } foreach (const QNetworkCookie &cookie, cookies) { mApp->cookieJar()->deleteCookie(cookie); } } void CookieManager::currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* parent) { Q_UNUSED(parent); if (!current) { return; } if (current->text(1).isEmpty()) { ui->name->setText(tr("")); ui->value->setText(tr("")); ui->server->setText(tr("")); ui->path->setText(tr("")); ui->secure->setText(tr("")); ui->expiration->setText(tr("")); ui->removeOne->setText(tr("Remove cookies")); return; } const QNetworkCookie cookie = qvariant_cast(current->data(0, Qt::UserRole + 10)); ui->name->setText(cookie.name()); ui->value->setText(cookie.value()); ui->server->setText(cookie.domain()); ui->path->setText(cookie.path()); cookie.isSecure() ? ui->secure->setText(tr("Secure only")) : ui->secure->setText(tr("All connections")); cookie.isSessionCookie() ? ui->expiration->setText(tr("Session cookie")) : ui->expiration->setText(QDateTime(cookie.expirationDate()).toString("hh:mm:ss dddd d. MMMM yyyy")); ui->removeOne->setText(tr("Remove cookie")); } void CookieManager::addWhitelist() { const QString server = QInputDialog::getText(this, tr("Add to whitelist"), tr("Server:")); if (server.isEmpty()) { return; } if (!ui->blackList->findItems(server, Qt::MatchFixedString).isEmpty()) { QMessageBox::information(this, tr("Already blacklisted!"), tr("The server \"%1\" is already in blacklist, please remove it first.").arg(server)); return; } if (ui->whiteList->findItems(server, Qt::MatchFixedString).isEmpty()) { ui->whiteList->addItem(server); } } void CookieManager::removeWhitelist() { delete ui->whiteList->currentItem(); } void CookieManager::addBlacklist() { const QString server = QInputDialog::getText(this, tr("Add to blacklist"), tr("Server:")); addBlacklist(server); } void CookieManager::addBlacklist(const QString &server) { if (server.isEmpty()) { return; } if (!ui->whiteList->findItems(server, Qt::MatchFixedString).isEmpty()) { QMessageBox::information(this, tr("Already whitelisted!"), tr("The server \"%1\" is already in whitelist, please remove it first.").arg(server)); return; } if (ui->blackList->findItems(server, Qt::MatchFixedString).isEmpty()) { ui->blackList->addItem(server); } } QString CookieManager::cookieDomain(const QNetworkCookie &cookie) const { QString domain = cookie.domain(); if (domain.startsWith(QLatin1Char('.'))) { domain = domain.mid(1); } return domain; } QTreeWidgetItem *CookieManager::cookieItem(const QNetworkCookie &cookie) const { QHashIterator it(m_itemHash); while (it.hasNext()) { it.next(); if (it.value() == cookie) return it.key(); } return Q_NULLPTR; } void CookieManager::removeBlacklist() { delete ui->blackList->currentItem(); } void CookieManager::deletePressed() { if (ui->cookieTree->hasFocus()) { remove(); } else if (ui->whiteList->hasFocus()) { removeWhitelist(); } else if (ui->blackList->hasFocus()) { removeBlacklist(); } } void CookieManager::filterString(const QString &string) { if (string.isEmpty()) { for (int i = 0; i < ui->cookieTree->topLevelItemCount(); ++i) { ui->cookieTree->topLevelItem(i)->setHidden(false); ui->cookieTree->topLevelItem(i)->setExpanded(ui->cookieTree->defaultItemShowMode() == TreeWidget::ItemsExpanded); } } else { for (int i = 0; i < ui->cookieTree->topLevelItemCount(); ++i) { QString text = "." + ui->cookieTree->topLevelItem(i)->text(0); ui->cookieTree->topLevelItem(i)->setHidden(!text.contains(string, Qt::CaseInsensitive)); ui->cookieTree->topLevelItem(i)->setExpanded(true); } } } void CookieManager::addCookie(const QNetworkCookie &cookie) { QTreeWidgetItem* item; const QString domain = cookieDomain(cookie); QTreeWidgetItem* findParent = m_domainHash.value(domain); if (findParent) { item = new QTreeWidgetItem(findParent); } else { QTreeWidgetItem* newParent = new QTreeWidgetItem(ui->cookieTree); newParent->setText(0, domain); newParent->setIcon(0, IconProvider::standardIcon(QStyle::SP_DirIcon)); newParent->setData(0, Qt::UserRole + 10, cookie.domain()); ui->cookieTree->addTopLevelItem(newParent); m_domainHash[domain] = newParent; item = new QTreeWidgetItem(newParent); } item->setText(0, "." + domain); item->setText(1, cookie.name()); item->setData(0, Qt::UserRole + 10, QVariant::fromValue(cookie)); ui->cookieTree->addTopLevelItem(item); m_itemHash[item] = cookie; } void CookieManager::removeCookie(const QNetworkCookie &cookie) { QTreeWidgetItem *item = cookieItem(cookie); if (!item) return; m_itemHash.remove(item); if (item->parent() && item->parent()->childCount() == 1) { m_domainHash.remove(cookieDomain(cookie)); delete item->parent(); item = Q_NULLPTR; } delete item; } void CookieManager::closeEvent(QCloseEvent* e) { QStringList whitelist; QStringList blacklist; for (int i = 0; i < ui->whiteList->count(); ++i) { whitelist.append(ui->whiteList->item(i)->text()); } for (int i = 0; i < ui->blackList->count(); ++i) { blacklist.append(ui->blackList->item(i)->text()); } Settings settings; settings.beginGroup("Cookie-Settings"); settings.setValue("allowCookies", ui->saveCookies->isChecked()); settings.setValue("filterThirdPartyCookies", ui->filter3rdParty->isChecked()); settings.setValue("filterTrackingCookie", ui->filterTracking->isChecked()); settings.setValue("deleteCookiesOnClose", ui->deleteCookiesOnClose->isChecked()); settings.setValue("whitelist", whitelist); settings.setValue("blacklist", blacklist); settings.endGroup(); mApp->cookieJar()->loadSettings(); e->accept(); } void CookieManager::keyPressEvent(QKeyEvent* e) { if (e->key() == Qt::Key_Escape) { close(); } QWidget::keyPressEvent(e); } CookieManager::~CookieManager() { delete ui; } diff --git a/src/lib/preferences/jsoptions.cpp b/src/lib/preferences/jsoptions.cpp index 57a18529..e000185e 100644 --- a/src/lib/preferences/jsoptions.cpp +++ b/src/lib/preferences/jsoptions.cpp @@ -1,65 +1,65 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2013-2014 David Rosca 2013-2014 Mladen Pejaković * * 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 "jsoptions.h" #include "ui_jsoptions.h" #include "mainapplication.h" #include "settings.h" JsOptions::JsOptions(QWidget* parent) : QDialog(parent) , ui(new Ui::JsOptions) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); -#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) +#if QTWEBENGINE_VERSION < QT_VERSION_CHECK(5, 10, 0) ui->jscanActivateWindow->setVisible(false); #endif -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION < QT_VERSION_CHECK(5, 11, 0) ui->jscanPaste->setVisible(false); #endif Settings settings; settings.beginGroup("Web-Browser-Settings"); ui->jscanOpenWindow->setChecked(settings.value("allowJavaScriptOpenWindow", false).toBool()); ui->jscanActivateWindow->setChecked(settings.value("allowJavaScriptActivateWindow", false).toBool()); ui->jscanAccessClipboard->setChecked(settings.value("allowJavaScriptAccessClipboard", true).toBool()); ui->jscanPaste->setChecked(settings.value("allowJavaScriptPaste", true).toBool()); settings.endGroup(); } void JsOptions::accept() { Settings settings; settings.beginGroup("Web-Browser-Settings"); settings.setValue("allowJavaScriptOpenWindow", ui->jscanOpenWindow->isChecked()); settings.setValue("allowJavaScriptActivateWindow", ui->jscanActivateWindow->isChecked()); settings.setValue("allowJavaScriptAccessClipboard", ui->jscanAccessClipboard->isChecked()); settings.setValue("allowJavaScriptPaste", ui->jscanPaste->isChecked()); settings.endGroup(); QDialog::close(); } JsOptions::~JsOptions() { delete ui; } diff --git a/src/lib/preferences/preferences.cpp b/src/lib/preferences/preferences.cpp index 87d40acd..194da031 100644 --- a/src/lib/preferences/preferences.cpp +++ b/src/lib/preferences/preferences.cpp @@ -1,1073 +1,1073 @@ /* ============================================================ * 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 "preferences.h" #include "ui_preferences.h" #include "browserwindow.h" #include "bookmarkstoolbar.h" #include "history.h" #include "tabwidget.h" #include "cookiejar.h" #include "locationbar.h" #include "autofillmanager.h" #include "mainapplication.h" #include "cookiemanager.h" #include "pluginproxy.h" #include "pluginsmanager.h" #include "jsoptions.h" #include "networkmanager.h" #include "desktopnotificationsfactory.h" #include "desktopnotification.h" #include "thememanager.h" #include "acceptlanguage.h" #include "qztools.h" #include "autofill.h" #include "settings.h" #include "datapaths.h" #include "tabbedwebview.h" #include "clearprivatedata.h" #include "useragentdialog.h" #include "registerqappassociation.h" #include "profilemanager.h" #include "html5permissions/html5permissionsdialog.h" #include "searchenginesdialog.h" #include "webscrollbarmanager.h" #include "../config.h" #include #include #include #include #include #include #include #include #include #include static QString createLanguageItem(const QString &lang) { QLocale locale(lang); if (locale.language() == QLocale::C) { return lang; } QString country = QLocale::countryToString(locale.country()); QString language = QLocale::languageToString(locale.language()); if (lang == QLatin1String("es_ES")) { return QString::fromUtf8("Castellano"); } if (lang == QLatin1String("nqo")) { return QString("N'ko (nqo)"); } if (lang == QLatin1String("sr")) { return QString::fromUtf8("српски екавски"); } if (lang == QLatin1String("sr@ijekavian")) { return QString::fromUtf8("српски ијекавски"); } if (lang == QLatin1String("sr@latin")) { return QString::fromUtf8("srpski ekavski"); } if (lang == QLatin1String("sr@ijekavianlatin")) { return QString::fromUtf8("srpski ijekavski"); } return QString("%1, %2 (%3)").arg(language, country, lang); } Preferences::Preferences(BrowserWindow* window) : QDialog(window) , ui(new Ui::Preferences) , m_window(window) , m_autoFillManager(0) , m_pluginsList(0) { setAttribute(Qt::WA_DeleteOnClose); ui->setupUi(this); QzTools::centerWidgetOnScreen(this); m_themesManager = new ThemeManager(ui->themesWidget, this); m_pluginsList = new PluginsManager(this); ui->pluginsFrame->addWidget(m_pluginsList); #ifdef DISABLE_CHECK_UPDATES ui->checkUpdates->setVisible(false); #endif -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION < QT_VERSION_CHECK(5, 11, 0) ui->disableVideoAutoPlay->setVisible(false); ui->webRTCPublicIpOnly->setVisible(false); #endif auto setCategoryIcon = [this](int index, const QIcon &icon) { ui->listWidget->item(index)->setIcon(QIcon(icon.pixmap(32))); }; setCategoryIcon(0, QIcon(":/icons/preferences/general.svg")); setCategoryIcon(1, QIcon(":/icons/preferences/appearance.svg")); setCategoryIcon(2, QIcon(":/icons/preferences/tabs.svg")); setCategoryIcon(3, QIcon(":/icons/preferences/browsing.svg")); setCategoryIcon(4, QIcon(":/icons/preferences/fonts.svg")); setCategoryIcon(5, QIcon(":/icons/preferences/shortcuts.svg")); setCategoryIcon(6, QIcon(":/icons/preferences/downloads.svg")); setCategoryIcon(7, QIcon(":/icons/preferences/passwords.svg")); setCategoryIcon(8, QIcon(":/icons/preferences/privacy.svg")); setCategoryIcon(9, QIcon(":/icons/preferences/notifications.svg")); setCategoryIcon(10, QIcon(":/icons/preferences/extensions.svg")); setCategoryIcon(11, QIcon(":/icons/preferences/spellcheck.svg")); setCategoryIcon(12, QIcon(":/icons/preferences/other.svg")); Settings settings; //GENERAL URLs settings.beginGroup("Web-URL-Settings"); m_homepage = settings.value("homepage", QUrl(QSL("falkon:start"))).toUrl(); m_newTabUrl = settings.value("newTabUrl", QUrl(QSL("falkon:speeddial"))).toUrl(); ui->homepage->setText(m_homepage.toEncoded()); ui->newTabUrl->setText(m_newTabUrl.toEncoded()); settings.endGroup(); ui->afterLaunch->setCurrentIndex(mApp->afterLaunch()); ui->checkUpdates->setChecked(settings.value("Web-Browser-Settings/CheckUpdates", true).toBool()); ui->dontLoadTabsUntilSelected->setChecked(settings.value("Web-Browser-Settings/LoadTabsOnActivation", true).toBool()); #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) if (!mApp->isPortable()) { ui->checkDefaultBrowser->setChecked(settings.value("Web-Browser-Settings/CheckDefaultBrowser", DEFAULT_CHECK_DEFAULTBROWSER).toBool()); if (mApp->associationManager()->isDefaultForAllCapabilities()) { ui->checkNowDefaultBrowser->setText(tr("Default")); ui->checkNowDefaultBrowser->setEnabled(false); } else { ui->checkNowDefaultBrowser->setText(tr("Set as default")); ui->checkNowDefaultBrowser->setEnabled(true); connect(ui->checkNowDefaultBrowser, SIGNAL(clicked()), this, SLOT(makeFalkonDefault())); } } else { ui->checkDefaultBrowser->hide(); ui->checkNowDefaultBrowser->hide(); } #else // No Default Browser settings on non-Windows platform ui->hSpacerDefaultBrowser->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed); ui->hLayoutDefaultBrowser->invalidate(); delete ui->hLayoutDefaultBrowser; delete ui->checkDefaultBrowser; delete ui->checkNowDefaultBrowser; #endif ui->newTabFrame->setVisible(false); if (m_newTabUrl.isEmpty() || m_newTabUrl.toString() == QL1S("about:blank")) { ui->newTab->setCurrentIndex(0); } else if (m_newTabUrl == m_homepage) { ui->newTab->setCurrentIndex(1); } else if (m_newTabUrl.toString() == QL1S("falkon:speeddial")) { ui->newTab->setCurrentIndex(2); } else { ui->newTab->setCurrentIndex(3); ui->newTabFrame->setVisible(true); } afterLaunchChanged(ui->afterLaunch->currentIndex()); connect(ui->afterLaunch, SIGNAL(currentIndexChanged(int)), this, SLOT(afterLaunchChanged(int))); connect(ui->newTab, SIGNAL(currentIndexChanged(int)), this, SLOT(newTabChanged(int))); if (m_window) { connect(ui->useCurrentBut, SIGNAL(clicked()), this, SLOT(useActualHomepage())); connect(ui->newTabUseCurrent, SIGNAL(clicked()), this, SLOT(useActualNewTab())); } else { ui->useCurrentBut->setEnabled(false); ui->newTabUseCurrent->setEnabled(false); } // PROFILES QString startingProfile = ProfileManager::startingProfile(); ui->activeProfile->setText("" + ProfileManager::currentProfile() + ""); ui->startProfile->addItem(startingProfile); foreach (const QString &name, ProfileManager::availableProfiles()) { if (startingProfile != name) { ui->startProfile->addItem(name); } } connect(ui->createProfile, SIGNAL(clicked()), this, SLOT(createProfile())); connect(ui->deleteProfile, SIGNAL(clicked()), this, SLOT(deleteProfile())); connect(ui->startProfile, SIGNAL(currentIndexChanged(int)), this, SLOT(startProfileIndexChanged(int))); startProfileIndexChanged(ui->startProfile->currentIndex()); //APPEREANCE settings.beginGroup("Browser-View-Settings"); ui->showStatusbar->setChecked(settings.value("showStatusBar", false).toBool()); // NOTE: instantBookmarksToolbar and showBookmarksToolbar cannot be both enabled at the same time ui->instantBookmarksToolbar->setChecked(settings.value("instantBookmarksToolbar", false).toBool()); ui->showBookmarksToolbar->setChecked(settings.value("showBookmarksToolbar", false).toBool()); ui->instantBookmarksToolbar->setDisabled(settings.value("showBookmarksToolbar", false).toBool()); ui->showBookmarksToolbar->setDisabled(settings.value("instantBookmarksToolbar").toBool()); connect(ui->instantBookmarksToolbar, SIGNAL(toggled(bool)), ui->showBookmarksToolbar, SLOT(setDisabled(bool))); connect(ui->showBookmarksToolbar, SIGNAL(toggled(bool)), ui->instantBookmarksToolbar, SLOT(setDisabled(bool))); ui->showNavigationToolbar->setChecked(settings.value("showNavigationToolbar", true).toBool()); int currentSettingsPage = settings.value("settingsDialogPage", 0).toInt(0); settings.endGroup(); //TABS settings.beginGroup("Browser-Tabs-Settings"); ui->hideTabsOnTab->setChecked(settings.value("hideTabsWithOneTab", false).toBool()); ui->activateLastTab->setChecked(settings.value("ActivateLastTabWhenClosingActual", false).toBool()); ui->openNewTabAfterActive->setChecked(settings.value("newTabAfterActive", true).toBool()); ui->openNewEmptyTabAfterActive->setChecked(settings.value("newEmptyTabAfterActive", false).toBool()); ui->openPopupsInTabs->setChecked(settings.value("OpenPopupsInTabs", false).toBool()); ui->alwaysSwitchTabsWithWheel->setChecked(settings.value("AlwaysSwitchTabsWithWheel", false).toBool()); ui->switchToNewTabs->setChecked(settings.value("OpenNewTabsSelected", false).toBool()); ui->dontCloseOnLastTab->setChecked(settings.value("dontCloseWithOneTab", false).toBool()); ui->askWhenClosingMultipleTabs->setChecked(settings.value("AskOnClosing", false).toBool()); ui->showClosedTabsButton->setChecked(settings.value("showClosedTabsButton", false).toBool()); ui->showCloseOnInactive->setCurrentIndex(settings.value("showCloseOnInactiveTabs", 0).toInt()); settings.endGroup(); //AddressBar settings.beginGroup("AddressBar"); ui->addressbarCompletion->setCurrentIndex(settings.value("showSuggestions", 0).toInt()); ui->useInlineCompletion->setChecked(settings.value("useInlineCompletion", true).toBool()); ui->completionShowSwitchTab->setChecked(settings.value("showSwitchTab", true).toBool()); ui->alwaysShowGoIcon->setChecked(settings.value("alwaysShowGoIcon", false).toBool()); ui->selectAllOnFocus->setChecked(settings.value("SelectAllTextOnDoubleClick", true).toBool()); ui->selectAllOnClick->setChecked(settings.value("SelectAllTextOnClick", false).toBool()); bool showPBinAB = settings.value("ShowLoadingProgress", false).toBool(); ui->showLoadingInAddressBar->setChecked(showPBinAB); ui->adressProgressSettings->setEnabled(showPBinAB); ui->progressStyleSelector->setCurrentIndex(settings.value("ProgressStyle", 0).toInt()); bool pbInABuseCC = settings.value("UseCustomProgressColor", false).toBool(); ui->checkBoxCustomProgressColor->setChecked(pbInABuseCC); ui->progressBarColorSelector->setEnabled(pbInABuseCC); QColor pbColor = settings.value("CustomProgressColor", palette().color(QPalette::Highlight)).value(); setProgressBarColorIcon(pbColor); connect(ui->customColorToolButton, SIGNAL(clicked(bool)), SLOT(selectCustomProgressBarColor())); connect(ui->resetProgressBarcolor, SIGNAL(clicked()), SLOT(setProgressBarColorIcon())); settings.endGroup(); settings.beginGroup("SearchEngines"); bool searchFromAB = settings.value("SearchFromAddressBar", true).toBool(); ui->searchFromAddressBar->setChecked(searchFromAB); ui->searchWithDefaultEngine->setEnabled(searchFromAB); ui->searchWithDefaultEngine->setChecked(settings.value("SearchWithDefaultEngine", false).toBool()); ui->showABSearchSuggestions->setEnabled(searchFromAB); ui->showABSearchSuggestions->setChecked(settings.value("showSearchSuggestions", true).toBool()); connect(ui->searchFromAddressBar, SIGNAL(toggled(bool)), this, SLOT(searchFromAddressBarChanged(bool))); settings.endGroup(); // BROWSING settings.beginGroup("Web-Browser-Settings"); ui->allowPlugins->setChecked(settings.value("allowPlugins", true).toBool()); ui->allowJavaScript->setChecked(settings.value("allowJavaScript", true).toBool()); ui->linksInFocusChain->setChecked(settings.value("IncludeLinkInFocusChain", false).toBool()); ui->spatialNavigation->setChecked(settings.value("SpatialNavigation", false).toBool()); ui->animateScrolling->setChecked(settings.value("AnimateScrolling", true).toBool()); ui->wheelScroll->setValue(settings.value("wheelScrollLines", qApp->wheelScrollLines()).toInt()); ui->xssAuditing->setChecked(settings.value("XSSAuditing", false).toBool()); ui->printEBackground->setChecked(settings.value("PrintElementBackground", true).toBool()); ui->useNativeScrollbars->setChecked(settings.value("UseNativeScrollbars", false).toBool()); ui->disableVideoAutoPlay->setChecked(settings.value("DisableVideoAutoPlay", false).toBool()); ui->webRTCPublicIpOnly->setChecked(settings.value("WebRTCPublicIpOnly", true).toBool()); foreach (int level, WebView::zoomLevels()) { ui->defaultZoomLevel->addItem(QString("%1%").arg(level)); } ui->defaultZoomLevel->setCurrentIndex(settings.value("DefaultZoomLevel", WebView::zoomLevels().indexOf(100)).toInt()); ui->closeAppWithCtrlQ->setChecked(settings.value("closeAppWithCtrlQ", true).toBool()); //Cache ui->allowCache->setChecked(settings.value("AllowLocalCache", true).toBool()); ui->removeCache->setChecked(settings.value("deleteCacheOnClose", false).toBool()); ui->cacheMB->setValue(settings.value("LocalCacheSize", 50).toInt()); ui->cachePath->setText(settings.value("CachePath", QWebEngineProfile::defaultProfile()->cachePath()).toString()); connect(ui->allowCache, SIGNAL(clicked(bool)), this, SLOT(allowCacheChanged(bool))); connect(ui->changeCachePath, SIGNAL(clicked()), this, SLOT(changeCachePathClicked())); allowCacheChanged(ui->allowCache->isChecked()); //PASSWORD MANAGER ui->allowPassManager->setChecked(settings.value("SavePasswordsOnSites", true).toBool()); ui->autoCompletePasswords->setChecked(settings.value("AutoCompletePasswords", true).toBool()); //PRIVACY //Web storage ui->saveHistory->setChecked(settings.value("allowHistory", true).toBool()); ui->deleteHistoryOnClose->setChecked(settings.value("deleteHistoryOnClose", false).toBool()); if (!ui->saveHistory->isChecked()) { ui->deleteHistoryOnClose->setEnabled(false); } connect(ui->saveHistory, SIGNAL(toggled(bool)), this, SLOT(saveHistoryChanged(bool))); // Html5Storage ui->html5storage->setChecked(settings.value("HTML5StorageEnabled", true).toBool()); ui->deleteHtml5storageOnClose->setChecked(settings.value("deleteHTML5StorageOnClose", false).toBool()); connect(ui->html5storage, SIGNAL(toggled(bool)), this, SLOT(allowHtml5storageChanged(bool))); // Other ui->doNotTrack->setChecked(settings.value("DoNotTrack", false).toBool()); //CSS Style ui->userStyleSheet->setText(settings.value("userStyleSheet", "").toString()); connect(ui->chooseUserStylesheet, SIGNAL(clicked()), this, SLOT(chooseUserStyleClicked())); settings.endGroup(); //DOWNLOADS settings.beginGroup("DownloadManager"); ui->downLoc->setText(settings.value("defaultDownloadPath", "").toString()); ui->closeDownManOnFinish->setChecked(settings.value("CloseManagerOnFinish", false).toBool()); if (ui->downLoc->text().isEmpty()) { ui->askEverytime->setChecked(true); } else { ui->useDefined->setChecked(true); } ui->useExternalDownManager->setChecked(settings.value("UseExternalManager", false).toBool()); ui->externalDownExecutable->setText(settings.value("ExternalManagerExecutable", "").toString()); ui->externalDownArguments->setText(settings.value("ExternalManagerArguments", "").toString()); connect(ui->useExternalDownManager, SIGNAL(toggled(bool)), this, SLOT(useExternalDownManagerChanged(bool))); connect(ui->useDefined, SIGNAL(toggled(bool)), this, SLOT(downLocChanged(bool))); connect(ui->downButt, SIGNAL(clicked()), this, SLOT(chooseDownPath())); connect(ui->chooseExternalDown, SIGNAL(clicked()), this, SLOT(chooseExternalDownloadManager())); downLocChanged(ui->useDefined->isChecked()); useExternalDownManagerChanged(ui->useExternalDownManager->isChecked()); settings.endGroup(); //FONTS settings.beginGroup("Browser-Fonts"); QWebEngineSettings* webSettings = mApp->webSettings(); auto defaultFont = [&](QWebEngineSettings::FontFamily font) -> const QString { const QString family = webSettings->fontFamily(font); if (!family.isEmpty()) return family; switch (font) { case QWebEngineSettings::FixedFont: return QFontDatabase::systemFont(QFontDatabase::FixedFont).family(); case QWebEngineSettings::SerifFont: // TODO default: return QFontDatabase::systemFont(QFontDatabase::GeneralFont).family(); } }; ui->fontStandard->setCurrentFont(QFont(settings.value("StandardFont", defaultFont(QWebEngineSettings::StandardFont)).toString())); ui->fontCursive->setCurrentFont(QFont(settings.value("CursiveFont", defaultFont(QWebEngineSettings::CursiveFont)).toString())); ui->fontFantasy->setCurrentFont(QFont(settings.value("FantasyFont", defaultFont(QWebEngineSettings::FantasyFont)).toString())); ui->fontFixed->setCurrentFont(QFont(settings.value("FixedFont", defaultFont(QWebEngineSettings::FixedFont)).toString())); ui->fontSansSerif->setCurrentFont(QFont(settings.value("SansSerifFont", defaultFont(QWebEngineSettings::SansSerifFont)).toString())); ui->fontSerif->setCurrentFont(QFont(settings.value("SerifFont", defaultFont(QWebEngineSettings::SerifFont)).toString())); ui->sizeDefault->setValue(settings.value("DefaultFontSize", webSettings->fontSize(QWebEngineSettings::DefaultFontSize)).toInt()); ui->sizeFixed->setValue(settings.value("FixedFontSize", webSettings->fontSize(QWebEngineSettings::DefaultFixedFontSize)).toInt()); ui->sizeMinimum->setValue(settings.value("MinimumFontSize", webSettings->fontSize(QWebEngineSettings::MinimumFontSize)).toInt()); ui->sizeMinimumLogical->setValue(settings.value("MinimumLogicalFontSize", webSettings->fontSize(QWebEngineSettings::MinimumLogicalFontSize)).toInt()); settings.endGroup(); //KEYBOARD SHORTCUTS settings.beginGroup("Shortcuts"); ui->switchTabsAlt->setChecked(settings.value("useTabNumberShortcuts", true).toBool()); ui->loadSpeedDialsCtrl->setChecked(settings.value("useSpeedDialNumberShortcuts", true).toBool()); ui->singleKeyShortcuts->setChecked(settings.value("useSingleKeyShortcuts", false).toBool()); settings.endGroup(); //NOTIFICATIONS ui->useNativeSystemNotifications->setEnabled(mApp->desktopNotifications()->supportsNativeNotifications()); DesktopNotificationsFactory::Type notifyType; settings.beginGroup("Notifications"); ui->notificationTimeout->setValue(settings.value("Timeout", 6000).toInt() / 1000); #if defined(Q_OS_UNIX) && !defined(DISABLE_DBUS) notifyType = settings.value("UseNativeDesktop", true).toBool() ? DesktopNotificationsFactory::DesktopNative : DesktopNotificationsFactory::PopupWidget; #else notifyType = DesktopNotificationsFactory::PopupWidget; #endif if (ui->useNativeSystemNotifications->isEnabled() && notifyType == DesktopNotificationsFactory::DesktopNative) { ui->useNativeSystemNotifications->setChecked(true); } else { ui->useOSDNotifications->setChecked(true); } connect(ui->notificationPreview, &QPushButton::clicked, this, &Preferences::showNotificationPreview); ui->doNotUseNotifications->setChecked(!settings.value("Enabled", true).toBool()); m_notifPosition = settings.value("Position", QPoint(10, 10)).toPoint(); settings.endGroup(); //SPELLCHECK settings.beginGroup(QSL("SpellCheck")); ui->spellcheckEnabled->setChecked(settings.value(QSL("Enabled"), false).toBool()); const QStringList spellcheckLanguages = settings.value(QSL("Languages")).toStringList(); settings.endGroup(); auto updateSpellCheckEnabled = [this]() { ui->spellcheckLanguages->setEnabled(ui->spellcheckEnabled->isChecked()); ui->spellcheckNoLanguages->setEnabled(ui->spellcheckEnabled->isChecked()); }; updateSpellCheckEnabled(); connect(ui->spellcheckEnabled, &QCheckBox::toggled, this, updateSpellCheckEnabled); QStringList dictionariesDirs = { #ifdef Q_OS_OSX QDir::cleanPath(QCoreApplication::applicationDirPath() + QL1S("/../Resources/qtwebengine_dictionaries")), QDir::cleanPath(QCoreApplication::applicationDirPath() + QL1S("/../Frameworks/QtWebEngineCore.framework/Resources/qtwebengine_dictionaries")) #else QDir::cleanPath(QCoreApplication::applicationDirPath() + QL1S("/qtwebengine_dictionaries")), QDir::cleanPath(QLibraryInfo::location(QLibraryInfo::DataPath) + QL1S("/qtwebengine_dictionaries")) #endif }; dictionariesDirs.removeDuplicates(); ui->spellcheckDirectories->setText(dictionariesDirs.join(QL1C('\n'))); for (const QString &path : dictionariesDirs) { QDir dir(path); const QStringList files = dir.entryList({QSL("*.bdic")}); for (const QString &file : files) { const QString lang = file.left(file.size() - 5); const QString langName = createLanguageItem(lang); if (!ui->spellcheckLanguages->findItems(langName, Qt::MatchExactly).isEmpty()) { continue; } QListWidgetItem *item = new QListWidgetItem; item->setText(langName); item->setData(Qt::UserRole, lang); item->setFlags(item->flags() & ~Qt::ItemIsSelectable); item->setCheckState(Qt::Unchecked); ui->spellcheckLanguages->addItem(item); } } int topIndex = 0; for (const QString &lang : spellcheckLanguages) { const auto items = ui->spellcheckLanguages->findItems(createLanguageItem(lang), Qt::MatchExactly); if (items.isEmpty()) { continue; } QListWidgetItem *item = items.at(0); ui->spellcheckLanguages->takeItem(ui->spellcheckLanguages->row(item)); ui->spellcheckLanguages->insertItem(topIndex++, item); item->setCheckState(Qt::Checked); } if (ui->spellcheckLanguages->count() == 0) { ui->spellcheckLanguages->hide(); } else { ui->spellcheckNoLanguages->hide(); } // Proxy Configuration settings.beginGroup("Web-Proxy"); int proxyType = settings.value("ProxyType", 2).toInt(); if (proxyType == 0) { ui->noProxy->setChecked(true); } else if (proxyType == 2) { ui->systemProxy->setChecked(true); } else if (proxyType == 3) { ui->manualProxy->setChecked(true); ui->proxyType->setCurrentIndex(0); } else { ui->manualProxy->setChecked(true); ui->proxyType->setCurrentIndex(1); } ui->proxyServer->setText(settings.value("HostName", "").toString()); ui->proxyPort->setText(settings.value("Port", 8080).toString()); ui->proxyUsername->setText(settings.value("Username", "").toString()); ui->proxyPassword->setText(settings.value("Password", "").toString()); settings.endGroup(); setManualProxyConfigurationEnabled(ui->manualProxy->isChecked()); connect(ui->manualProxy, SIGNAL(toggled(bool)), this, SLOT(setManualProxyConfigurationEnabled(bool))); //CONNECTS connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*))); connect(ui->cookieManagerBut, SIGNAL(clicked()), this, SLOT(showCookieManager())); connect(ui->html5permissions, SIGNAL(clicked()), this, SLOT(showHtml5Permissions())); connect(ui->preferredLanguages, SIGNAL(clicked()), this, SLOT(showAcceptLanguage())); connect(ui->deleteHtml5storage, SIGNAL(clicked()), this, SLOT(deleteHtml5storage())); connect(ui->uaManager, SIGNAL(clicked()), this, SLOT(openUserAgentManager())); connect(ui->jsOptionsButton, SIGNAL(clicked()), this, SLOT(openJsOptions())); connect(ui->searchEngines, SIGNAL(clicked()), this, SLOT(openSearchEnginesManager())); connect(ui->listWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(showStackedPage(QListWidgetItem*))); ui->listWidget->setItemSelected(ui->listWidget->itemAt(5, 5), true); ui->listWidget->setCurrentRow(currentSettingsPage); QDesktopWidget* desktop = QApplication::desktop(); QSize s = size(); if (desktop->availableGeometry(this).size().width() < s.width()) { s.setWidth(desktop->availableGeometry(this).size().width() - 50); } if (desktop->availableGeometry(this).size().height() < s.height()) { s.setHeight(desktop->availableGeometry(this).size().height() - 50); } resize(s); settings.beginGroup(QSL("Preferences")); restoreGeometry(settings.value(QSL("Geometry")).toByteArray()); settings.endGroup(); QzTools::setWmClass("Preferences", this); } void Preferences::chooseExternalDownloadManager() { QString path = QzTools::getOpenFileName("Preferences-ExternalDownloadManager", this, tr("Choose executable location..."), QDir::homePath()); if (path.isEmpty()) { return; } ui->externalDownExecutable->setText(path); } void Preferences::showStackedPage(QListWidgetItem* item) { if (!item) { return; } int index = ui->listWidget->currentRow(); ui->caption->setText("" + item->text() + ""); ui->stackedWidget->setCurrentIndex(index); if (m_notification) { m_notifPosition = m_notification.data()->pos(); delete m_notification.data(); } if (index == 10) { m_pluginsList->load(); } if (index == 7 && !m_autoFillManager) { m_autoFillManager = new AutoFillManager(this); ui->autoFillFrame->addWidget(m_autoFillManager); } } void Preferences::showNotificationPreview() { if (ui->useOSDNotifications->isChecked()) { if (m_notification) { m_notifPosition = m_notification.data()->pos(); delete m_notification.data(); } m_notification = new DesktopNotification(true); m_notification.data()->setHeading(tr("OSD Notification")); m_notification.data()->setText(tr("Drag it on the screen to place it where you want.")); m_notification.data()->move(m_notifPosition); m_notification.data()->show(); } else if (ui->useNativeSystemNotifications->isChecked()) { mApp->desktopNotifications()->nativeNotificationPreview(); } } void Preferences::makeFalkonDefault() { #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) disconnect(ui->checkNowDefaultBrowser, SIGNAL(clicked()), this, SLOT(makeFalkonDefault())); ui->checkNowDefaultBrowser->setText(tr("Default")); ui->checkNowDefaultBrowser->setEnabled(false); if (!mApp->associationManager()->showNativeDefaultAppSettingsUi()) mApp->associationManager()->registerAllAssociation(); #endif } void Preferences::allowCacheChanged(bool state) { ui->removeCache->setEnabled(state); ui->maxCacheLabel->setEnabled(state); ui->cacheMB->setEnabled(state); ui->storeCacheLabel->setEnabled(state); ui->cachePath->setEnabled(state); ui->changeCachePath->setEnabled(state); } void Preferences::useActualHomepage() { if (!m_window) return; ui->homepage->setText(m_window->weView()->url().toString()); } void Preferences::useActualNewTab() { if (!m_window) return; ui->newTabUrl->setText(m_window->weView()->url().toString()); } void Preferences::chooseDownPath() { QString userFileName = QzTools::getExistingDirectory("Preferences-ChooseDownPath", this, tr("Choose download location..."), QDir::homePath()); if (userFileName.isEmpty()) { return; } #ifdef Q_OS_WIN //QFileDialog::getExistingDirectory returns path with \ instead of / (??) userFileName.replace(QLatin1Char('\\'), QLatin1Char('/')); #endif userFileName += QLatin1Char('/'); ui->downLoc->setText(userFileName); } void Preferences::chooseUserStyleClicked() { QString file = QzTools::getOpenFileName("Preferences-UserStyle", this, tr("Choose stylesheet location..."), QDir::homePath(), "*.css"); if (file.isEmpty()) { return; } ui->userStyleSheet->setText(file); } void Preferences::deleteHtml5storage() { ClearPrivateData::clearLocalStorage(); ui->deleteHtml5storage->setText(tr("Deleted")); ui->deleteHtml5storage->setEnabled(false); } void Preferences::openUserAgentManager() { UserAgentDialog* dialog = new UserAgentDialog(this); dialog->open(); } void Preferences::downLocChanged(bool state) { ui->downButt->setEnabled(state); ui->downLoc->setEnabled(state); } void Preferences::setManualProxyConfigurationEnabled(bool state) { ui->proxyType->setEnabled(state); ui->proxyServer->setEnabled(state); ui->proxyPort->setEnabled(state); ui->proxyUsername->setEnabled(state); ui->proxyPassword->setEnabled(state); } void Preferences::searchFromAddressBarChanged(bool stat) { ui->searchWithDefaultEngine->setEnabled(stat); ui->showABSearchSuggestions->setEnabled(stat); } void Preferences::saveHistoryChanged(bool stat) { ui->deleteHistoryOnClose->setEnabled(stat); } void Preferences::allowHtml5storageChanged(bool stat) { ui->deleteHtml5storageOnClose->setEnabled(stat); } void Preferences::showCookieManager() { CookieManager* dialog = new CookieManager(this); dialog->show(); } void Preferences::showHtml5Permissions() { HTML5PermissionsDialog* dialog = new HTML5PermissionsDialog(this); dialog->open(); } void Preferences::openJsOptions() { JsOptions* dialog = new JsOptions(this); dialog->open(); } void Preferences::useExternalDownManagerChanged(bool state) { ui->externalDownExecutable->setEnabled(state); ui->externalDownArguments->setEnabled(state); ui->chooseExternalDown->setEnabled(state); } void Preferences::openSearchEnginesManager() { SearchEnginesDialog* dialog = new SearchEnginesDialog(this); dialog->open(); } void Preferences::showAcceptLanguage() { AcceptLanguage* dialog = new AcceptLanguage(this); dialog->open(); } void Preferences::newTabChanged(int value) { ui->newTabFrame->setVisible(value == 3); } void Preferences::afterLaunchChanged(int value) { ui->dontLoadTabsUntilSelected->setEnabled(value == 3 || value == 4); } void Preferences::changeCachePathClicked() { QString path = QzTools::getExistingDirectory("Preferences-CachePath", this, tr("Choose cache path..."), ui->cachePath->text()); if (path.isEmpty()) { return; } ui->cachePath->setText(path); } void Preferences::buttonClicked(QAbstractButton* button) { switch (ui->buttonBox->buttonRole(button)) { case QDialogButtonBox::ApplyRole: saveSettings(); break; case QDialogButtonBox::RejectRole: close(); break; case QDialogButtonBox::AcceptRole: saveSettings(); close(); break; default: break; } } void Preferences::createProfile() { QString name = QInputDialog::getText(this, tr("New Profile"), tr("Enter the new profile's name:")); name = QzTools::filterCharsFromFilename(name); if (name.isEmpty()) { return; } int res = ProfileManager::createProfile(name); if (res == -1) { QMessageBox::warning(this, tr("Error!"), tr("This profile already exists!")); return; } if (res != 0) { QMessageBox::warning(this, tr("Error!"), tr("Cannot create profile directory!")); return; } ui->startProfile->addItem(name); ui->startProfile->setCurrentIndex(ui->startProfile->count() - 1); } void Preferences::deleteProfile() { QString name = ui->startProfile->currentText(); QMessageBox::StandardButton button = QMessageBox::warning(this, tr("Confirmation"), tr("Are you sure you want to permanently delete \"%1\" profile? This action cannot be undone!").arg(name), QMessageBox::Yes | QMessageBox::No); if (button != QMessageBox::Yes) { return; } ProfileManager::removeProfile(name); ui->startProfile->removeItem(ui->startProfile->currentIndex()); } void Preferences::startProfileIndexChanged(int index) { const bool current = ui->startProfile->itemText(index) == ProfileManager::currentProfile(); ui->deleteProfile->setEnabled(!current); ui->cannotDeleteActiveProfileLabel->setText(current ? tr("Note: You cannot delete active profile.") : QString()); } void Preferences::closeEvent(QCloseEvent* event) { Settings settings; settings.beginGroup("Browser-View-Settings"); settings.setValue("settingsDialogPage", ui->stackedWidget->currentIndex()); settings.endGroup(); event->accept(); } void Preferences::saveSettings() { Settings settings; //GENERAL URLs QUrl homepage = QUrl::fromUserInput(ui->homepage->text()); settings.beginGroup("Web-URL-Settings"); settings.setValue("homepage", homepage); settings.setValue("afterLaunch", ui->afterLaunch->currentIndex()); switch (ui->newTab->currentIndex()) { case 0: settings.setValue("newTabUrl", QUrl()); break; case 1: settings.setValue("newTabUrl", homepage); break; case 2: settings.setValue("newTabUrl", QUrl(QSL("falkon:speeddial"))); break; case 3: settings.setValue("newTabUrl", QUrl::fromUserInput(ui->newTabUrl->text())); break; default: break; } settings.endGroup(); //PROFILES /* * * * */ //WINDOW settings.beginGroup("Browser-View-Settings"); settings.setValue("showStatusBar", ui->showStatusbar->isChecked()); settings.setValue("instantBookmarksToolbar", ui->instantBookmarksToolbar->isChecked()); settings.setValue("showBookmarksToolbar", ui->showBookmarksToolbar->isChecked()); settings.setValue("showNavigationToolbar", ui->showNavigationToolbar->isChecked()); settings.endGroup(); //TABS settings.beginGroup("Browser-Tabs-Settings"); settings.setValue("hideTabsWithOneTab", ui->hideTabsOnTab->isChecked()); settings.setValue("ActivateLastTabWhenClosingActual", ui->activateLastTab->isChecked()); settings.setValue("newTabAfterActive", ui->openNewTabAfterActive->isChecked()); settings.setValue("newEmptyTabAfterActive", ui->openNewEmptyTabAfterActive->isChecked()); settings.setValue("OpenPopupsInTabs", ui->openPopupsInTabs->isChecked()); settings.setValue("AlwaysSwitchTabsWithWheel", ui->alwaysSwitchTabsWithWheel->isChecked()); settings.setValue("OpenNewTabsSelected", ui->switchToNewTabs->isChecked()); settings.setValue("dontCloseWithOneTab", ui->dontCloseOnLastTab->isChecked()); settings.setValue("AskOnClosing", ui->askWhenClosingMultipleTabs->isChecked()); settings.setValue("showClosedTabsButton", ui->showClosedTabsButton->isChecked()); settings.setValue("showCloseOnInactiveTabs", ui->showCloseOnInactive->currentIndex()); settings.endGroup(); //DOWNLOADS settings.beginGroup("DownloadManager"); if (ui->askEverytime->isChecked()) { settings.setValue("defaultDownloadPath", ""); } else { settings.setValue("defaultDownloadPath", ui->downLoc->text()); } settings.setValue("CloseManagerOnFinish", ui->closeDownManOnFinish->isChecked()); settings.setValue("UseExternalManager", ui->useExternalDownManager->isChecked()); settings.setValue("ExternalManagerExecutable", ui->externalDownExecutable->text()); settings.setValue("ExternalManagerArguments", ui->externalDownArguments->text()); settings.endGroup(); //FONTS settings.beginGroup("Browser-Fonts"); settings.setValue("StandardFont", ui->fontStandard->currentFont().family()); settings.setValue("CursiveFont", ui->fontCursive->currentFont().family()); settings.setValue("FantasyFont", ui->fontFantasy->currentFont().family()); settings.setValue("FixedFont", ui->fontFixed->currentFont().family()); settings.setValue("SansSerifFont", ui->fontSansSerif->currentFont().family()); settings.setValue("SerifFont", ui->fontSerif->currentFont().family()); settings.setValue("DefaultFontSize", ui->sizeDefault->value()); settings.setValue("FixedFontSize", ui->sizeFixed->value()); settings.setValue("MinimumFontSize", ui->sizeMinimum->value()); settings.setValue("MinimumLogicalFontSize", ui->sizeMinimumLogical->value()); settings.endGroup(); //KEYBOARD SHORTCUTS settings.beginGroup("Shortcuts"); settings.setValue("useTabNumberShortcuts", ui->switchTabsAlt->isChecked()); settings.setValue("useSpeedDialNumberShortcuts", ui->loadSpeedDialsCtrl->isChecked()); settings.setValue("useSingleKeyShortcuts", ui->singleKeyShortcuts->isChecked()); settings.endGroup(); //BROWSING settings.beginGroup("Web-Browser-Settings"); settings.setValue("allowPlugins", ui->allowPlugins->isChecked()); settings.setValue("allowJavaScript", ui->allowJavaScript->isChecked()); settings.setValue("IncludeLinkInFocusChain", ui->linksInFocusChain->isChecked()); settings.setValue("SpatialNavigation", ui->spatialNavigation->isChecked()); settings.setValue("AnimateScrolling", ui->animateScrolling->isChecked()); settings.setValue("wheelScrollLines", ui->wheelScroll->value()); settings.setValue("DoNotTrack", ui->doNotTrack->isChecked()); settings.setValue("CheckUpdates", ui->checkUpdates->isChecked()); settings.setValue("LoadTabsOnActivation", ui->dontLoadTabsUntilSelected->isChecked()); settings.setValue("DefaultZoomLevel", ui->defaultZoomLevel->currentIndex()); settings.setValue("XSSAuditing", ui->xssAuditing->isChecked()); settings.setValue("PrintElementBackground", ui->printEBackground->isChecked()); settings.setValue("closeAppWithCtrlQ", ui->closeAppWithCtrlQ->isChecked()); settings.setValue("UseNativeScrollbars", ui->useNativeScrollbars->isChecked()); settings.setValue("DisableVideoAutoPlay", ui->disableVideoAutoPlay->isChecked()); settings.setValue("WebRTCPublicIpOnly", ui->webRTCPublicIpOnly->isChecked()); #ifdef Q_OS_WIN settings.setValue("CheckDefaultBrowser", ui->checkDefaultBrowser->isChecked()); #endif //Cache settings.setValue("AllowLocalCache", ui->allowCache->isChecked()); settings.setValue("deleteCacheOnClose", ui->removeCache->isChecked()); settings.setValue("LocalCacheSize", ui->cacheMB->value()); settings.setValue("CachePath", ui->cachePath->text()); //CSS Style settings.setValue("userStyleSheet", ui->userStyleSheet->text()); //PASSWORD MANAGER settings.setValue("SavePasswordsOnSites", ui->allowPassManager->isChecked()); settings.setValue("AutoCompletePasswords", ui->autoCompletePasswords->isChecked()); //PRIVACY //Web storage settings.setValue("allowHistory", ui->saveHistory->isChecked()); settings.setValue("deleteHistoryOnClose", ui->deleteHistoryOnClose->isChecked()); settings.setValue("HTML5StorageEnabled", ui->html5storage->isChecked()); settings.setValue("deleteHTML5StorageOnClose", ui->deleteHtml5storageOnClose->isChecked()); settings.endGroup(); //NOTIFICATIONS settings.beginGroup("Notifications"); settings.setValue("Timeout", ui->notificationTimeout->value() * 1000); settings.setValue("Enabled", !ui->doNotUseNotifications->isChecked()); settings.setValue("UseNativeDesktop", ui->useNativeSystemNotifications->isChecked()); settings.setValue("Position", m_notification.data() ? m_notification.data()->pos() : m_notifPosition); settings.endGroup(); //SPELLCHECK settings.beginGroup(QSL("SpellCheck")); settings.setValue("Enabled", ui->spellcheckEnabled->isChecked()); QStringList languages; for (int i = 0; i < ui->spellcheckLanguages->count(); ++i) { QListWidgetItem *item = ui->spellcheckLanguages->item(i); if (item->checkState() == Qt::Checked) { languages.append(item->data(Qt::UserRole).toString()); } } settings.setValue("Languages", languages); settings.endGroup(); //OTHER //AddressBar settings.beginGroup("AddressBar"); settings.setValue("showSuggestions", ui->addressbarCompletion->currentIndex()); settings.setValue("useInlineCompletion", ui->useInlineCompletion->isChecked()); settings.setValue("alwaysShowGoIcon", ui->alwaysShowGoIcon->isChecked()); settings.setValue("showSwitchTab", ui->completionShowSwitchTab->isChecked()); settings.setValue("SelectAllTextOnDoubleClick", ui->selectAllOnFocus->isChecked()); settings.setValue("SelectAllTextOnClick", ui->selectAllOnClick->isChecked()); settings.setValue("ShowLoadingProgress", ui->showLoadingInAddressBar->isChecked()); settings.setValue("ProgressStyle", ui->progressStyleSelector->currentIndex()); settings.setValue("UseCustomProgressColor", ui->checkBoxCustomProgressColor->isChecked()); settings.setValue("CustomProgressColor", ui->customColorToolButton->property("ProgressColor").value()); settings.endGroup(); settings.beginGroup("SearchEngines"); settings.setValue("SearchFromAddressBar", ui->searchFromAddressBar->isChecked()); settings.setValue("SearchWithDefaultEngine", ui->searchWithDefaultEngine->isChecked()); settings.setValue("showSearchSuggestions", ui->showABSearchSuggestions->isChecked()); settings.endGroup(); //Proxy Configuration int proxyType; if (ui->noProxy->isChecked()) { proxyType = 0; } else if (ui->systemProxy->isChecked()) { proxyType = 2; } else if (ui->proxyType->currentIndex() == 0) { // Http proxyType = 3; } else { // Socks5 proxyType = 4; } settings.beginGroup("Web-Proxy"); settings.setValue("ProxyType", proxyType); settings.setValue("HostName", ui->proxyServer->text()); settings.setValue("Port", ui->proxyPort->text().toInt()); settings.setValue("Username", ui->proxyUsername->text()); settings.setValue("Password", ui->proxyPassword->text()); settings.endGroup(); ProfileManager::setStartingProfile(ui->startProfile->currentText()); m_pluginsList->save(); m_themesManager->save(); mApp->cookieJar()->loadSettings(); mApp->history()->loadSettings(); mApp->reloadSettings(); mApp->desktopNotifications()->loadSettings(); mApp->autoFill()->loadSettings(); mApp->networkManager()->loadSettings(); WebScrollBarManager::instance()->loadSettings(); } Preferences::~Preferences() { Settings().setValue(QSL("Preferences/Geometry"), saveGeometry()); delete ui; delete m_autoFillManager; delete m_pluginsList; delete m_notification.data(); } void Preferences::setProgressBarColorIcon(QColor color) { const int size = style()->pixelMetric(QStyle::PM_ToolBarIconSize); QPixmap pm(QSize(size, size)); if (!color.isValid()) { color = palette().color(QPalette::Highlight); } pm.fill(color); ui->customColorToolButton->setIcon(pm); ui->customColorToolButton->setProperty("ProgressColor", color); } void Preferences::selectCustomProgressBarColor() { QColor newColor = QColorDialog::getColor(ui->customColorToolButton->property("ProgressColor").value(), this, tr("Select Color")); if (newColor.isValid()) { setProgressBarColorIcon(newColor); } } diff --git a/src/lib/webengine/webinspector.cpp b/src/lib/webengine/webinspector.cpp index 1ef70e4d..ed4b5c8f 100644 --- a/src/lib/webengine/webinspector.cpp +++ b/src/lib/webengine/webinspector.cpp @@ -1,165 +1,165 @@ /* ============================================================ * 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 "webinspector.h" #include "mainapplication.h" #include "networkmanager.h" #include "settings.h" #include "webview.h" #include "webpage.h" #include #include #include #include #include QList WebInspector::s_views; WebInspector::WebInspector(QWidget *parent) : QWebEngineView(parent) , m_view(Q_NULLPTR) { setAttribute(Qt::WA_DeleteOnClose); setObjectName(QSL("web-inspector")); setMinimumHeight(80); m_height = Settings().value(QSL("Web-Inspector/height"), 80).toInt(); m_windowSize = Settings().value(QSL("Web-Inspector/windowSize"), QSize(640, 480)).toSize(); registerView(this); connect(page(), &QWebEnginePage::windowCloseRequested, this, &WebInspector::deleteLater); connect(page(), &QWebEnginePage::loadFinished, this, &WebInspector::loadFinished); } WebInspector::~WebInspector() { if (m_view && hasFocus()) { m_view->setFocus(); } unregisterView(this); if (isWindow()) { Settings().setValue(QSL("Web-Inspector/windowSize"), size()); } else { Settings().setValue(QSL("Web-Inspector/height"), height()); } } void WebInspector::setView(WebView *view) { m_view = view; Q_ASSERT(isEnabled()); -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 11, 0) page()->setInspectedPage(m_view->page()); connect(m_view, &WebView::pageChanged, this, &WebInspector::deleteLater); #else int port = qEnvironmentVariableIntValue("QTWEBENGINE_REMOTE_DEBUGGING"); QUrl inspectorUrl = QUrl(QSL("http://localhost:%1").arg(port)); int index = s_views.indexOf(m_view); QNetworkReply *reply = mApp->networkManager()->get(QNetworkRequest(inspectorUrl.resolved(QUrl("json/list")))); connect(reply, &QNetworkReply::finished, this, [=]() { QJsonArray clients = QJsonDocument::fromJson(reply->readAll()).array(); QUrl pageUrl; if (clients.size() > index) { QJsonObject object = clients.at(index).toObject(); pageUrl = inspectorUrl.resolved(QUrl(object.value(QSL("devtoolsFrontendUrl")).toString())); } load(pageUrl); pushView(this); show(); }); #endif } void WebInspector::inspectElement() { m_inspectElement = true; } bool WebInspector::isEnabled() { -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION < QT_VERSION_CHECK(5, 11, 0) if (!qEnvironmentVariableIsSet("QTWEBENGINE_REMOTE_DEBUGGING")) { return false; } #endif if (!mApp->webSettings()->testAttribute(QWebEngineSettings::JavascriptEnabled)) { return false; } return true; } void WebInspector::pushView(QWebEngineView *view) { s_views.removeOne(view); s_views.prepend(view); } void WebInspector::registerView(QWebEngineView *view) { s_views.prepend(view); } void WebInspector::unregisterView(QWebEngineView *view) { s_views.removeOne(view); } void WebInspector::loadFinished() { // Show close button only when docked if (!isWindow()) { page()->runJavaScript(QL1S("var button = Components.dockController._closeButton;" "button.setVisible(true);" "button.element.onmouseup = function() {" " window.close();" "};")); } // Inspect element if (m_inspectElement) { m_view->triggerPageAction(QWebEnginePage::InspectElement); m_inspectElement = false; } } QSize WebInspector::sizeHint() const { if (isWindow()) { return m_windowSize; } QSize s = QWebEngineView::sizeHint(); s.setHeight(m_height); return s; } void WebInspector::keyPressEvent(QKeyEvent *event) { Q_UNUSED(event) // Stop propagation } void WebInspector::keyReleaseEvent(QKeyEvent *event) { Q_UNUSED(event) // Stop propagation } diff --git a/src/lib/webengine/webview.cpp b/src/lib/webengine/webview.cpp index a570c34d..a94b5268 100644 --- a/src/lib/webengine/webview.cpp +++ b/src/lib/webengine/webview.cpp @@ -1,1370 +1,1370 @@ /* ============================================================ * 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 "webview.h" #include "webpage.h" #include "mainapplication.h" #include "qztools.h" #include "iconprovider.h" #include "history.h" #include "pluginproxy.h" #include "downloadmanager.h" #include "siteinfo.h" #include "searchenginesmanager.h" #include "browsinglibrary.h" #include "bookmarkstools.h" #include "settings.h" #include "qzsettings.h" #include "enhancedmenu.h" #include "locationbar.h" #include "webinspector.h" #include "scripts.h" #include "webhittestresult.h" #include "webscrollbarmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include bool WebView::s_forceContextMenuOnMouseRelease = false; WebView::WebView(QWidget* parent) : QWebEngineView(parent) , m_progress(100) , m_backgroundActivity(false) , m_page(0) , m_firstLoad(false) { connect(this, &QWebEngineView::loadStarted, this, &WebView::slotLoadStarted); connect(this, &QWebEngineView::loadProgress, this, &WebView::slotLoadProgress); connect(this, &QWebEngineView::loadFinished, this, &WebView::slotLoadFinished); connect(this, &QWebEngineView::iconChanged, this, &WebView::slotIconChanged); connect(this, &QWebEngineView::urlChanged, this, &WebView::slotUrlChanged); connect(this, &QWebEngineView::titleChanged, this, &WebView::slotTitleChanged); m_currentZoomLevel = zoomLevels().indexOf(100); setAcceptDrops(true); installEventFilter(this); if (parentWidget()) { parentWidget()->installEventFilter(this); } WebInspector::registerView(this); } WebView::~WebView() { mApp->plugins()->emitWebPageDeleted(m_page); WebInspector::unregisterView(this); WebScrollBarManager::instance()->removeWebView(this); } QIcon WebView::icon(bool allowNull) const { if (!QWebEngineView::icon().isNull()) { return QWebEngineView::icon(); } if (url().scheme() == QLatin1String("ftp")) { return IconProvider::standardIcon(QStyle::SP_ComputerIcon); } if (url().scheme() == QLatin1String("file")) { return IconProvider::standardIcon(QStyle::SP_DriveHDIcon); } return IconProvider::iconForUrl(url(), allowNull); } QString WebView::title(bool allowEmpty) const { QString title = QWebEngineView::title(); if (allowEmpty) { return title; } const QUrl u = url().isEmpty() ? m_page->requestedUrl() : url(); if (title.isEmpty()) { title = u.host(); } if (title.isEmpty()) { title = u.toString(QUrl::RemoveFragment); } if (title.isEmpty() || title == QL1S("about:blank")) { return tr("Empty Page"); } return title; } WebPage* WebView::page() const { return m_page; } void WebView::setPage(WebPage *page) { if (m_page == page) { return; } if (m_page) { if (m_page->isLoading()) { emit m_page->loadProgress(100); emit m_page->loadFinished(true); } mApp->plugins()->emitWebPageDeleted(m_page); m_page->setView(nullptr); } page->setParent(this); QWebEngineView::setPage(page); delete m_page; m_page = page; if (m_page->isLoading()) { emit loadStarted(); emit loadProgress(m_page->m_loadProgress); } connect(m_page, &WebPage::privacyChanged, this, &WebView::privacyChanged); connect(m_page, &WebPage::printRequested, this, &WebView::printPage); // Set default zoom level zoomReset(); // Actions needs to be initialized for every QWebEnginePage change initializeActions(); // Scrollbars must be added only after QWebEnginePage is set WebScrollBarManager::instance()->addWebView(this); emit pageChanged(m_page); mApp->plugins()->emitWebPageCreated(m_page); } void WebView::load(const QUrl &url) { if (m_page && !m_page->acceptNavigationRequest(url, QWebEnginePage::NavigationTypeTyped, true)) { return; } QWebEngineView::load(url); if (!m_firstLoad) { m_firstLoad = true; WebInspector::pushView(this); } } void WebView::load(const LoadRequest &request) { const QUrl reqUrl = request.url(); if (reqUrl.isEmpty()) return; if (reqUrl.scheme() == QL1S("javascript")) { const QString scriptSource = reqUrl.toString().mid(11); // Is the javascript source percent encoded or not? // Looking for % character in source should work in most cases if (scriptSource.contains(QL1C('%'))) page()->runJavaScript(QUrl::fromPercentEncoding(scriptSource.toUtf8())); else page()->runJavaScript(scriptSource); return; } if (isUrlValid(reqUrl)) { loadRequest(request); } } bool WebView::isLoading() const { return m_progress < 100; } int WebView::loadingProgress() const { return m_progress; } bool WebView::backgroundActivity() const { return m_backgroundActivity; } int WebView::zoomLevel() const { return m_currentZoomLevel; } void WebView::setZoomLevel(int level) { m_currentZoomLevel = level; applyZoom(); } QPointF WebView::mapToViewport(const QPointF &pos) const { return page()->mapToViewport(pos); } QRect WebView::scrollBarGeometry(Qt::Orientation orientation) const { QScrollBar *s = WebScrollBarManager::instance()->scrollBar(orientation, const_cast(this)); return s && s->isVisible() ? s->geometry() : QRect(); } QWidget *WebView::inputWidget() const { return m_rwhvqt ? m_rwhvqt : const_cast(this); } // static bool WebView::isUrlValid(const QUrl &url) { // Valid url must have scheme and actually contains something (therefore scheme:// is invalid) return url.isValid() && !url.scheme().isEmpty() && (!url.host().isEmpty() || !url.path().isEmpty() || url.hasQuery()); } // static QList WebView::zoomLevels() { return QList() << 30 << 40 << 50 << 67 << 80 << 90 << 100 << 110 << 120 << 133 << 150 << 170 << 200 << 220 << 233 << 250 << 270 << 285 << 300; } // static bool WebView::forceContextMenuOnMouseRelease() { return s_forceContextMenuOnMouseRelease; } // static void WebView::setForceContextMenuOnMouseRelease(bool force) { // Windows open context menu on mouse release by default #ifndef Q_OS_WIN s_forceContextMenuOnMouseRelease = force; #endif } void WebView::addNotification(QWidget* notif) { emit showNotification(notif); } void WebView::applyZoom() { setZoomFactor(qreal(zoomLevels().at(m_currentZoomLevel)) / 100.0); emit zoomLevelChanged(m_currentZoomLevel); } void WebView::zoomIn() { if (m_currentZoomLevel < zoomLevels().count() - 1) { m_currentZoomLevel++; applyZoom(); } } void WebView::zoomOut() { if (m_currentZoomLevel > 0) { m_currentZoomLevel--; applyZoom(); } } void WebView::zoomReset() { if (m_currentZoomLevel != qzSettings->defaultZoomLevel) { m_currentZoomLevel = qzSettings->defaultZoomLevel; applyZoom(); } } void WebView::editUndo() { triggerPageAction(QWebEnginePage::Undo); } void WebView::editRedo() { triggerPageAction(QWebEnginePage::Redo); } void WebView::editCut() { triggerPageAction(QWebEnginePage::Cut); } void WebView::editCopy() { triggerPageAction(QWebEnginePage::Copy); } void WebView::editPaste() { triggerPageAction(QWebEnginePage::Paste); } void WebView::editSelectAll() { triggerPageAction(QWebEnginePage::SelectAll); } void WebView::editDelete() { QKeyEvent ev(QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier); QApplication::sendEvent(this, &ev); } void WebView::reloadBypassCache() { triggerPageAction(QWebEnginePage::ReloadAndBypassCache); } void WebView::back() { QWebEngineHistory* history = page()->history(); if (history->canGoBack()) { history->back(); emit urlChanged(url()); } } void WebView::forward() { QWebEngineHistory* history = page()->history(); if (history->canGoForward()) { history->forward(); emit urlChanged(url()); } } void WebView::printPage() { Q_ASSERT(m_page); QPrinter *printer = new QPrinter(); printer->setCreator(tr("Falkon %1 (%2)").arg(Qz::VERSION, Qz::WWWADDRESS)); printer->setDocName(QzTools::filterCharsFromFilename(title())); QPrintDialog *dialog = new QPrintDialog(printer, this); dialog->setOptions(QAbstractPrintDialog::PrintToFile | QAbstractPrintDialog::PrintShowPageSize); #ifndef Q_OS_WIN dialog->setOption(QAbstractPrintDialog::PrintPageRange); dialog->setOption(QAbstractPrintDialog::PrintCollateCopies); #endif if (dialog->exec() == QDialog::Accepted) { if (dialog->printer()->outputFormat() == QPrinter::PdfFormat) { m_page->printToPdf(dialog->printer()->outputFileName(), dialog->printer()->pageLayout()); delete dialog; } else { m_page->print(dialog->printer(), [=](bool success) { Q_UNUSED(success); delete dialog; }); } } } void WebView::slotLoadStarted() { m_progress = 0; if (title(/*allowEmpty*/true).isEmpty()) { emit titleChanged(title()); } } void WebView::slotLoadProgress(int progress) { if (m_progress < 100) { m_progress = progress; } // QtWebEngine sometimes forgets applied zoom factor if (!qFuzzyCompare(zoomFactor(), zoomLevels().at(m_currentZoomLevel) / 100.0)) { applyZoom(); } } void WebView::slotLoadFinished(bool ok) { m_progress = 100; if (ok) mApp->history()->addHistoryEntry(this); } void WebView::slotIconChanged() { IconProvider::instance()->saveIcon(this); } void WebView::slotUrlChanged(const QUrl &url) { if (!url.isEmpty() && title(/*allowEmpty*/true).isEmpty()) { // Don't treat this as background activity change const bool oldActivity = m_backgroundActivity; m_backgroundActivity = true; emit titleChanged(title()); m_backgroundActivity = oldActivity; } } void WebView::slotTitleChanged(const QString &title) { Q_UNUSED(title) if (!isVisible() && !isLoading() && !m_backgroundActivity) { m_backgroundActivity = true; emit backgroundActivityChanged(m_backgroundActivity); } } void WebView::openUrlInNewWindow() { if (QAction* action = qobject_cast(sender())) { mApp->createWindow(Qz::BW_NewWindow, action->data().toUrl()); } } void WebView::sendTextByMail() { if (QAction* action = qobject_cast(sender())) { const QUrl mailUrl = QUrl::fromEncoded("mailto:%20?body=" + QUrl::toPercentEncoding(action->data().toString())); QDesktopServices::openUrl(mailUrl); } } void WebView::sendPageByMail() { const QUrl mailUrl = QUrl::fromEncoded("mailto:%20?body=" + QUrl::toPercentEncoding(url().toEncoded()) + "&subject=" + QUrl::toPercentEncoding(title())); QDesktopServices::openUrl(mailUrl); } void WebView::copyLinkToClipboard() { if (QAction* action = qobject_cast(sender())) { QApplication::clipboard()->setText(action->data().toUrl().toEncoded()); } } void WebView::savePageAs() { -#if HAVE_QTWEBENGINE_5_10 +#if QTWEBENGINE_VERSION >= QT_VERSION_CHECK(5, 10, 0) page()->runJavaScript(QSL("document.contentType"), WebPage::SafeJsWorld, [this](const QVariant &res) { const QSet webPageTypes = { QSL("text/html"), QSL("application/xhtml+xml") }; if (res.isNull() || webPageTypes.contains(res.toString())) { triggerPageAction(QWebEnginePage::SavePage); } else { page()->download(url()); } }); #else triggerPageAction(QWebEnginePage::SavePage); #endif } void WebView::copyImageToClipboard() { triggerPageAction(QWebEnginePage::CopyImageToClipboard); } void WebView::downloadLinkToDisk() { triggerPageAction(QWebEnginePage::DownloadLinkToDisk); } void WebView::downloadImageToDisk() { triggerPageAction(QWebEnginePage::DownloadImageToDisk); } void WebView::downloadMediaToDisk() { triggerPageAction(QWebEnginePage::DownloadMediaToDisk); } void WebView::openUrlInNewTab(const QUrl &url, Qz::NewTabPositionFlags position) { loadInNewTab(url, position); } void WebView::openActionUrl() { if (QAction* action = qobject_cast(sender())) { load(action->data().toUrl()); } } void WebView::showSource() { // view-source: doesn't work on itself and custom schemes if (url().scheme() == QL1S("view-source") || url().scheme() == QL1S("falkon") || url().scheme() == QL1S("qrc")) { page()->toHtml([](const QString &html) { std::cout << html.toLocal8Bit().constData() << std::endl; }); return; } triggerPageAction(QWebEnginePage::ViewSource); } void WebView::showSiteInfo() { SiteInfo* s = new SiteInfo(this); s->show(); } void WebView::searchSelectedText() { SearchEngine engine = mApp->searchEnginesManager()->defaultEngine(); if (QAction* act = qobject_cast(sender())) { if (act->data().isValid()) { engine = act->data().value(); } } const LoadRequest req = mApp->searchEnginesManager()->searchResult(engine, selectedText()); loadInNewTab(req, Qz::NT_SelectedTab); } void WebView::searchSelectedTextInBackgroundTab() { SearchEngine engine = mApp->searchEnginesManager()->defaultEngine(); if (QAction* act = qobject_cast(sender())) { if (act->data().isValid()) { engine = act->data().value(); } } const LoadRequest req = mApp->searchEnginesManager()->searchResult(engine, selectedText()); loadInNewTab(req, Qz::NT_NotSelectedTab); } void WebView::bookmarkLink() { if (QAction* action = qobject_cast(sender())) { if (action->data().isNull()) { BookmarksTools::addBookmarkDialog(this, url(), title()); } else { const QVariantList bData = action->data().value(); const QString bookmarkTitle = bData.at(1).toString().isEmpty() ? title() : bData.at(1).toString(); BookmarksTools::addBookmarkDialog(this, bData.at(0).toUrl(), bookmarkTitle); } } } void WebView::openUrlInSelectedTab() { if (QAction* action = qobject_cast(sender())) { openUrlInNewTab(action->data().toUrl(), Qz::NT_CleanSelectedTab); } } void WebView::openUrlInBackgroundTab() { if (QAction* action = qobject_cast(sender())) { openUrlInNewTab(action->data().toUrl(), Qz::NT_CleanNotSelectedTab); } } void WebView::userDefinedOpenUrlInNewTab(const QUrl &url, bool invert) { Qz::NewTabPositionFlags position = qzSettings->newTabPosition; if (invert) { if (position & Qz::NT_SelectedTab) { position &= ~Qz::NT_SelectedTab; position |= Qz::NT_NotSelectedTab; } else { position &= ~Qz::NT_NotSelectedTab; position |= Qz::NT_SelectedTab; } } QUrl actionUrl; if (!url.isEmpty()) { actionUrl = url; } else if (QAction* action = qobject_cast(sender())) { actionUrl = action->data().toUrl(); } openUrlInNewTab(actionUrl, position); } void WebView::userDefinedOpenUrlInBgTab(const QUrl &url) { QUrl actionUrl; if (!url.isEmpty()) { actionUrl = url; } else if (QAction* action = qobject_cast(sender())) { actionUrl = action->data().toUrl(); } userDefinedOpenUrlInNewTab(actionUrl, true); } void WebView::showEvent(QShowEvent *event) { QWebEngineView::showEvent(event); if (m_backgroundActivity) { m_backgroundActivity = false; emit backgroundActivityChanged(m_backgroundActivity); } } void WebView::createContextMenu(QMenu *menu, WebHitTestResult &hitTest) { // cppcheck-suppress variableScope int spellCheckActionCount = 0; const QWebEngineContextMenuData &contextMenuData = page()->contextMenuData(); hitTest.updateWithContextMenuData(contextMenuData); if (!contextMenuData.misspelledWord().isEmpty()) { QFont boldFont = menu->font(); boldFont.setBold(true); for (const QString &suggestion : contextMenuData.spellCheckerSuggestions()) { QAction *action = menu->addAction(suggestion); action->setFont(boldFont); connect(action, &QAction::triggered, this, [=]() { page()->replaceMisspelledWord(suggestion); }); } if (menu->actions().isEmpty()) { menu->addAction(tr("No suggestions"))->setEnabled(false); } menu->addSeparator(); spellCheckActionCount = menu->actions().count(); } if (!hitTest.linkUrl().isEmpty() && hitTest.linkUrl().scheme() != QL1S("javascript")) { createLinkContextMenu(menu, hitTest); } if (!hitTest.imageUrl().isEmpty()) { createImageContextMenu(menu, hitTest); } if (!hitTest.mediaUrl().isEmpty()) { createMediaContextMenu(menu, hitTest); } if (hitTest.isContentEditable()) { // This only checks if the menu is empty (only spellchecker actions added) if (menu->actions().count() == spellCheckActionCount) { menu->addAction(pageAction(QWebEnginePage::Undo)); menu->addAction(pageAction(QWebEnginePage::Redo)); menu->addSeparator(); menu->addAction(pageAction(QWebEnginePage::Cut)); menu->addAction(pageAction(QWebEnginePage::Copy)); menu->addAction(pageAction(QWebEnginePage::Paste)); } if (hitTest.tagName() == QL1S("input")) { QAction *act = menu->addAction(QString()); act->setVisible(false); checkForForm(act, hitTest.pos()); } } if (!selectedText().isEmpty()) { createSelectedTextContextMenu(menu, hitTest); } if (menu->isEmpty()) { createPageContextMenu(menu); } menu->addSeparator(); mApp->plugins()->populateWebViewMenu(menu, this, hitTest); } void WebView::createPageContextMenu(QMenu* menu) { QAction* action = menu->addAction(tr("&Back"), this, SLOT(back())); action->setIcon(IconProvider::standardIcon(QStyle::SP_ArrowBack)); action->setEnabled(history()->canGoBack()); action = menu->addAction(tr("&Forward"), this, SLOT(forward())); action->setIcon(IconProvider::standardIcon(QStyle::SP_ArrowForward)); action->setEnabled(history()->canGoForward()); // Special menu for Speed Dial page if (url().toString() == QL1S("falkon:speeddial")) { menu->addSeparator(); menu->addAction(QIcon::fromTheme("list-add"), tr("&Add New Page"), this, SLOT(addSpeedDial())); menu->addAction(IconProvider::settingsIcon(), tr("&Configure Speed Dial"), this, SLOT(configureSpeedDial())); menu->addSeparator(); menu->addAction(QIcon::fromTheme(QSL("view-refresh")), tr("Reload All Dials"), this, SLOT(reloadAllSpeedDials())); return; } QAction *reloadAction = pageAction(QWebEnginePage::Reload); action = menu->addAction(reloadAction->icon(), reloadAction->text(), reloadAction, &QAction::trigger); action->setVisible(reloadAction->isEnabled()); connect(reloadAction, &QAction::changed, action, [=]() { action->setVisible(reloadAction->isEnabled()); }); QAction *stopAction = pageAction(QWebEnginePage::Stop); action = menu->addAction(stopAction->icon(), stopAction->text(), stopAction, &QAction::trigger); action->setVisible(stopAction->isEnabled()); connect(stopAction, &QAction::changed, action, [=]() { action->setVisible(stopAction->isEnabled()); }); menu->addSeparator(); menu->addAction(QIcon::fromTheme("bookmark-new"), tr("Book&mark page"), this, SLOT(bookmarkLink())); menu->addAction(QIcon::fromTheme("document-save"), tr("&Save page as..."), this, SLOT(savePageAs())); menu->addAction(QIcon::fromTheme("edit-copy"), tr("&Copy page link"), this, SLOT(copyLinkToClipboard()))->setData(url()); menu->addAction(QIcon::fromTheme("mail-message-new"), tr("Send page link..."), this, SLOT(sendPageByMail())); menu->addSeparator(); menu->addAction(QIcon::fromTheme("edit-select-all"), tr("Select &all"), this, SLOT(editSelectAll())); menu->addSeparator(); const QString scheme = url().scheme(); if (scheme != QL1S("view-source") && WebPage::internalSchemes().contains(scheme)) { menu->addAction(QIcon::fromTheme("text-html"), tr("Show so&urce code"), this, SLOT(showSource())); } if (SiteInfo::canShowSiteInfo(url())) menu->addAction(QIcon::fromTheme("dialog-information"), tr("Show info ab&out site"), this, SLOT(showSiteInfo())); } void WebView::createLinkContextMenu(QMenu* menu, const WebHitTestResult &hitTest) { menu->addSeparator(); Action* act = new Action(IconProvider::newTabIcon(), tr("Open link in new &tab")); act->setData(hitTest.linkUrl()); connect(act, SIGNAL(triggered()), this, SLOT(userDefinedOpenUrlInNewTab())); connect(act, SIGNAL(ctrlTriggered()), this, SLOT(userDefinedOpenUrlInBgTab())); menu->addAction(act); menu->addAction(IconProvider::newWindowIcon(), tr("Open link in new &window"), this, SLOT(openUrlInNewWindow()))->setData(hitTest.linkUrl()); menu->addAction(IconProvider::privateBrowsingIcon(), tr("Open link in &private window"), mApp, SLOT(startPrivateBrowsing()))->setData(hitTest.linkUrl()); menu->addSeparator(); QVariantList bData; bData << hitTest.linkUrl() << hitTest.linkTitle(); menu->addAction(QIcon::fromTheme("bookmark-new"), tr("B&ookmark link"), this, SLOT(bookmarkLink()))->setData(bData); menu->addAction(QIcon::fromTheme("document-save"), tr("&Save link as..."), this, SLOT(downloadLinkToDisk())); menu->addAction(QIcon::fromTheme("mail-message-new"), tr("Send link..."), this, SLOT(sendTextByMail()))->setData(hitTest.linkUrl().toEncoded()); menu->addAction(QIcon::fromTheme("edit-copy"), tr("&Copy link address"), this, SLOT(copyLinkToClipboard()))->setData(hitTest.linkUrl()); menu->addSeparator(); if (!selectedText().isEmpty()) { pageAction(QWebEnginePage::Copy)->setIcon(QIcon::fromTheme("edit-copy")); menu->addAction(pageAction(QWebEnginePage::Copy)); } } void WebView::createImageContextMenu(QMenu* menu, const WebHitTestResult &hitTest) { menu->addSeparator(); if (hitTest.imageUrl() != url()) { Action *act = new Action(tr("Show i&mage")); act->setData(hitTest.imageUrl()); connect(act, SIGNAL(triggered()), this, SLOT(openActionUrl())); connect(act, SIGNAL(ctrlTriggered()), this, SLOT(userDefinedOpenUrlInNewTab())); menu->addAction(act); } menu->addAction(tr("Copy image"), this, SLOT(copyImageToClipboard())); menu->addAction(QIcon::fromTheme("edit-copy"), tr("Copy image ad&dress"), this, SLOT(copyLinkToClipboard()))->setData(hitTest.imageUrl()); menu->addSeparator(); menu->addAction(QIcon::fromTheme("document-save"), tr("&Save image as..."), this, SLOT(downloadImageToDisk())); menu->addAction(QIcon::fromTheme("mail-message-new"), tr("Send image..."), this, SLOT(sendTextByMail()))->setData(hitTest.imageUrl().toEncoded()); menu->addSeparator(); if (!selectedText().isEmpty()) { pageAction(QWebEnginePage::Copy)->setIcon(QIcon::fromTheme("edit-copy")); menu->addAction(pageAction(QWebEnginePage::Copy)); } } void WebView::createSelectedTextContextMenu(QMenu* menu, const WebHitTestResult &hitTest) { Q_UNUSED(hitTest) QString selectedText = page()->selectedText(); menu->addSeparator(); if (!menu->actions().contains(pageAction(QWebEnginePage::Copy))) { menu->addAction(pageAction(QWebEnginePage::Copy)); } menu->addAction(QIcon::fromTheme("mail-message-new"), tr("Send text..."), this, SLOT(sendTextByMail()))->setData(selectedText); menu->addSeparator(); // #379: Remove newlines QString selectedString = selectedText.trimmed().remove(QLatin1Char('\n')); if (!selectedString.contains(QLatin1Char('.'))) { // Try to add .com selectedString.append(QLatin1String(".com")); } QUrl guessedUrl = QUrl::fromUserInput(selectedString); if (isUrlValid(guessedUrl)) { Action* act = new Action(QIcon::fromTheme("document-open-remote"), tr("Go to &web address")); act->setData(guessedUrl); connect(act, SIGNAL(triggered()), this, SLOT(openActionUrl())); connect(act, SIGNAL(ctrlTriggered()), this, SLOT(userDefinedOpenUrlInNewTab())); menu->addAction(act); } menu->addSeparator(); selectedText.truncate(20); // KDE is displaying newlines in menu actions ... weird -,- selectedText.replace(QLatin1Char('\n'), QLatin1Char(' ')).replace(QLatin1Char('\t'), QLatin1Char(' ')); SearchEngine engine = mApp->searchEnginesManager()->defaultEngine(); Action* act = new Action(engine.icon, tr("Search \"%1 ..\" with %2").arg(selectedText, engine.name)); connect(act, SIGNAL(triggered()), this, SLOT(searchSelectedText())); connect(act, SIGNAL(ctrlTriggered()), this, SLOT(searchSelectedTextInBackgroundTab())); menu->addAction(act); // Search with ... Menu* swMenu = new Menu(tr("Search with..."), menu); swMenu->setCloseOnMiddleClick(true); SearchEnginesManager* searchManager = mApp->searchEnginesManager(); foreach (const SearchEngine &en, searchManager->allEngines()) { Action* act = new Action(en.icon, en.name); act->setData(QVariant::fromValue(en)); connect(act, SIGNAL(triggered()), this, SLOT(searchSelectedText())); connect(act, SIGNAL(ctrlTriggered()), this, SLOT(searchSelectedTextInBackgroundTab())); swMenu->addAction(act); } menu->addMenu(swMenu); } void WebView::createMediaContextMenu(QMenu *menu, const WebHitTestResult &hitTest) { bool paused = hitTest.mediaPaused(); bool muted = hitTest.mediaMuted(); menu->addSeparator(); menu->addAction(paused ? tr("&Play") : tr("&Pause"), this, SLOT(toggleMediaPause()))->setIcon(QIcon::fromTheme(paused ? "media-playback-start" : "media-playback-pause")); menu->addAction(muted ? tr("Un&mute") : tr("&Mute"), this, SLOT(toggleMediaMute()))->setIcon(QIcon::fromTheme(muted ? "audio-volume-muted" : "audio-volume-high")); menu->addSeparator(); menu->addAction(QIcon::fromTheme("edit-copy"), tr("&Copy Media Address"), this, SLOT(copyLinkToClipboard()))->setData(hitTest.mediaUrl()); menu->addAction(QIcon::fromTheme("mail-message-new"), tr("&Send Media Address"), this, SLOT(sendTextByMail()))->setData(hitTest.mediaUrl().toEncoded()); menu->addAction(QIcon::fromTheme("document-save"), tr("Save Media To &Disk"), this, SLOT(downloadMediaToDisk())); } void WebView::checkForForm(QAction *action, const QPoint &pos) { m_clickedPos = mapToViewport(pos); QPointer act = action; page()->runJavaScript(Scripts::getFormData(m_clickedPos), WebPage::SafeJsWorld, [this, act](const QVariant &res) { const QVariantMap &map = res.toMap(); if (!act || map.isEmpty()) return; const QUrl url = map.value(QSL("action")).toUrl(); const QString method = map.value(QSL("method")).toString(); if (!url.isEmpty() && (method == QL1S("get") || method == QL1S("post"))) { act->setVisible(true); act->setIcon(QIcon::fromTheme(QSL("edit-find"), QIcon(QSL(":icons/menu/search-icon.svg")))); act->setText(tr("Create Search Engine")); connect(act.data(), &QAction::triggered, this, &WebView::createSearchEngine); } }); } void WebView::createSearchEngine() { page()->runJavaScript(Scripts::getFormData(m_clickedPos), WebPage::SafeJsWorld, [this](const QVariant &res) { mApp->searchEnginesManager()->addEngineFromForm(res.toMap(), this); }); } void WebView::addSpeedDial() { page()->runJavaScript("addSpeedDial()"); } void WebView::configureSpeedDial() { page()->runJavaScript("configureSpeedDial()"); } void WebView::reloadAllSpeedDials() { page()->runJavaScript("reloadAll()"); } void WebView::toggleMediaPause() { triggerPageAction(QWebEnginePage::ToggleMediaPlayPause); } void WebView::toggleMediaMute() { triggerPageAction(QWebEnginePage::ToggleMediaMute); } void WebView::initializeActions() { QAction* undoAction = pageAction(QWebEnginePage::Undo); undoAction->setText(tr("&Undo")); undoAction->setShortcut(QKeySequence("Ctrl+Z")); undoAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); undoAction->setIcon(QIcon::fromTheme(QSL("edit-undo"))); QAction* redoAction = pageAction(QWebEnginePage::Redo); redoAction->setText(tr("&Redo")); redoAction->setShortcut(QKeySequence("Ctrl+Shift+Z")); redoAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); redoAction->setIcon(QIcon::fromTheme(QSL("edit-redo"))); QAction* cutAction = pageAction(QWebEnginePage::Cut); cutAction->setText(tr("&Cut")); cutAction->setShortcut(QKeySequence("Ctrl+X")); cutAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); cutAction->setIcon(QIcon::fromTheme(QSL("edit-cut"))); QAction* copyAction = pageAction(QWebEnginePage::Copy); copyAction->setText(tr("&Copy")); copyAction->setShortcut(QKeySequence("Ctrl+C")); copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); copyAction->setIcon(QIcon::fromTheme(QSL("edit-copy"))); QAction* pasteAction = pageAction(QWebEnginePage::Paste); pasteAction->setText(tr("&Paste")); pasteAction->setShortcut(QKeySequence("Ctrl+V")); pasteAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); pasteAction->setIcon(QIcon::fromTheme(QSL("edit-paste"))); QAction* selectAllAction = pageAction(QWebEnginePage::SelectAll); selectAllAction->setText(tr("Select All")); selectAllAction->setShortcut(QKeySequence("Ctrl+A")); selectAllAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); selectAllAction->setIcon(QIcon::fromTheme(QSL("edit-select-all"))); QAction* reloadAction = pageAction(QWebEnginePage::Reload); reloadAction->setText(tr("&Reload")); reloadAction->setIcon(QIcon::fromTheme(QSL("view-refresh"))); QAction* stopAction = pageAction(QWebEnginePage::Stop); stopAction->setText(tr("S&top")); stopAction->setIcon(QIcon::fromTheme(QSL("process-stop"))); // Make action shortcuts available for webview addAction(undoAction); addAction(redoAction); addAction(cutAction); addAction(copyAction); addAction(pasteAction); addAction(selectAllAction); } void WebView::_wheelEvent(QWheelEvent *event) { if (mApp->plugins()->processWheelEvent(Qz::ON_WebView, this, event)) { event->accept(); return; } if (event->modifiers() & Qt::ControlModifier) { m_wheelHelper.processEvent(event); while (WheelHelper::Direction direction = m_wheelHelper.takeDirection()) { switch (direction) { case WheelHelper::WheelUp: case WheelHelper::WheelLeft: zoomIn(); break; case WheelHelper::WheelDown: case WheelHelper::WheelRight: zoomOut(); break; default: break; } } event->accept(); return; } m_wheelHelper.reset(); // QtWebEngine ignores QApplication::wheelScrollLines() and instead always scrolls 3 lines if (event->spontaneous()) { const qreal multiplier = QApplication::wheelScrollLines() / 3.0; if (multiplier != 1.0) { QWheelEvent e(event->pos(), event->globalPos(), event->pixelDelta(), event->angleDelta() * multiplier, 0, Qt::Horizontal, event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted()); QApplication::sendEvent(m_rwhvqt, &e); event->accept(); } } } void WebView::_mousePressEvent(QMouseEvent *event) { m_clickedUrl = QUrl(); m_clickedPos = QPointF(); if (mApp->plugins()->processMousePress(Qz::ON_WebView, this, event)) { event->accept(); return; } switch (event->button()) { case Qt::XButton1: back(); event->accept(); break; case Qt::XButton2: forward(); event->accept(); break; case Qt::MiddleButton: m_clickedUrl = page()->hitTestContent(event->pos()).linkUrl(); if (!m_clickedUrl.isEmpty()) event->accept(); break; case Qt::LeftButton: m_clickedUrl = page()->hitTestContent(event->pos()).linkUrl(); break; default: break; } } void WebView::_mouseReleaseEvent(QMouseEvent *event) { if (mApp->plugins()->processMouseRelease(Qz::ON_WebView, this, event)) { event->accept(); return; } switch (event->button()) { case Qt::MiddleButton: if (!m_clickedUrl.isEmpty()) { const QUrl link = page()->hitTestContent(event->pos()).linkUrl(); if (m_clickedUrl == link && isUrlValid(link)) { userDefinedOpenUrlInNewTab(link, event->modifiers() & Qt::ShiftModifier); event->accept(); } } break; case Qt::LeftButton: if (!m_clickedUrl.isEmpty()) { const QUrl link = page()->hitTestContent(event->pos()).linkUrl(); if (m_clickedUrl == link && isUrlValid(link)) { if (event->modifiers() & Qt::ControlModifier) { userDefinedOpenUrlInNewTab(link, event->modifiers() & Qt::ShiftModifier); event->accept(); } } } break; case Qt::RightButton: if (s_forceContextMenuOnMouseRelease) { QContextMenuEvent ev(QContextMenuEvent::Mouse, event->pos(), event->globalPos(), event->modifiers()); _contextMenuEvent(&ev); event->accept(); } break; default: break; } } void WebView::_mouseMoveEvent(QMouseEvent *event) { if (mApp->plugins()->processMouseMove(Qz::ON_WebView, this, event)) { event->accept(); } } void WebView::_keyPressEvent(QKeyEvent *event) { if (mApp->plugins()->processKeyPress(Qz::ON_WebView, this, event)) { event->accept(); return; } switch (event->key()) { case Qt::Key_ZoomIn: zoomIn(); event->accept(); break; case Qt::Key_ZoomOut: zoomOut(); event->accept(); break; case Qt::Key_Plus: if (event->modifiers() & Qt::ControlModifier) { zoomIn(); event->accept(); } break; case Qt::Key_Minus: if (event->modifiers() & Qt::ControlModifier) { zoomOut(); event->accept(); } break; case Qt::Key_0: if (event->modifiers() & Qt::ControlModifier) { zoomReset(); event->accept(); } break; case Qt::Key_M: if (event->modifiers() & Qt::ControlModifier) { page()->setAudioMuted(!page()->isAudioMuted()); event->accept(); } break; default: break; } } void WebView::_keyReleaseEvent(QKeyEvent *event) { if (mApp->plugins()->processKeyRelease(Qz::ON_WebView, this, event)) { event->accept(); } switch (event->key()) { case Qt::Key_Escape: if (isFullScreen()) { triggerPageAction(QWebEnginePage::ExitFullScreen); event->accept(); } break; default: break; } } void WebView::_contextMenuEvent(QContextMenuEvent *event) { Q_UNUSED(event) } void WebView::resizeEvent(QResizeEvent *event) { QWebEngineView::resizeEvent(event); emit viewportResized(size()); } void WebView::contextMenuEvent(QContextMenuEvent *event) { // Context menu is created in mouseReleaseEvent if (s_forceContextMenuOnMouseRelease) return; const QPoint pos = event->pos(); const QContextMenuEvent::Reason reason = event->reason(); QTimer::singleShot(0, this, [this, pos, reason]() { QContextMenuEvent ev(reason, pos); _contextMenuEvent(&ev); }); } bool WebView::focusNextPrevChild(bool next) { -#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) +#if QTWEBENGINE_VERSION < QT_VERSION_CHECK(5, 11, 0) // QTBUG-67043 // Workaround QtWebEngine issue where QWebEngineView loses focus on second load() call. if (next) { setFocus(); return false; } #endif return QWebEngineView::focusNextPrevChild(next); } void WebView::loadRequest(const LoadRequest &req) { QWebEngineView::load(req.webRequest()); } bool WebView::eventFilter(QObject *obj, QEvent *event) { // Keyboard events are sent to parent widget if (obj == this && event->type() == QEvent::ParentChange && parentWidget()) { parentWidget()->installEventFilter(this); } // Hack to find widget that receives input events if (obj == this && event->type() == QEvent::ChildAdded) { QTimer::singleShot(0, this, [this]() { if (focusProxy() && m_rwhvqt != focusProxy()) { m_rwhvqt = focusProxy(); m_rwhvqt->installEventFilter(this); if (QQuickWidget *w = qobject_cast(m_rwhvqt)) { w->setClearColor(palette().color(QPalette::Window)); } } }); } // Forward events to WebView #define HANDLE_EVENT(f, t) \ { \ bool wasAccepted = event->isAccepted(); \ event->setAccepted(false); \ f(static_cast(event)); \ bool ret = event->isAccepted(); \ event->setAccepted(wasAccepted); \ return ret; \ } if (obj == m_rwhvqt) { switch (event->type()) { case QEvent::MouseButtonPress: HANDLE_EVENT(_mousePressEvent, QMouseEvent); case QEvent::MouseButtonRelease: HANDLE_EVENT(_mouseReleaseEvent, QMouseEvent); case QEvent::MouseMove: HANDLE_EVENT(_mouseMoveEvent, QMouseEvent); case QEvent::Wheel: HANDLE_EVENT(_wheelEvent, QWheelEvent); default: break; } } if (obj == parentWidget()) { switch (event->type()) { case QEvent::KeyPress: HANDLE_EVENT(_keyPressEvent, QKeyEvent); case QEvent::KeyRelease: HANDLE_EVENT(_keyReleaseEvent, QKeyEvent); default: break; } } #undef HANDLE_EVENT // Block already handled events if (obj == this) { switch (event->type()) { case QEvent::KeyPress: case QEvent::KeyRelease: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: case QEvent::Wheel: return true; case QEvent::Hide: if (isFullScreen()) { triggerPageAction(QWebEnginePage::ExitFullScreen); } break; default: break; } } const bool res = QWebEngineView::eventFilter(obj, event); if (obj == m_rwhvqt) { switch (event->type()) { case QEvent::FocusIn: case QEvent::FocusOut: emit focusChanged(hasFocus()); break; default: break; } } return res; }