diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index d0172d33..5b3e02ed 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,325 +1,327 @@ 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 if (WIN32) add_definitions(-DQT_QTSINGLEAPPLICATION_EXPORT=) endif() set(SRCS 3rdparty/qtsingleapplication/qtsingleapplication.cpp 3rdparty/qtsingleapplication/qtlocalpeer.cpp ) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/qtsingleapplication) 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 ) 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 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/networkproxyfactory.cpp network/networkurlinterceptor.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/statusbarmessage.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/tabstackedwidget.cpp tabwidget/tabwidget.cpp tabwidget/tabcontextmenu.cpp tools/abstractbuttoninterface.cpp tools/aesinterface.cpp tools/animatedwidget.cpp tools/buttonbox.cpp tools/buttonwithmenu.cpp tools/certificateinfowidget.cpp tools/clickablelabel.cpp tools/closedtabsmanager.cpp tools/closedwindowsmanager.cpp tools/colors.cpp tools/delayedfilewatcher.cpp tools/docktitlebarwidget.cpp tools/emptynetworkreply.cpp tools/enhancedmenu.cpp tools/focusselectlineedit.cpp tools/frame.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/qzregexp.cpp tools/qztools.cpp tools/removeitemfocusdelegate.cpp tools/scripts.cpp tools/sqldatabase.cpp tools/toolbutton.cpp tools/treewidget.cpp tools/widget.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}) target_link_libraries(FalkonPrivate Qt5::Widgets Qt5::WebEngineWidgets Qt5::Network Qt5::Sql Qt5::PrintSupport Qt5::QuickWidgets Qt5::WebChannel) if (UNIX AND NOT APPLE) if (NOT NO_X11) target_link_libraries(FalkonPrivate XCB::XCB Qt5::X11Extras) endif() target_link_libraries(FalkonPrivate crypto) set_target_properties(FalkonPrivate PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION "2") install(TARGETS FalkonPrivate ${KDE_INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP) endif() if (WIN32) target_link_libraries(FalkonPrivate Qt5::WinExtras) target_link_libraries(FalkonPrivate libeay32) endif() if (APPLE) # homebrew openssl execute_process(COMMAND "readlink `brew --prefix openssl` | sed 's/..//'" OUTPUT_VARIABLE READLINK_OUTPUT) set(BREW_OPENSSL "/usr/local${READLINK_OUTPUT}") include_directories(${BREW_OPENSSL}/include) target_link_libraries(FalkonPrivate ${BREW_OPENSSL}/lib/libcrypto.so "-framework CoreServices -framework AppKit") endif() if (NOT DISABLE_DBUS) target_link_libraries(FalkonPrivate Qt5::DBus) endif() diff --git a/src/lib/adblock/adblock.qrc b/src/lib/adblock/adblock.qrc new file mode 100644 index 00000000..903bcb64 --- /dev/null +++ b/src/lib/adblock/adblock.qrc @@ -0,0 +1,7 @@ + + + data/adblock.png + data/adblock_big.png + data/adblock.html + + diff --git a/src/lib/adblock/adblockicon.cpp b/src/lib/adblock/adblockicon.cpp index 5d0a755d..dd430b17 100644 --- a/src/lib/adblock/adblockicon.cpp +++ b/src/lib/adblock/adblockicon.cpp @@ -1,187 +1,187 @@ /* ============================================================ * 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 "adblockicon.h" #include "adblockrule.h" #include "adblockmanager.h" #include "adblocksubscription.h" #include "mainapplication.h" #include "browserwindow.h" #include "webpage.h" #include "tabbedwebview.h" #include "tabwidget.h" #include "desktopnotificationsfactory.h" #include "qztools.h" #include AdBlockIcon::AdBlockIcon(QObject *parent) : AbstractButtonInterface(parent) { setTitle(tr("AdBlock")); - setIcon(QIcon(QSL(":icons/other/adblock.png"))); + setIcon(QIcon(QSL(":adblock/data/adblock.png"))); updateState(); connect(this, &AbstractButtonInterface::clicked, this, &AdBlockIcon::clicked); connect(this, &AbstractButtonInterface::webPageChanged, this, &AdBlockIcon::webPageChanged); connect(AdBlockManager::instance(), &AdBlockManager::enabledChanged, this, &AdBlockIcon::updateState); } AdBlockIcon::~AdBlockIcon() { for (int i = 0; i < m_blockedPopups.count(); ++i) delete m_blockedPopups.at(i).first; } QString AdBlockIcon::id() const { return QSL("adblock-icon"); } QString AdBlockIcon::name() const { return tr("AdBlock Icon"); } void AdBlockIcon::popupBlocked(const QString &ruleString, const QUrl &url) { int index = ruleString.lastIndexOf(QLatin1String(" (")); const QString subscriptionName = ruleString.left(index); const QString filter = ruleString.mid(index + 2, ruleString.size() - index - 3); AdBlockSubscription* subscription = AdBlockManager::instance()->subscriptionByName(subscriptionName); if (filter.isEmpty() || !subscription) { return; } QPair pair; pair.first = new AdBlockRule(filter, subscription); pair.second = url; m_blockedPopups.append(pair); mApp->desktopNotifications()->showNotification(QPixmap(":html/adblock_big.png"), tr("Blocked popup window"), tr("AdBlock blocked unwanted popup window.")); } void AdBlockIcon::toggleCustomFilter() { QAction* action = qobject_cast(sender()); if (!action) { return; } const QString filter = action->data().toString(); AdBlockManager* manager = AdBlockManager::instance(); AdBlockCustomList* customList = manager->customList(); if (customList->containsFilter(filter)) { customList->removeFilter(filter); } else { AdBlockRule* rule = new AdBlockRule(filter, customList); customList->addRule(rule); } } void AdBlockIcon::updateState() { WebPage *page = webPage(); if (!page) { setActive(false); setToolTip(name()); return; } if (!AdBlockManager::instance()->isEnabled()) { setActive(false); setToolTip(tr("AdBlock is disabled")); return; } if (!AdBlockManager::instance()->canRunOnScheme(page->url().scheme())) { setActive(false); setToolTip(tr("AdBlock is disabled on this site ")); return; } setActive(true); setToolTip(tr("AdBlock is active")); } void AdBlockIcon::webPageChanged(WebPage *page) { updateState(); if (m_page) { disconnect(m_page.data(), &QWebEnginePage::urlChanged, this, &AdBlockIcon::updateState); } m_page = page; if (m_page) { connect(m_page.data(), &QWebEnginePage::urlChanged, this, &AdBlockIcon::updateState); } } void AdBlockIcon::clicked(ClickController *controller) { WebPage *page = webPage(); if (!page) { return; } AdBlockManager* manager = AdBlockManager::instance(); AdBlockCustomList* customList = manager->customList(); const QUrl pageUrl = page->url(); QMenu menu; menu.addAction(tr("Show AdBlock &Settings"), manager, SLOT(showDialog())); menu.addSeparator(); if (!pageUrl.host().isEmpty() && manager->isEnabled() && manager->canRunOnScheme(pageUrl.scheme())) { const QString host = page->url().host().contains(QLatin1String("www.")) ? pageUrl.host().mid(4) : pageUrl.host(); const QString hostFilter = QString("@@||%1^$document").arg(host); const QString pageFilter = QString("@@|%1|$document").arg(pageUrl.toString()); QAction* act = menu.addAction(tr("Disable on %1").arg(host)); act->setCheckable(true); act->setChecked(customList->containsFilter(hostFilter)); act->setData(hostFilter); connect(act, SIGNAL(triggered()), this, SLOT(toggleCustomFilter())); act = menu.addAction(tr("Disable only on this page")); act->setCheckable(true); act->setChecked(customList->containsFilter(pageFilter)); act->setData(pageFilter); connect(act, SIGNAL(triggered()), this, SLOT(toggleCustomFilter())); menu.addSeparator(); } if (!m_blockedPopups.isEmpty()) { menu.addAction(tr("Blocked Popup Windows"))->setEnabled(false); for (int i = 0; i < m_blockedPopups.count(); i++) { const QPair &pair = m_blockedPopups.at(i); QString address = pair.second.toString().right(55); QString actionText = tr("%1 with (%2)").arg(address, pair.first->filter()).replace(QLatin1Char('&'), QLatin1String("&&")); QAction* action = menu.addAction(actionText, manager, SLOT(showRule())); action->setData(QVariant::fromValue((void*)pair.first)); } } menu.exec(controller->popupPosition(menu.sizeHint())); } diff --git a/src/lib/adblock/adblockplugin.cpp b/src/lib/adblock/adblockplugin.cpp new file mode 100644 index 00000000..5b138a4e --- /dev/null +++ b/src/lib/adblock/adblockplugin.cpp @@ -0,0 +1,61 @@ +/* ============================================================ +* QupZilla - Qt web browser +* Copyright (C) 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 "adblockplugin.h" +#include "adblockmanager.h" +#include "adblockicon.h" + +#include "scripts.h" +#include "webpage.h" +#include "pluginproxy.h" +#include "browserwindow.h" +#include "navigationbar.h" +#include "mainapplication.h" + +AdBlockPlugin::AdBlockPlugin(QObject *parent) + : QObject(parent) +{ + connect(mApp, &MainApplication::aboutToQuit, AdBlockManager::instance(), &AdBlockManager::save); + connect(mApp->plugins(), &PluginProxy::webPageCreated, this, &AdBlockPlugin::webPageCreated); + connect(mApp->plugins(), &PluginProxy::mainWindowCreated, this, &AdBlockPlugin::mainWindowCreated); +} + +void AdBlockPlugin::webPageCreated(WebPage *page) +{ + connect(page, &WebPage::loadFinished, this, [=]() { + AdBlockManager *manager = AdBlockManager::instance(); + if (!manager->isEnabled()) { + return; + } + // Apply global element hiding rules + const QString elementHiding = manager->elementHidingRules(page->url()); + if (!elementHiding.isEmpty()) { + page->runJavaScript(Scripts::setCss(elementHiding), WebPage::SafeJsWorld); + } + // Apply domain-specific element hiding rules + const QString siteElementHiding = manager->elementHidingRulesForDomain(page->url()); + if (!siteElementHiding.isEmpty()) { + page->runJavaScript(Scripts::setCss(siteElementHiding), WebPage::SafeJsWorld); + } + }); +} + +void AdBlockPlugin::mainWindowCreated(BrowserWindow *window) +{ + window->navigationBar()->addToolButton(new AdBlockIcon(window)); +} diff --git a/src/lib/adblock/adblockplugin.h b/src/lib/adblock/adblockplugin.h new file mode 100644 index 00000000..64372ef6 --- /dev/null +++ b/src/lib/adblock/adblockplugin.h @@ -0,0 +1,33 @@ +/* ============================================================ +* QupZilla - Qt web browser +* Copyright (C) 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 . +* ============================================================ */ +#pragma once + +#include + +class WebPage; +class BrowserWindow; + +class AdBlockPlugin : public QObject +{ +public: + explicit AdBlockPlugin(QObject *parent = nullptr); + +private: + void webPageCreated(WebPage *page); + void mainWindowCreated(BrowserWindow *window); +}; diff --git a/src/lib/data/html/adblock.html b/src/lib/adblock/data/adblock.html similarity index 100% rename from src/lib/data/html/adblock.html rename to src/lib/adblock/data/adblock.html diff --git a/src/lib/data/icons/other/adblock.png b/src/lib/adblock/data/adblock.png similarity index 100% rename from src/lib/data/icons/other/adblock.png rename to src/lib/adblock/data/adblock.png diff --git a/src/lib/data/html/adblock_big.png b/src/lib/adblock/data/adblock_big.png similarity index 100% rename from src/lib/data/html/adblock_big.png rename to src/lib/adblock/data/adblock_big.png diff --git a/src/lib/app/browserwindow.cpp b/src/lib/app/browserwindow.cpp index 05135c2c..e3916639 100644 --- a/src/lib/app/browserwindow.cpp +++ b/src/lib/app/browserwindow.cpp @@ -1,1622 +1,1619 @@ /* ============================================================ * 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 "browserwindow.h" #include "tabwidget.h" #include "tabbar.h" #include "webpage.h" #include "tabbedwebview.h" #include "lineedit.h" #include "history.h" #include "locationbar.h" #include "websearchbar.h" #include "pluginproxy.h" #include "sidebar.h" #include "downloadmanager.h" #include "cookiejar.h" #include "cookiemanager.h" #include "bookmarkstoolbar.h" #include "clearprivatedata.h" #include "autofill.h" #include "mainapplication.h" #include "checkboxdialog.h" #include "clickablelabel.h" #include "docktitlebarwidget.h" #include "iconprovider.h" #include "progressbar.h" -#include "adblockicon.h" #include "closedwindowsmanager.h" #include "statusbarmessage.h" #include "browsinglibrary.h" #include "navigationbar.h" #include "bookmarksimport/bookmarksimportdialog.h" #include "qztools.h" #include "reloadstopbutton.h" #include "enhancedmenu.h" #include "navigationcontainer.h" #include "settings.h" #include "qzsettings.h" #include "speeddial.h" #include "menubar.h" #include "bookmarkstools.h" #include "bookmarksmenu.h" #include "historymenu.h" #include "mainmenu.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef QZ_WS_X11 #include #include #include #endif static const int savedWindowVersion = 2; BrowserWindow::SavedWindow::SavedWindow() { } BrowserWindow::SavedWindow::SavedWindow(BrowserWindow *window) { windowState = window->isFullScreen() ? QByteArray() : window->saveState(); windowGeometry = window->saveGeometry(); windowUiState = window->saveUiState(); #ifdef QZ_WS_X11 virtualDesktop = window->getCurrentVirtualDesktop(); #endif const int tabsCount = window->tabCount(); tabs.reserve(tabsCount); for (int i = 0; i < tabsCount; ++i) { TabbedWebView *webView = window->weView(i); if (!webView) { continue; } WebTab* webTab = webView->webTab(); if (!webTab) { continue; } WebTab::SavedTab tab(webTab); if (!tab.isValid()) { continue; } if (webTab->isCurrentTab()) { currentTab = tabs.size(); } tabs.append(tab); } } bool BrowserWindow::SavedWindow::isValid() const { return currentTab > -1; } void BrowserWindow::SavedWindow::clear() { windowState.clear(); windowGeometry.clear(); virtualDesktop = -1; currentTab = -1; tabs.clear(); } QDataStream &operator<<(QDataStream &stream, const BrowserWindow::SavedWindow &window) { stream << savedWindowVersion; stream << window.windowState; stream << window.windowGeometry; stream << window.virtualDesktop; stream << window.currentTab; stream << window.tabs.count(); for (int i = 0; i < window.tabs.count(); ++i) { stream << window.tabs.at(i); } stream << window.windowUiState; return stream; } QDataStream &operator>>(QDataStream &stream, BrowserWindow::SavedWindow &window) { int version; stream >> version; if (version < 1) { return stream; } stream >> window.windowState; stream >> window.windowGeometry; stream >> window.virtualDesktop; stream >> window.currentTab; int tabsCount = -1; stream >> tabsCount; window.tabs.reserve(tabsCount); for (int i = 0; i < tabsCount; ++i) { WebTab::SavedTab tab; stream >> tab; window.tabs.append(tab); } if (version >= 2) { stream >> window.windowUiState; } return stream; } BrowserWindow::BrowserWindow(Qz::BrowserWindowType type, const QUrl &startUrl) : QMainWindow(0) , m_startUrl(startUrl) , m_windowType(type) , m_startTab(0) , m_startPage(0) , m_sideBarManager(new SideBarManager(this)) , m_statusBarMessage(new StatusBarMessage(this)) , m_isHtmlFullScreen(false) , m_hideNavigationTimer(0) { setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DontCreateNativeAncestors); setObjectName("mainwindow"); setWindowTitle(tr("Falkon")); setProperty("private", mApp->isPrivate()); setupUi(); setupMenu(); m_hideNavigationTimer = new QTimer(this); m_hideNavigationTimer->setInterval(1000); m_hideNavigationTimer->setSingleShot(true); connect(m_hideNavigationTimer, SIGNAL(timeout()), this, SLOT(hideNavigationSlot())); connect(mApp, SIGNAL(settingsReloaded()), this, SLOT(loadSettings())); QTimer::singleShot(0, this, SLOT(postLaunch())); if (mApp->isPrivate()) { QzTools::setWmClass("Falkon Browser (Private Window)", this); } else { QzTools::setWmClass("Falkon Browser", this); } } BrowserWindow::~BrowserWindow() { mApp->plugins()->emitMainWindowDeleted(this); foreach (const QPointer &pointer, m_deleteOnCloseWidgets) { if (pointer) { pointer->deleteLater(); } } } void BrowserWindow::setStartTab(WebTab* tab) { m_startTab = tab; } void BrowserWindow::setStartPage(WebPage *page) { m_startPage = page; } void BrowserWindow::postLaunch() { loadSettings(); bool addTab = true; QUrl startUrl; switch (mApp->afterLaunch()) { case MainApplication::OpenBlankPage: startUrl = QUrl(); break; case MainApplication::OpenSpeedDial: startUrl = QUrl("falkon:speeddial"); break; case MainApplication::OpenHomePage: case MainApplication::RestoreSession: case MainApplication::SelectSession: startUrl = m_homepage; break; default: break; } show(); switch (m_windowType) { case Qz::BW_FirstAppWindow: if (mApp->isStartingAfterCrash()) { addTab = false; startUrl.clear(); // qupzilla:restore needs JavaScript enabled // correct value is then restored in MainApplication::destroyRestoreManager mApp->webSettings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); m_tabWidget->addView(QUrl("falkon:restore"), Qz::NT_CleanSelectedTabAtTheEnd); } else if (mApp->afterLaunch() == MainApplication::SelectSession || mApp->afterLaunch() == MainApplication::RestoreSession) { addTab = m_tabWidget->count() <= 0; } break; case Qz::BW_NewWindow: case Qz::BW_MacFirstWindow: addTab = true; break; case Qz::BW_OtherRestoredWindow: addTab = false; break; } if (!m_startUrl.isEmpty()) { startUrl = m_startUrl; addTab = true; } if (m_startTab) { addTab = false; m_tabWidget->addView(m_startTab, Qz::NT_SelectedTab); } if (m_startPage) { addTab = false; m_tabWidget->addView(QUrl()); weView()->setPage(m_startPage); } if (addTab) { m_tabWidget->addView(startUrl, Qz::NT_CleanSelectedTabAtTheEnd); if (startUrl.isEmpty() || startUrl.toString() == QLatin1String("falkon:speeddial")) { locationBar()->setFocus(); } } // Something went really wrong .. add one tab if (m_tabWidget->count() <= 0) { m_tabWidget->addView(m_homepage, Qz::NT_SelectedTabAtTheEnd); } mApp->plugins()->emitMainWindowCreated(this); emit startingCompleted(); raise(); activateWindow(); updateStartupFocus(); } void BrowserWindow::setupUi() { Settings settings; settings.beginGroup("Browser-View-Settings"); const QByteArray windowGeometry = settings.value(QSL("WindowGeometry")).toByteArray(); const QStringList keys = { QSL("LocationBarWidth"), QSL("WebSearchBarWidth"), QSL("SideBarWidth"), QSL("WebViewWidth"), QSL("SideBar") }; QHash uiState; for (const QString &key : keys) { if (settings.contains(key)) { uiState[key] = settings.value(key); } } settings.endGroup(); QWidget* widget = new QWidget(this); widget->setCursor(Qt::ArrowCursor); setCentralWidget(widget); m_mainLayout = new QVBoxLayout(widget); m_mainLayout->setContentsMargins(0, 0, 0, 0); m_mainLayout->setSpacing(0); m_mainSplitter = new QSplitter(this); m_mainSplitter->setObjectName("sidebar-splitter"); m_tabWidget = new TabWidget(this); m_superMenu = new QMenu(this); m_navigationToolbar = new NavigationBar(this); m_bookmarksToolbar = new BookmarksToolbar(this); m_navigationContainer = new NavigationContainer(this); m_navigationContainer->addWidget(m_navigationToolbar); m_navigationContainer->addWidget(m_bookmarksToolbar); m_navigationContainer->setTabBar(m_tabWidget->tabBar()); m_mainSplitter->addWidget(m_tabWidget); m_mainSplitter->setCollapsible(0, false); m_mainLayout->addWidget(m_navigationContainer); m_mainLayout->addWidget(m_mainSplitter); statusBar()->setObjectName("mainwindow-statusbar"); statusBar()->setCursor(Qt::ArrowCursor); m_progressBar = new ProgressBar(statusBar()); m_ipLabel = new QLabel(this); m_ipLabel->setObjectName("statusbar-ip-label"); m_ipLabel->setToolTip(tr("IP Address of current page")); statusBar()->addPermanentWidget(m_progressBar); statusBar()->addPermanentWidget(m_ipLabel); - m_navigationToolbar->addToolButton(new AdBlockIcon(this)); - QDesktopWidget* desktop = mApp->desktop(); int windowWidth = desktop->availableGeometry().width() / 1.3; int windowHeight = desktop->availableGeometry().height() / 1.3; // Let the WM decides where to put new browser window if (m_windowType != Qz::BW_FirstAppWindow && m_windowType != Qz::BW_MacFirstWindow && mApp->getWindow()) { #ifdef Q_WS_WIN // Windows WM places every new window in the middle of screen .. for some reason QPoint p = mApp->getWindow()->geometry().topLeft(); p.setX(p.x() + 30); p.setY(p.y() + 30); if (!desktop->availableGeometry(mApp->getWindow()).contains(p)) { p.setX(desktop->availableGeometry(mApp->getWindow()).x() + 30); p.setY(desktop->availableGeometry(mApp->getWindow()).y() + 30); } setGeometry(QRect(p, mApp->getWindow()->size())); #else resize(mApp->getWindow()->size()); #endif } else if (!restoreGeometry(windowGeometry)) { #ifdef Q_WS_WIN setGeometry(QRect(desktop->availableGeometry(mApp->getWindow()).x() + 30, desktop->availableGeometry(mApp->getWindow()).y() + 30, windowWidth, windowHeight)); #else resize(windowWidth, windowHeight); #endif } // Workaround for Oxygen tooltips not having transparent background QPalette pal = QToolTip::palette(); QColor col = pal.window().color(); col.setAlpha(0); pal.setColor(QPalette::Window, col); QToolTip::setPalette(pal); restoreUiState(uiState); // Set some sane minimum width setMinimumWidth(300); } void BrowserWindow::setupMenu() { #ifdef Q_OS_MACOS static MainMenu* macMainMenu = 0; if (!macMainMenu) { macMainMenu = new MainMenu(this, 0); macMainMenu->initMenuBar(new QMenuBar(0)); connect(mApp, SIGNAL(activeWindowChanged(BrowserWindow*)), macMainMenu, SLOT(setWindow(BrowserWindow*))); } else { macMainMenu->setWindow(this); } m_mainMenu = macMainMenu; #else setMenuBar(new MenuBar(this)); m_mainMenu = new MainMenu(this, this); m_mainMenu->initMenuBar(menuBar()); #endif m_mainMenu->initSuperMenu(m_superMenu); // Setup other shortcuts QShortcut* reloadBypassCacheAction = new QShortcut(QKeySequence(QSL("Ctrl+F5")), this); QShortcut* reloadBypassCacheAction2 = new QShortcut(QKeySequence(QSL("Ctrl+Shift+R")), this); connect(reloadBypassCacheAction, SIGNAL(activated()), this, SLOT(reloadBypassCache())); connect(reloadBypassCacheAction2, SIGNAL(activated()), this, SLOT(reloadBypassCache())); QShortcut* closeTabAction = new QShortcut(QKeySequence(QSL("Ctrl+W")), this); QShortcut* closeTabAction2 = new QShortcut(QKeySequence(QSL("Ctrl+F4")), this); connect(closeTabAction, SIGNAL(activated()), this, SLOT(closeTab())); connect(closeTabAction2, SIGNAL(activated()), this, SLOT(closeTab())); QShortcut* reloadAction = new QShortcut(QKeySequence("Ctrl+R"), this); connect(reloadAction, SIGNAL(activated()), this, SLOT(reload())); QShortcut* openLocationAction = new QShortcut(QKeySequence("Alt+D"), this); connect(openLocationAction, SIGNAL(activated()), this, SLOT(openLocation())); QShortcut* inspectorAction = new QShortcut(QKeySequence(QSL("F12")), this); connect(inspectorAction, SIGNAL(activated()), this, SLOT(toggleWebInspector())); QShortcut* restoreClosedWindow = new QShortcut(QKeySequence(QSL("Ctrl+Shift+N")), this); connect(restoreClosedWindow, &QShortcut::activated, mApp->closedWindowsManager(), &ClosedWindowsManager::restoreClosedWindow); } void BrowserWindow::updateStartupFocus() { QTimer::singleShot(500, this, [this]() { // Scroll to current tab tabWidget()->tabBar()->ensureVisible(); // Update focus if (!m_startPage && LocationBar::convertUrlToText(weView()->page()->requestedUrl()).isEmpty()) locationBar()->setFocus(); else weView()->setFocus(); }); } QAction* BrowserWindow::createEncodingAction(const QString &codecName, const QString &activeCodecName, QMenu* menu) { QAction* action = new QAction(codecName, menu); action->setData(codecName); action->setCheckable(true); connect(action, SIGNAL(triggered()), this, SLOT(changeEncoding())); if (activeCodecName.compare(codecName, Qt::CaseInsensitive) == 0) { action->setChecked(true); } return action; } void BrowserWindow::createEncodingSubMenu(const QString &name, QStringList &codecNames, QMenu* menu) { if (codecNames.isEmpty()) { return; } QCollator collator; collator.setNumericMode(true); std::sort(codecNames.begin(), codecNames.end(), [collator](const QString &a, const QString &b) { return collator.compare(a, b) < 0; }); QMenu* subMenu = new QMenu(name, menu); const QString activeCodecName = mApp->webSettings()->defaultTextEncoding(); QActionGroup *group = new QActionGroup(subMenu); foreach (const QString &codecName, codecNames) { QAction *act = createEncodingAction(codecName, activeCodecName, subMenu); group->addAction(act); subMenu->addAction(act); } menu->addMenu(subMenu); } QHash BrowserWindow::saveUiState() { saveSideBarSettings(); QHash state; state[QSL("LocationBarWidth")] = m_navigationToolbar->splitter()->sizes().at(0); state[QSL("WebSearchBarWidth")] = m_navigationToolbar->splitter()->sizes().at(1); state[QSL("SideBarWidth")] = m_sideBarWidth; state[QSL("WebViewWidth")] = m_webViewWidth; state[QSL("SideBar")] = m_sideBarManager->activeSideBar(); return state; } void BrowserWindow::restoreUiState(const QHash &state) { const int locationBarWidth = state.value(QSL("LocationBarWidth"), 480).toInt(); const int websearchBarWidth = state.value(QSL("WebSearchBarWidth"), 140).toInt(); m_navigationToolbar->setSplitterSizes(locationBarWidth, websearchBarWidth); m_sideBarWidth = state.value(QSL("SideBarWidth"), 250).toInt(); m_webViewWidth = state.value(QSL("WebViewWidth"), 2000).toInt(); if (m_sideBar) { m_mainSplitter->setSizes({m_sideBarWidth, m_webViewWidth}); } const QString activeSideBar = state.value(QSL("SideBar")).toString(); if (activeSideBar.isEmpty() && m_sideBar) { m_sideBar->close(); } else { m_sideBarManager->showSideBar(activeSideBar, false); } } void BrowserWindow::loadSettings() { Settings settings; //Url settings settings.beginGroup("Web-URL-Settings"); m_homepage = settings.value("homepage", "falkon:start").toUrl(); settings.endGroup(); //Browser Window settings settings.beginGroup("Browser-View-Settings"); bool showStatusBar = settings.value("showStatusBar", false).toBool(); bool showBookmarksToolbar = settings.value("showBookmarksToolbar", true).toBool(); bool showNavigationToolbar = settings.value("showNavigationToolbar", true).toBool(); bool showMenuBar = settings.value("showMenubar", false).toBool(); // Make sure both menubar and navigationbar are not hidden // Fixes #781 if (!showNavigationToolbar) { showMenuBar = true; settings.setValue("showMenubar", true); } settings.endGroup(); settings.beginGroup("Shortcuts"); m_useTabNumberShortcuts = settings.value("useTabNumberShortcuts", true).toBool(); m_useSpeedDialNumberShortcuts = settings.value("useSpeedDialNumberShortcuts", true).toBool(); m_useSingleKeyShortcuts = settings.value("useSingleKeyShortcuts", false).toBool(); settings.endGroup(); settings.beginGroup("Web-Browser-Settings"); QAction *quitAction = m_mainMenu->action(QSL("Standard/Quit")); if (settings.value("closeAppWithCtrlQ", true).toBool()) { quitAction->setShortcut(QzTools::actionShortcut(QKeySequence::Quit, QKeySequence(QSL("Ctrl+Q")))); } else { quitAction->setShortcut(QKeySequence()); } settings.endGroup(); statusBar()->setVisible(!isFullScreen() && showStatusBar); m_bookmarksToolbar->setVisible(showBookmarksToolbar); m_navigationToolbar->setVisible(showNavigationToolbar); #ifndef Q_OS_MACOS menuBar()->setVisible(!isFullScreen() && showMenuBar); #endif m_navigationToolbar->setSuperMenuVisible(!showMenuBar); } void BrowserWindow::goForward() { weView()->forward(); } void BrowserWindow::reload() { weView()->reload(); } void BrowserWindow::reloadBypassCache() { weView()->reloadBypassCache(); } void BrowserWindow::goBack() { weView()->back(); } int BrowserWindow::tabCount() const { return m_tabWidget->count(); } TabbedWebView* BrowserWindow::weView() const { return weView(m_tabWidget->currentIndex()); } TabbedWebView* BrowserWindow::weView(int index) const { WebTab* webTab = qobject_cast(m_tabWidget->widget(index)); if (!webTab) { return 0; } return webTab->webView(); } LocationBar* BrowserWindow::locationBar() const { return qobject_cast(m_tabWidget->locationBars()->currentWidget()); } TabWidget* BrowserWindow::tabWidget() const { return m_tabWidget; } BookmarksToolbar* BrowserWindow::bookmarksToolbar() const { return m_bookmarksToolbar; } StatusBarMessage* BrowserWindow::statusBarMessage() const { return m_statusBarMessage; } NavigationBar* BrowserWindow::navigationBar() const { return m_navigationToolbar; } SideBarManager* BrowserWindow::sideBarManager() const { return m_sideBarManager; } QLabel* BrowserWindow::ipLabel() const { return m_ipLabel; } QMenu* BrowserWindow::superMenu() const { return m_superMenu; } QUrl BrowserWindow::homepageUrl() const { return m_homepage; } Qz::BrowserWindowType BrowserWindow::windowType() const { return m_windowType; } QAction* BrowserWindow::action(const QString &name) const { return m_mainMenu->action(name); } void BrowserWindow::setWindowTitle(const QString &t) { QString title = t; if (mApp->isPrivate()) { title.append(tr(" (Private Browsing)")); } QMainWindow::setWindowTitle(title); } void BrowserWindow::changeEncoding() { if (QAction* action = qobject_cast(sender())) { const QString encoding = action->data().toString(); mApp->webSettings()->setDefaultTextEncoding(encoding); Settings settings; settings.setValue("Web-Browser-Settings/DefaultEncoding", encoding); weView()->reload(); } } void BrowserWindow::printPage() { weView()->printPage(); } void BrowserWindow::bookmarkPage() { TabbedWebView* view = weView(); BookmarksTools::addBookmarkDialog(this, view->url(), view->title()); } void BrowserWindow::bookmarkAllTabs() { BookmarksTools::bookmarkAllTabsDialog(this, m_tabWidget); } void BrowserWindow::addBookmark(const QUrl &url, const QString &title) { BookmarksTools::addBookmarkDialog(this, url, title); } void BrowserWindow::goHome() { loadAddress(m_homepage); } void BrowserWindow::goHomeInNewTab() { m_tabWidget->addView(m_homepage, Qz::NT_SelectedTab); } void BrowserWindow::loadActionUrl(QObject* obj) { if (!obj) { obj = sender(); } if (QAction* action = qobject_cast(obj)) { loadAddress(action->data().toUrl()); } } void BrowserWindow::loadActionUrlInNewTab(QObject* obj) { if (!obj) { obj = sender(); } if (QAction* action = qobject_cast(obj)) { m_tabWidget->addView(action->data().toUrl(), Qz::NT_SelectedTabAtTheEnd); } } void BrowserWindow::loadAddress(const QUrl &url) { if (weView()->webTab()->isPinned()) { int index = m_tabWidget->addView(url, qzSettings->newTabPosition); weView(index)->setFocus(); } else { weView()->load(url); weView()->setFocus(); } } void BrowserWindow::showHistoryManager() { mApp->browsingLibrary()->showHistory(this); } void BrowserWindow::showSource(WebView *view) { if (!view) view = weView(); view->showSource(); } void BrowserWindow::showNormal() { if (m_normalWindowState & Qt::WindowMaximized) { QMainWindow::showMaximized(); } else { QMainWindow::showNormal(); } } SideBar* BrowserWindow::addSideBar() { if (m_sideBar) { return m_sideBar.data(); } m_sideBar = new SideBar(m_sideBarManager, this); m_mainSplitter->insertWidget(0, m_sideBar.data()); m_mainSplitter->setCollapsible(0, false); m_mainSplitter->setSizes({m_sideBarWidth, m_webViewWidth}); return m_sideBar.data(); } void BrowserWindow::saveSideBarSettings() { if (m_sideBar) { // That +1 is important here, without it, the sidebar width would // decrease by 1 pixel every close m_sideBarWidth = m_mainSplitter->sizes().at(0) + 1; m_webViewWidth = width() - m_sideBarWidth; } Settings().setValue(QSL("Browser-View-Settings/SideBar"), m_sideBarManager->activeSideBar()); } void BrowserWindow::toggleShowMenubar() { #ifdef Q_OS_MACOS // We use one shared global menubar on Mac that can't be hidden return; #endif setUpdatesEnabled(false); menuBar()->setVisible(!menuBar()->isVisible()); m_navigationToolbar->setSuperMenuVisible(!menuBar()->isVisible()); setUpdatesEnabled(true); Settings().setValue("Browser-View-Settings/showMenubar", menuBar()->isVisible()); // Make sure we show Navigation Toolbar when Menu Bar is hidden if (!m_navigationToolbar->isVisible() && !menuBar()->isVisible()) { toggleShowNavigationToolbar(); } } void BrowserWindow::toggleShowStatusBar() { setUpdatesEnabled(false); statusBar()->setVisible(!statusBar()->isVisible()); setUpdatesEnabled(true); Settings().setValue("Browser-View-Settings/showStatusBar", statusBar()->isVisible()); } void BrowserWindow::toggleShowBookmarksToolbar() { setUpdatesEnabled(false); m_bookmarksToolbar->setVisible(!m_bookmarksToolbar->isVisible()); setUpdatesEnabled(true); Settings().setValue("Browser-View-Settings/showBookmarksToolbar", m_bookmarksToolbar->isVisible()); Settings().setValue("Browser-View-Settings/instantBookmarksToolbar", false); } void BrowserWindow::toggleShowNavigationToolbar() { setUpdatesEnabled(false); m_navigationToolbar->setVisible(!m_navigationToolbar->isVisible()); setUpdatesEnabled(true); Settings().setValue("Browser-View-Settings/showNavigationToolbar", m_navigationToolbar->isVisible()); #ifndef Q_OS_MACOS // Make sure we show Menu Bar when Navigation Toolbar is hidden if (!m_navigationToolbar->isVisible() && !menuBar()->isVisible()) { toggleShowMenubar(); } #endif } void BrowserWindow::toggleTabsOnTop(bool enable) { qzSettings->tabsOnTop = enable; m_navigationContainer->toggleTabsOnTop(enable); } void BrowserWindow::toggleFullScreen() { if (m_isHtmlFullScreen) { weView()->triggerPageAction(QWebEnginePage::ExitFullScreen); return; } if (isFullScreen()) showNormal(); else showFullScreen(); } void BrowserWindow::toggleHtmlFullScreen(bool enable) { if (enable) showFullScreen(); else showNormal(); if (m_sideBar) m_sideBar.data()->setHidden(enable); m_isHtmlFullScreen = enable; } void BrowserWindow::showWebInspector() { if (weView() && weView()->webTab()) { weView()->webTab()->showWebInspector(); } } void BrowserWindow::toggleWebInspector() { if (weView() && weView()->webTab()) { weView()->webTab()->toggleWebInspector(); } } void BrowserWindow::refreshHistory() { m_navigationToolbar->refreshHistory(); } void BrowserWindow::currentTabChanged() { TabbedWebView* view = weView(); if (!view) { return; } setWindowTitle(tr("%1 - Falkon").arg(view->webTab()->title())); m_ipLabel->setText(view->getIp()); view->setFocus(); m_navigationToolbar->setCurrentView(view); updateLoadingActions(); // Setting correct tab order (LocationBar -> WebSearchBar -> WebView) setTabOrder(locationBar(), m_navigationToolbar->webSearchBar()); setTabOrder(m_navigationToolbar->webSearchBar(), view); } void BrowserWindow::updateLoadingActions() { TabbedWebView* view = weView(); if (!view) { return; } bool isLoading = view->isLoading(); m_ipLabel->setVisible(!isLoading); m_progressBar->setVisible(isLoading); action(QSL("View/Stop"))->setEnabled(isLoading); action(QSL("View/Reload"))->setEnabled(!isLoading); if (isLoading) { m_progressBar->setValue(view->loadingProgress()); m_navigationToolbar->showStopButton(); } else { m_navigationToolbar->showReloadButton(); } } void BrowserWindow::addDeleteOnCloseWidget(QWidget* widget) { if (!m_deleteOnCloseWidgets.contains(widget)) { m_deleteOnCloseWidgets.append(widget); } } void BrowserWindow::restoreWindow(const SavedWindow &window) { restoreState(window.windowState); restoreGeometry(window.windowGeometry); restoreUiState(window.windowUiState); #ifdef QZ_WS_X11 moveToVirtualDesktop(window.virtualDesktop); #endif show(); // Window has to be visible before adding QWebEngineView's m_tabWidget->restoreState(window.tabs, window.currentTab); updateStartupFocus(); } void BrowserWindow::createToolbarsMenu(QMenu* menu) { removeActions(menu->actions()); menu->clear(); QAction* action; #ifndef Q_OS_MACOS action = menu->addAction(tr("&Menu Bar"), this, SLOT(toggleShowMenubar())); action->setCheckable(true); action->setChecked(menuBar()->isVisible()); #endif action = menu->addAction(tr("&Navigation Toolbar"), this, SLOT(toggleShowNavigationToolbar())); action->setCheckable(true); action->setChecked(m_navigationToolbar->isVisible()); action = menu->addAction(tr("&Bookmarks Toolbar"), this, SLOT(toggleShowBookmarksToolbar())); action->setCheckable(true); action->setChecked(Settings().value("Browser-View-Settings/showBookmarksToolbar").toBool()); menu->addSeparator(); action = menu->addAction(tr("&Tabs on Top"), this, SLOT(toggleTabsOnTop(bool))); action->setCheckable(true); action->setChecked(qzSettings->tabsOnTop); addActions(menu->actions()); } void BrowserWindow::createSidebarsMenu(QMenu* menu) { m_sideBarManager->createMenu(menu); } void BrowserWindow::createEncodingMenu(QMenu* menu) { const QString activeCodecName = mApp->webSettings()->defaultTextEncoding(); QStringList isoCodecs; QStringList utfCodecs; QStringList windowsCodecs; QStringList isciiCodecs; QStringList ibmCodecs; QStringList otherCodecs; QStringList allCodecs; foreach (const int mib, QTextCodec::availableMibs()) { const QString codecName = QString::fromUtf8(QTextCodec::codecForMib(mib)->name()); if (!allCodecs.contains(codecName)) allCodecs.append(codecName); else continue; if (codecName.startsWith(QLatin1String("ISO"))) isoCodecs.append(codecName); else if (codecName.startsWith(QLatin1String("UTF"))) utfCodecs.append(codecName); else if (codecName.startsWith(QLatin1String("windows"))) windowsCodecs.append(codecName); else if (codecName.startsWith(QLatin1String("Iscii"))) isciiCodecs.append(codecName); else if (codecName.startsWith(QLatin1String("IBM"))) ibmCodecs.append(codecName); else otherCodecs.append(codecName); } if (!menu->isEmpty()) menu->addSeparator(); createEncodingSubMenu("ISO", isoCodecs, menu); createEncodingSubMenu("UTF", utfCodecs, menu); createEncodingSubMenu("Windows", windowsCodecs, menu); createEncodingSubMenu("Iscii", isciiCodecs, menu); createEncodingSubMenu("IBM", ibmCodecs, menu); createEncodingSubMenu(tr("Other"), otherCodecs, menu); } void BrowserWindow::removeActions(const QList &actions) { foreach (QAction *action, actions) { removeAction(action); } } void BrowserWindow::addTab() { m_tabWidget->addView(QUrl(), Qz::NT_SelectedNewEmptyTab, true); m_tabWidget->setCurrentTabFresh(true); if (isFullScreen()) showNavigationWithFullScreen(); } void BrowserWindow::webSearch() { m_navigationToolbar->webSearchBar()->setFocus(); m_navigationToolbar->webSearchBar()->selectAll(); } void BrowserWindow::searchOnPage() { if (weView() && weView()->webTab()) { weView()->webTab()->showSearchToolBar(); } } void BrowserWindow::openFile() { const QString fileTypes = QString("%1(*.html *.htm *.shtml *.shtm *.xhtml);;" "%2(*.png *.jpg *.jpeg *.bmp *.gif *.svg *.tiff);;" "%3(*.txt);;" "%4(*.*)").arg(tr("HTML files"), tr("Image files"), tr("Text files"), tr("All files")); const QString filePath = QzTools::getOpenFileName("MainWindow-openFile", this, tr("Open file..."), QDir::homePath(), fileTypes); if (!filePath.isEmpty()) { loadAddress(QUrl::fromLocalFile(filePath)); } } void BrowserWindow::openLocation() { if (isFullScreen()) { showNavigationWithFullScreen(); } locationBar()->setFocus(); locationBar()->selectAll(); } bool BrowserWindow::fullScreenNavigationVisible() const { return m_navigationContainer->isVisible(); } void BrowserWindow::showNavigationWithFullScreen() { if (m_isHtmlFullScreen) return; if (m_hideNavigationTimer->isActive()) { m_hideNavigationTimer->stop(); } m_navigationContainer->show(); } void BrowserWindow::hideNavigationWithFullScreen() { if (m_tabWidget->isCurrentTabFresh()) return; if (!m_hideNavigationTimer->isActive()) { m_hideNavigationTimer->start(); } } void BrowserWindow::hideNavigationSlot() { TabbedWebView* view = weView(); bool mouseInView = view && view->underMouse(); if (isFullScreen() && mouseInView) { m_navigationContainer->hide(); } } bool BrowserWindow::event(QEvent* event) { switch (event->type()) { case QEvent::WindowStateChange: if (!(m_oldWindowState & Qt::WindowFullScreen) && windowState() & Qt::WindowFullScreen) { // Enter fullscreen m_normalWindowState = m_oldWindowState; m_statusBarVisible = statusBar()->isVisible(); #ifndef Q_OS_MACOS m_menuBarVisible = menuBar()->isVisible(); menuBar()->hide(); #endif statusBar()->hide(); m_navigationContainer->hide(); } else if (m_oldWindowState & Qt::WindowFullScreen && !(windowState() & Qt::WindowFullScreen)) { // Leave fullscreen statusBar()->setVisible(m_statusBarVisible); #ifndef Q_OS_MACOS menuBar()->setVisible(m_menuBarVisible); #endif m_navigationContainer->show(); m_navigationToolbar->setSuperMenuVisible(!m_menuBarVisible); m_isHtmlFullScreen = false; } if (m_hideNavigationTimer) { m_hideNavigationTimer->stop(); } m_oldWindowState = windowState(); break; default: break; } return QMainWindow::event(event); } void BrowserWindow::resizeEvent(QResizeEvent* event) { m_bookmarksToolbar->setMaximumWidth(width()); QMainWindow::resizeEvent(event); } void BrowserWindow::keyPressEvent(QKeyEvent* event) { if (mApp->plugins()->processKeyPress(Qz::ON_BrowserWindow, this, event)) { return; } int number = -1; TabbedWebView* view = weView(); switch (event->key()) { case Qt::Key_Back: if (view) { view->back(); event->accept(); } break; case Qt::Key_Forward: if (view) { view->forward(); event->accept(); } break; case Qt::Key_Stop: if (view) { view->stop(); event->accept(); } break; case Qt::Key_Reload: case Qt::Key_Refresh: if (view) { view->reload(); event->accept(); } break; case Qt::Key_HomePage: goHome(); event->accept(); break; case Qt::Key_Favorites: mApp->browsingLibrary()->showBookmarks(this); event->accept(); break; case Qt::Key_Search: searchOnPage(); event->accept(); break; case Qt::Key_F6: case Qt::Key_OpenUrl: openLocation(); event->accept(); break; case Qt::Key_History: showHistoryManager(); event->accept(); break; case Qt::Key_AddFavorite: bookmarkPage(); event->accept(); break; case Qt::Key_News: action(QSL("Tools/RssReader"))->trigger(); event->accept(); break; case Qt::Key_Tools: action(QSL("Standard/Preferences"))->trigger(); event->accept(); break; case Qt::Key_Tab: if (event->modifiers() == Qt::ControlModifier) { m_tabWidget->nextTab(); event->accept(); } break; case Qt::Key_Backtab: if (event->modifiers() == (Qt::ControlModifier + Qt::ShiftModifier)) { m_tabWidget->previousTab(); event->accept(); } break; case Qt::Key_PageDown: if (event->modifiers() == Qt::ControlModifier) { m_tabWidget->nextTab(); event->accept(); } break; case Qt::Key_PageUp: if (event->modifiers() == Qt::ControlModifier) { m_tabWidget->previousTab(); event->accept(); } break; case Qt::Key_Equal: if (view && event->modifiers() == Qt::ControlModifier) { view->zoomIn(); event->accept(); } break; case Qt::Key_I: if (event->modifiers() == Qt::ControlModifier) { action(QSL("Tools/SiteInfo"))->trigger(); event->accept(); } break; case Qt::Key_U: if (event->modifiers() == Qt::ControlModifier) { action(QSL("View/PageSource"))->trigger(); event->accept(); } break; case Qt::Key_F: if (event->modifiers() == Qt::ControlModifier) { action(QSL("Edit/Find"))->trigger(); event->accept(); } break; case Qt::Key_Slash: if (m_useSingleKeyShortcuts) { action(QSL("Edit/Find"))->trigger(); event->accept(); } break; case Qt::Key_1: number = 1; break; case Qt::Key_2: number = 2; break; case Qt::Key_3: number = 3; break; case Qt::Key_4: number = 4; break; case Qt::Key_5: number = 5; break; case Qt::Key_6: number = 6; break; case Qt::Key_7: number = 7; break; case Qt::Key_8: number = 8; break; case Qt::Key_9: number = 9; break; default: break; } if (number != -1) { if (event->modifiers() & Qt::AltModifier && m_useTabNumberShortcuts) { if (number == 9) { number = m_tabWidget->count(); } m_tabWidget->setCurrentIndex(number - 1); event->accept(); return; } if (event->modifiers() & Qt::ControlModifier && m_useSpeedDialNumberShortcuts) { const QUrl url = mApp->plugins()->speedDial()->urlForShortcut(number - 1); if (url.isValid()) { loadAddress(url); event->accept(); return; } } if (event->modifiers() == Qt::NoModifier && m_useSingleKeyShortcuts) { if (number == 1) m_tabWidget->previousTab(); if (number == 2) m_tabWidget->nextTab(); } } QMainWindow::keyPressEvent(event); } void BrowserWindow::keyReleaseEvent(QKeyEvent* event) { if (mApp->plugins()->processKeyRelease(Qz::ON_BrowserWindow, this, event)) { return; } switch (event->key()) { case Qt::Key_F: if (event->modifiers() == Qt::ControlModifier) { action(QSL("Edit/Find"))->trigger(); event->accept(); } break; default: break; } QMainWindow::keyReleaseEvent(event); } void BrowserWindow::closeEvent(QCloseEvent* event) { if (mApp->isClosing()) { saveSettings(); return; } Settings settings; bool askOnClose = settings.value("Browser-Tabs-Settings/AskOnClosing", true).toBool(); if ((mApp->afterLaunch() == MainApplication::SelectSession || mApp->afterLaunch() == MainApplication::RestoreSession) && mApp->windowCount() == 1) { askOnClose = false; } if (askOnClose && m_tabWidget->normalTabsCount() > 1) { CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, this); dialog.setDefaultButton(QMessageBox::No); //~ singular There is still %n open tab and your session won't be stored.\nAre you sure you want to close this window? //~ plural There are still %n open tabs and your session won't be stored.\nAre you sure you want to close this window? dialog.setText(tr("There are still %n open tabs and your session won't be stored.\nAre you sure you want to close this window?", "", m_tabWidget->count())); dialog.setCheckBoxText(tr("Don't ask again")); dialog.setWindowTitle(tr("There are still open tabs")); dialog.setIcon(QMessageBox::Warning); if (dialog.exec() != QMessageBox::Yes) { event->ignore(); return; } if (dialog.isChecked()) { settings.setValue("Browser-Tabs-Settings/AskOnClosing", false); } } saveSettings(); mApp->closedWindowsManager()->saveWindow(this); #ifndef Q_OS_MACOS if (mApp->windowCount() == 1) mApp->quitApplication(); #endif event->accept(); } void BrowserWindow::closeWindow() { #ifdef Q_OS_MACOS close(); return; #endif if (mApp->windowCount() > 1) { close(); } } void BrowserWindow::saveSettings() { if (mApp->isPrivate()) { return; } Settings settings; settings.beginGroup("Browser-View-Settings"); settings.setValue("WindowGeometry", saveGeometry()); const auto state = saveUiState(); for (auto it = state.constBegin(); it != state.constEnd(); ++it) { settings.setValue(it.key(), it.value()); } settings.endGroup(); } void BrowserWindow::closeTab() { // Don't close pinned tabs with keyboard shortcuts (Ctrl+W, Ctrl+F4) if (weView() && !weView()->webTab()->isPinned()) { m_tabWidget->requestCloseTab(); } } #ifdef QZ_WS_X11 int BrowserWindow::getCurrentVirtualDesktop() const { if (QGuiApplication::platformName() != QL1S("xcb")) return 0; xcb_intern_atom_cookie_t intern_atom; xcb_intern_atom_reply_t *atom_reply = 0; xcb_atom_t atom; xcb_get_property_cookie_t cookie; xcb_get_property_reply_t *reply = 0; uint32_t value; intern_atom = xcb_intern_atom(QX11Info::connection(), false, qstrlen("_NET_WM_DESKTOP"), "_NET_WM_DESKTOP"); atom_reply = xcb_intern_atom_reply(QX11Info::connection(), intern_atom, 0); if (!atom_reply) goto error; atom = atom_reply->atom; cookie = xcb_get_property(QX11Info::connection(), false, winId(), atom, XCB_ATOM_CARDINAL, 0, 1); reply = xcb_get_property_reply(QX11Info::connection(), cookie, 0); if (!reply || reply->type != XCB_ATOM_CARDINAL || reply->value_len != 1 || reply->format != sizeof(uint32_t) * 8) goto error; value = *reinterpret_cast(xcb_get_property_value(reply)); free(reply); free(atom_reply); return value; error: free(reply); free(atom_reply); return 0; } void BrowserWindow::moveToVirtualDesktop(int desktopId) { if (QGuiApplication::platformName() != QL1S("xcb")) return; // Don't move when window is already visible or it is first app window if (desktopId < 0 || isVisible() || m_windowType == Qz::BW_FirstAppWindow) return; xcb_intern_atom_cookie_t intern_atom; xcb_intern_atom_reply_t *atom_reply = 0; xcb_atom_t atom; intern_atom = xcb_intern_atom(QX11Info::connection(), false, qstrlen("_NET_WM_DESKTOP"), "_NET_WM_DESKTOP"); atom_reply = xcb_intern_atom_reply(QX11Info::connection(), intern_atom, 0); if (!atom_reply) goto error; atom = atom_reply->atom; xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, winId(), atom, XCB_ATOM_CARDINAL, 32, 1, (const void*) &desktopId); error: free(atom_reply); } #endif diff --git a/src/lib/app/browserwindow.h b/src/lib/app/browserwindow.h index 15b6df96..f30c99cd 100644 --- a/src/lib/app/browserwindow.h +++ b/src/lib/app/browserwindow.h @@ -1,245 +1,244 @@ /* ============================================================ * 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 BROWSERWINDOW_H #define BROWSERWINDOW_H #include #include #include #include "webtab.h" #include "qzcommon.h" class QLabel; class QVBoxLayout; class QSplitter; class QWebEngineFrame; class QTimer; class Menu; class MainMenu; class TabWidget; class TabbedWebView; class LineEdit; class HistoryMenu; class BookmarksMenu; class BookmarksToolbar; class AutoFill; class MainApplication; class WebView; class WebPage; -class AdBlockIcon; class SideBar; class SideBarManager; class ProgressBar; class StatusBarMessage; class NavigationBar; class NavigationContainer; class ClickableLabel; class LocationBar; class FALKON_EXPORT BrowserWindow : public QMainWindow { Q_OBJECT public: struct SavedWindow { QByteArray windowState; QByteArray windowGeometry; QHash windowUiState; int virtualDesktop = -1; int currentTab = -1; QVector tabs; SavedWindow(); SavedWindow(BrowserWindow *window); bool isValid() const; void clear(); friend FALKON_EXPORT QDataStream &operator<<(QDataStream &stream, const SavedWindow &window); friend FALKON_EXPORT QDataStream &operator>>(QDataStream &stream, SavedWindow &window); }; explicit BrowserWindow(Qz::BrowserWindowType type, const QUrl &url = QUrl()); ~BrowserWindow(); void setStartTab(WebTab* tab); void setStartPage(WebPage* page); void restoreWindow(const SavedWindow &window); bool fullScreenNavigationVisible() const; void showNavigationWithFullScreen(); void hideNavigationWithFullScreen(); void currentTabChanged(); void updateLoadingActions(); void addBookmark(const QUrl &url, const QString &title); void addDeleteOnCloseWidget(QWidget* widget); void createToolbarsMenu(QMenu* menu); void createSidebarsMenu(QMenu* menu); void createEncodingMenu(QMenu* menu); void removeActions(const QList &actions); SideBar* addSideBar(); void saveSideBarSettings(); int tabCount() const; TabbedWebView* weView() const; TabbedWebView* weView(int index) const; Qz::BrowserWindowType windowType() const; LocationBar* locationBar() const; TabWidget* tabWidget() const; BookmarksToolbar* bookmarksToolbar() const; StatusBarMessage* statusBarMessage() const; NavigationBar* navigationBar() const; SideBarManager* sideBarManager() const; QLabel* ipLabel() const; QMenu* superMenu() const; QUrl homepageUrl() const; QAction* action(const QString &name) const; signals: void startingCompleted(); public slots: void goHome(); void goHomeInNewTab(); void goBack(); void goForward(); void reload(); void reloadBypassCache(); void setWindowTitle(const QString &t); void showWebInspector(); void toggleWebInspector(); void showHistoryManager(); void toggleShowMenubar(); void toggleShowStatusBar(); void toggleShowBookmarksToolbar(); void toggleShowNavigationToolbar(); void toggleTabsOnTop(bool enable); void toggleFullScreen(); void toggleHtmlFullScreen(bool enable); void loadActionUrl(QObject* obj = 0); void loadActionUrlInNewTab(QObject* obj = 0); void bookmarkPage(); void bookmarkAllTabs(); void loadAddress(const QUrl &url); void showSource(WebView *view = Q_NULLPTR); void showNormal(); private slots: void addTab(); void openLocation(); void openFile(); void closeWindow(); void closeTab(); void loadSettings(); void postLaunch(); void refreshHistory(); void webSearch(); void searchOnPage(); void changeEncoding(); void printPage(); void saveSettings(); void hideNavigationSlot(); private: bool event(QEvent* event); void resizeEvent(QResizeEvent* event); void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); void closeEvent(QCloseEvent* event); void setupUi(); void setupMenu(); void updateStartupFocus(); QAction *createEncodingAction(const QString &codecName, const QString &activeCodecName, QMenu *menu); void createEncodingSubMenu(const QString &name, QStringList &codecNames, QMenu *menu); QHash saveUiState(); void restoreUiState(const QHash &state); QUrl m_startUrl; QUrl m_homepage; Qz::BrowserWindowType m_windowType; WebTab* m_startTab; WebPage* m_startPage; QVBoxLayout* m_mainLayout; QSplitter* m_mainSplitter; TabWidget* m_tabWidget; QPointer m_sideBar; SideBarManager* m_sideBarManager; StatusBarMessage* m_statusBarMessage; NavigationContainer* m_navigationContainer; NavigationBar* m_navigationToolbar; BookmarksToolbar* m_bookmarksToolbar; ProgressBar* m_progressBar; QLabel* m_ipLabel; QMenu* m_superMenu; MainMenu* m_mainMenu; int m_sideBarWidth; int m_webViewWidth; // Shortcuts bool m_useTabNumberShortcuts; bool m_useSpeedDialNumberShortcuts; bool m_useSingleKeyShortcuts; // Remember visibility of menubar and statusbar after entering Fullscreen bool m_menuBarVisible; bool m_statusBarVisible; bool m_isHtmlFullScreen; Qt::WindowStates m_oldWindowState = Qt::WindowNoState; Qt::WindowStates m_normalWindowState = Qt::WindowNoState; QTimer* m_hideNavigationTimer; QList > m_deleteOnCloseWidgets; #ifdef QZ_WS_X11 private: int getCurrentVirtualDesktop() const; void moveToVirtualDesktop(int desktopId); #endif }; #endif // BROWSERWINDOW_H diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index a02614d6..fd4c65f2 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -1,1245 +1,1245 @@ /* ============================================================ * 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 "qzregexp.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 "adblockmanager.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 "adblock/adblockplugin.h" #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 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("qupzilla"), QIcon(QSL(":icons/exeicons/qupzilla-window.png")))); 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::setThemeSearchPaths(QStringList() << QL1S(":/breeze-fallback")); 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()) { 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 (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); // Setup QWebChannel userscript QWebEngineScript script; script.setName(QSL("_falkon_webchannel")); script.setInjectionPoint(QWebEngineScript::DocumentCreation); script.setWorldId(QWebEngineScript::MainWorld); script.setRunsOnSubFrames(true); script.setSourceCode(Scripts::setupWebChannel()); m_webProfile->scripts()->insert(script); if (!isPrivate()) { 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(); 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()); } translateApp(); loadSettings(); m_plugins = new PluginProxy; m_autoFill = new AutoFill(this); + new AdBlockPlugin(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()) { #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()); } } QTimer::singleShot(0, this, SLOT(postLaunch())); } MainApplication::~MainApplication() { 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; delete m_cookieJar; delete m_plugins; 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; } // Restore JavaScript settings const bool jsEnabled = Settings().value(QSL("Web-Browser-Settings/allowJavaScript"), true).toBool(); m_webProfile->settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, jsEnabled); 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); } QString MainApplication::currentLanguageFile() const { return m_languageFile; } QString MainApplication::currentLanguage() const { QString lang = m_languageFile; if (lang.isEmpty()) { return "en_US"; } return lang.left(lang.length() - 3); } 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()); } 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; } 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(); } QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, DataPaths::currentProfilePath()); connect(this, SIGNAL(messageReceived(QString)), this, SLOT(messageReceived(QString))); connect(this, SIGNAL(aboutToQuit()), this, SLOT(saveSettings())); 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::removeDir(mApp->webProfile()->cachePath()); } m_searchEnginesManager->saveSettings(); m_plugins->shutdown(); m_networkManager->shutdown(); qzSettings->saveSettings(); - AdBlockManager::instance()->save(); 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); 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(); networkManager()->loadSettings(); userAgentManager()->loadSettings(); } void MainApplication::loadTheme(const QString &name) { QString activeThemePath; const QStringList themePaths = DataPaths::allPaths(DataPaths::Themes); foreach (const QString &path, themePaths) { const QString theme = QString("%1/%2").arg(path, name); if (QFile::exists(theme + QLatin1String("/main.css"))) { activeThemePath = theme; break; } } 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"))); } QString relativePath = QDir::current().relativeFilePath(activeThemePath); qss.replace(QzRegExp(QSL("url\\s*\\(\\s*([^\\*:\\);]+)\\s*\\)"), Qt::CaseSensitive), QString("url(%1/\\1)").arg(relativePath)); setStyleSheet(qss); } void MainApplication::translateApp() { QString file = Settings().value(QSL("Language/language"), QLocale::system().name()).toString(); // It can only be "C" locale, for which we will use default English language if (file.size() < 2) file.clear(); if (!file.isEmpty() && !file.endsWith(QL1S(".qm"))) file.append(QL1S(".qm")); // Either we load default language (with empty file), or we attempt to load xx.qm (xx_yy.qm) Q_ASSERT(file.isEmpty() || file.size() >= 5); QString translationPath = DataPaths::path(DataPaths::Translations); if (!file.isEmpty()) { const QStringList translationsPaths = DataPaths::allPaths(DataPaths::Translations); foreach (const QString &path, translationsPaths) { // If "xx_yy" translation doesn't exists, try to use "xx*" translation // It can only happen when language is chosen from system locale if (!QFile(QString("%1/%2").arg(path, file)).exists()) { QDir dir(path); QString lang = file.left(2) + QL1S("*.qm"); const QStringList translations = dir.entryList(QStringList(lang)); // If no translation can be found, default English will be used file = translations.isEmpty() ? QString() : translations.at(0); } if (!file.isEmpty() && QFile(QString("%1/%2").arg(path, file)).exists()) { translationPath = path; break; } } } // Load application translation QTranslator* app = new QTranslator(this); app->load(file, translationPath); // Load Qt translation (first try to load from Qt path) QTranslator* sys = new QTranslator(this); sys->load(QL1S("qt_") + file, QLibraryInfo::location(QLibraryInfo::TranslationsPath)); // If there is no translation in Qt path for specified language, try to load it from our path if (sys->isEmpty()) { sys->load(QL1S("qt_") + file, translationPath); } m_languageFile = file; installTranslator(app); installTranslator(sys); } 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::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", "qupzilla"); qputenv("PULSE_PROP_OVERRIDE_media.icon_name", "qupzilla"); } #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) RegisterQAppAssociation* MainApplication::associationManager() { if (!m_registerQAppAssociation) { QString desc = tr("Falkon is a new, fast and secure open-source WWW browser. Falkon is licensed under GPL version 3 or (at your option) any later version. It is based on WebKit core 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", "Falkon.HTML", "HTML File", fileIconPath, RegisterQAppAssociation::FileAssociation); m_registerQAppAssociation->addCapability(".htm", "Falkon.HTM", "HTM File", fileIconPath, RegisterQAppAssociation::FileAssociation); m_registerQAppAssociation->addCapability("http", "Falkon.HTTP", "URL:HyperText Transfer Protocol", appIconPath, RegisterQAppAssociation::UrlAssociation); m_registerQAppAssociation->addCapability("https", "Falkon.HTTPS", "URL:HyperText Transfer Protocol with Privacy", 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/data/html.qrc b/src/lib/data/html.qrc index 5b88ed5e..78e21537 100644 --- a/src/lib/data/html.qrc +++ b/src/lib/data/html.qrc @@ -1,23 +1,21 @@ - html/adblock_big.png - html/adblock.html html/about.html html/copyright html/reportbug.html html/start.html html/close.png html/edit.png html/speeddial.html html/jquery.js html/jquery-ui.js html/plus.png html/loading.gif html/reload.png html/broken-page.png html/configure.png html/config.html html/restore.html html/tabcrash.html diff --git a/src/lib/data/icons.qrc b/src/lib/data/icons.qrc index 04b265c8..31606892 100644 --- a/src/lib/data/icons.qrc +++ b/src/lib/data/icons.qrc @@ -1,67 +1,65 @@ icons/qupzilla.png qupzilla.png icons/menu/history.svg icons/menu/history_entry.svg icons/menu/tab-new.svg icons/menu/window-new.svg icons/other/about.png icons/other/about@2x.png icons/other/bigstar.svg icons/other/bigstar-selected.svg icons/locationbar/safe.png icons/locationbar/unsafe.png icons/locationbar/visit1.png icons/locationbar/visit2.png icons/locationbar/visit3.png icons/other/login.png icons/preferences/applications-graphics.png icons/preferences/document-properties.png - icons/other/adblock.png icons/other/download.svg icons/other/bighistory.svg icons/other/bighistory-selected.svg - icons/other/adblock-disabled.png icons/menu/search-icon.svg icons/browsers/firefox.png icons/browsers/firefox@2x.png icons/browsers/chrome.png icons/browsers/chrome@2x.png icons/browsers/opera.png icons/browsers/opera@2x.png icons/browsers/ie.png icons/browsers/ie@2x.png icons/browsers/html.svg icons/exeicons/qupzilla-window.png icons/sites/duck.png icons/sites/google.png icons/sites/translate.png icons/sites/wikipedia.png icons/menu/tab.svg icons/sites/startpage.png icons/sites/w3.png icons/other/loading.png icons/other/loading@2x.png icons/other/webpage.svg icons/menu/privatebrowsing.png icons/menu/settings.svg icons/other/startpage.png icons/other/startpage@2x.png icons/other/audioplaying.svg icons/other/audiomuted.svg icons/preferences/appearance.svg icons/preferences/browsing.svg icons/preferences/downloads.svg icons/preferences/extensions.svg icons/preferences/fonts.svg icons/preferences/general.svg icons/preferences/notifications.svg icons/preferences/other.svg icons/preferences/passwords.svg icons/preferences/privacy.svg icons/preferences/shortcuts.svg icons/preferences/spellcheck.svg icons/preferences/tabs.svg diff --git a/src/lib/data/icons/other/adblock-disabled.png b/src/lib/data/icons/other/adblock-disabled.png deleted file mode 100644 index 83503b38..00000000 Binary files a/src/lib/data/icons/other/adblock-disabled.png and /dev/null differ diff --git a/src/lib/network/schemehandlers/falkonschemehandler.cpp b/src/lib/network/schemehandlers/falkonschemehandler.cpp index 70faf4d7..4163a07b 100644 --- a/src/lib/network/schemehandlers/falkonschemehandler.cpp +++ b/src/lib/network/schemehandlers/falkonschemehandler.cpp @@ -1,494 +1,494 @@ /* ============================================================ * 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 "falkonschemehandler.h" #include "qztools.h" #include "browserwindow.h" #include "mainapplication.h" #include "tabbedwebview.h" #include "speeddial.h" #include "pluginproxy.h" #include "plugininterface.h" #include "settings.h" #include "datapaths.h" #include "iconprovider.h" #include "sessionmanager.h" #include #include #include #include #include static QString authorString(const char* name, const QString &mail) { return QSL("%1 <%2>").arg(QString::fromUtf8(name), mail); } FalkonSchemeHandler::FalkonSchemeHandler(QObject *parent) : QWebEngineUrlSchemeHandler(parent) { } void FalkonSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job) { QStringList knownPages; knownPages << "about" << "reportbug" << "start" << "speeddial" << "config" << "restore" << "adblock"; if (knownPages.contains(job->requestUrl().path())) job->reply(QByteArrayLiteral("text/html"), new FalkonSchemeReply(job)); else job->fail(QWebEngineUrlRequestJob::UrlInvalid); } FalkonSchemeReply::FalkonSchemeReply(QWebEngineUrlRequestJob *job, QObject *parent) : QIODevice(parent) , m_loaded(false) , m_job(job) { m_pageName = m_job->requestUrl().path(); open(QIODevice::ReadOnly); m_buffer.open(QIODevice::ReadWrite); } void FalkonSchemeReply::loadPage() { if (m_loaded) return; QTextStream stream(&m_buffer); stream.setCodec("UTF-8"); if (m_pageName == QLatin1String("about")) { stream << aboutPage(); } else if (m_pageName == QLatin1String("reportbug")) { stream << reportbugPage(); } else if (m_pageName == QLatin1String("start")) { stream << startPage(); } else if (m_pageName == QLatin1String("speeddial")) { stream << speeddialPage(); } else if (m_pageName == QLatin1String("config")) { stream << configPage(); } else if (m_pageName == QLatin1String("restore")) { stream << restorePage(); } else if (m_pageName == QLatin1String("adblock")) { stream << adblockPage(); } stream.flush(); m_buffer.reset(); m_loaded = true; } qint64 FalkonSchemeReply::bytesAvailable() const { return m_buffer.bytesAvailable(); } qint64 FalkonSchemeReply::readData(char *data, qint64 maxSize) { loadPage(); return m_buffer.read(data, maxSize); } qint64 FalkonSchemeReply::writeData(const char *data, qint64 len) { Q_UNUSED(data); Q_UNUSED(len); return 0; } QString FalkonSchemeReply::reportbugPage() { static QString bPage; if (!bPage.isEmpty()) { return bPage; } bPage.append(QzTools::readAllFileContents(":html/reportbug.html")); bPage.replace(QLatin1String("%TITLE%"), tr("Report Issue")); bPage.replace(QLatin1String("%REPORT-ISSUE%"), tr("Report Issue")); bPage.replace(QLatin1String("%PLUGINS-TEXT%"), tr("If you are experiencing problems with Falkon, please try to disable" " all extensions first.
If this does not fix it, then please fill out this form: ")); bPage.replace(QLatin1String("%EMAIL%"), tr("Your E-mail")); bPage.replace(QLatin1String("%TYPE%"), tr("Issue type")); bPage.replace(QLatin1String("%DESCRIPTION%"), tr("Issue description")); bPage.replace(QLatin1String("%SEND%"), tr("Send")); bPage.replace(QLatin1String("%E-MAIL-OPTIONAL%"), tr("E-mail is optional
Note: Please read how to make a " "bug report here first.").arg("https://github.com/QupZilla/qupzilla/wiki/Bug-Reports target=_blank")); bPage.replace(QLatin1String("%FIELDS-ARE-REQUIRED%"), tr("Please fill out all required fields!")); bPage.replace(QLatin1String("%INFO_OS%"), QzTools::operatingSystemLong()); bPage.replace(QLatin1String("%INFO_APP%"), #ifdef GIT_REVISION QString("%1 (%2)").arg(Qz::VERSION, GIT_REVISION) #else Qz::VERSION #endif ); bPage.replace(QLatin1String("%INFO_QT%"), QString("%1 (built with %2)").arg(qVersion(), QT_VERSION_STR)); bPage.replace(QLatin1String("%INFO_WEBKIT%"), QSL("QtWebEngine")), bPage = QzTools::applyDirectionToPage(bPage); return bPage; } QString FalkonSchemeReply::startPage() { static QString sPage; if (!sPage.isEmpty()) { return sPage; } sPage.append(QzTools::readAllFileContents(":html/start.html")); sPage.replace(QLatin1String("%ABOUT-IMG%"), QzTools::pixmapToDataUrl(QzTools::dpiAwarePixmap(QSL(":icons/other/startpage.png"))).toString()); sPage.replace(QLatin1String("%TITLE%"), tr("Start Page")); sPage.replace(QLatin1String("%BUTTON-LABEL%"), tr("Search on Web")); sPage.replace(QLatin1String("%SEARCH-BY%"), tr("Search results provided by DuckDuckGo")); sPage.replace(QLatin1String("%WWW%"), Qz::WIKIADDRESS); sPage.replace(QLatin1String("%ABOUT-FALKON%"), tr("About Falkon")); sPage.replace(QLatin1String("%PRIVATE-BROWSING%"), mApp->isPrivate() ? tr("

Private Browsing

") : QString()); sPage = QzTools::applyDirectionToPage(sPage); return sPage; } QString FalkonSchemeReply::aboutPage() { static QString aPage; if (aPage.isEmpty()) { aPage.append(QzTools::readAllFileContents(":html/about.html")); aPage.replace(QLatin1String("%ABOUT-IMG%"), QzTools::pixmapToDataUrl(QzTools::dpiAwarePixmap(QSL(":icons/other/about.png"))).toString()); aPage.replace(QLatin1String("%COPYRIGHT-INCLUDE%"), QzTools::readAllFileContents(":html/copyright").toHtmlEscaped()); aPage.replace(QLatin1String("%TITLE%"), tr("About Falkon")); aPage.replace(QLatin1String("%ABOUT-FALKON%"), tr("About Falkon")); aPage.replace(QLatin1String("%INFORMATIONS-ABOUT-VERSION%"), tr("Information about version")); aPage.replace(QLatin1String("%COPYRIGHT%"), tr("Copyright")); aPage.replace(QLatin1String("%VERSION-INFO%"), QString("
%1
%2
").arg(tr("Version"), #ifdef GIT_REVISION QString("%1 (%2)").arg(Qz::VERSION, GIT_REVISION))); #else Qz::VERSION)); #endif aPage.replace(QLatin1String("%MAIN-DEVELOPER%"), tr("Main developer")); aPage.replace(QLatin1String("%MAIN-DEVELOPER-TEXT%"), authorString(Qz::AUTHOR, "nowrep@gmail.com")); aPage.replace(QLatin1String("%CONTRIBUTORS%"), tr("Contributors")); aPage.replace(QLatin1String("%CONTRIBUTORS-TEXT%"), authorString("Mladen Pejaković", "pejakm@autistici.org") + "
" + authorString("Adrien Vigneron", "adrienvigneron@ml1.net") + "
" + authorString("Elio Qoshi", "ping@elioqoshi.me") + "
" + authorString("Seyyed Razi Alavizadeh", "s.r.alavizadeh@gmail.com") + "
" + authorString("Alexander Samilov", "alexsamilovskih@gmail.com") + "
" + authorString("Franz Fellner", "alpine.art.de@googlemail.com") + "
" + authorString("Bryan M Dunsmore", "dunsmoreb@gmail.com") + "
" + authorString("Mariusz Fik", "fisiu@opensuse.org") + "
" + authorString("Daniele Cocca", "jmc@chakra-project.org") ); aPage.replace(QLatin1String("%TRANSLATORS%"), tr("Translators")); aPage.replace(QLatin1String("%TRANSLATORS-TEXT%"), authorString("Heimen Stoffels", "vistausss@gmail.com") + " (Dutch)
" + authorString("Peter Vacula", "pvacula1989@gmail.com") + " (Slovak)
" + authorString("Ján Ďanovský", "dagsoftware@yahoo.com") + " (Slovak)
" + authorString("Jonathan Hooverman", "jonathan.hooverman@gmail.com") + " (German)
" + authorString("Federico Fabiani", "federico.fabiani85@gmail.com") + " (Italian)
" + authorString("Francesco Marinucci", "framarinucci@gmail.com") + " (Italian)
" + authorString("Jorge Sevilla", "jsevi@ozu.es") + " (Spanish)
" + authorString("Ștefan Comănescu", "sdfanq@gmail.com") + " (Romanian)
" + authorString("Michał Szymanowski", "tylkobuba@gmail.com") + " (Polish)
" + authorString("Mariusz Fik", "fisiu@opensuse.org") + " (Polish)
" + authorString("Jérôme Giry", "baikalink@hotmail.fr") + " (French)
" + authorString("Nicolas Ourceau", "lamessen@hotmail.fr") + " (French)
" + authorString("Vasilis Tsivikis", "vasitsiv.dev@gmail.com") + " (Greek)
" + authorString("Rustam Salakhutdinov", "salahutd@gmail.com") + " (Russian)
" + authorString("Oleg Brezhnev", "oleg-423@yandex.ru") + " (Russian)
" + authorString("Sérgio Marques", "smarquespt@gmail.com") + " (Portuguese)
" + authorString("Alexandre Carvalho", "alexandre05@live.com") + " (Brazilian Portuguese)
" + authorString("Mladen Pejaković", "pejakm@autistici.org") + " (Serbian)
" + authorString("Unink-Lio", "unink4451@163.com") + " (Chinese)
" + authorString("Yu Hai", "yohanprc@eml.cc") + " (Chinese)
" + authorString("Wu Cheng-Hong", "stu2731652@gmail.com") + " (Traditional Chinese)
" + authorString("Widya Walesa", "walecha99@gmail.com") + " (Indonesian)
" + authorString("Beqa Arabuli", "arabulibeqa@gmail.com") + " (Georgian)
" + authorString("Daiki Noda", "sys.pdr.pdm9@gmail.com") + " (Japanese)
" + authorString("Gábor Oberle", "oberleg@myopera.com") + " (Hungarian)
" + authorString("Piccoro McKay Lenz", "mckaygerhard@gmail.com") + " (Venezuelan Spanish)
" + authorString("Stanislav Kuznietsov", "stanislav_kuznetsov@ukr.net") + " (Ukrainian)
" + authorString("Seyyed Razi Alavizadeh", "s.r.alavizadeh@gmail.com") + " (Persian)
" + authorString("Guillem Prats", "guprej@gmail.com") + " (Catalan)
" + authorString("Clara Villalba", "cvilmon@gmail.com") + " (Catalan)
" + authorString("Muhammad Fawwaz Orabi", "mfawwaz93@gmail.com") + " (Arabic)
" + authorString("Lasso Kante", "kantemou@gmail.com") + " (N'ko)
" + authorString("Kizito Birabwa", "kbirabwa@yahoo.co.uk") + " (Luganda)
" + authorString("Juan Carlos Sánchez", "hollow1984angel@gmail.com") + " (Mexican Spanish)
" + authorString("Xabier Aramendi", "azpidatziak@gmail.com") + " (Basque)
" + authorString("Ferhat AYDIN", "ferhataydin44@gmail.com") + " (Turkish)" ); aPage = QzTools::applyDirectionToPage(aPage); } return aPage; } QString FalkonSchemeReply::speeddialPage() { static QString dPage; if (dPage.isEmpty()) { dPage.append(QzTools::readAllFileContents(":html/speeddial.html")); dPage.replace(QLatin1String("%IMG_PLUS%"), QLatin1String("qrc:html/plus.png")); dPage.replace(QLatin1String("%IMG_CLOSE%"), QLatin1String("qrc:html/close.png")); dPage.replace(QLatin1String("%IMG_EDIT%"), QLatin1String("qrc:html/edit.png")); dPage.replace(QLatin1String("%IMG_RELOAD%"), QLatin1String("qrc:html/reload.png")); dPage.replace(QLatin1String("%JQUERY%"), QLatin1String("qrc:html/jquery.js")); dPage.replace(QLatin1String("%JQUERY-UI%"), QLatin1String("qrc:html/jquery-ui.js")); dPage.replace(QLatin1String("%LOADING-IMG%"), QLatin1String("qrc:html/loading.gif")); dPage.replace(QLatin1String("%IMG_SETTINGS%"), QLatin1String("qrc:html/configure.png")); dPage.replace(QLatin1String("%SITE-TITLE%"), tr("Speed Dial")); dPage.replace(QLatin1String("%ADD-TITLE%"), tr("Add New Page")); dPage.replace(QLatin1String("%TITLE-EDIT%"), tr("Edit")); dPage.replace(QLatin1String("%TITLE-REMOVE%"), tr("Remove")); dPage.replace(QLatin1String("%TITLE-RELOAD%"), tr("Reload")); dPage.replace(QLatin1String("%TITLE-WARN%"), tr("Are you sure you want to remove this speed dial?")); dPage.replace(QLatin1String("%TITLE-WARN-REL%"), tr("Are you sure you want to reload all speed dials?")); dPage.replace(QLatin1String("%TITLE-FETCHTITLE%"), tr("Load title from page")); dPage.replace(QLatin1String("%JAVASCRIPT-DISABLED%"), tr("SpeedDial requires JavaScript enabled.")); dPage.replace(QLatin1String("%URL%"), tr("Url")); dPage.replace(QLatin1String("%TITLE%"), tr("Title")); dPage.replace(QLatin1String("%APPLY%"), tr("Apply")); dPage.replace(QLatin1String("%CLOSE%"), tr("Close")); dPage.replace(QLatin1String("%NEW-PAGE%"), tr("New Page")); dPage.replace(QLatin1String("%SETTINGS-TITLE%"), tr("Speed Dial settings")); dPage.replace(QLatin1String("%TXT_PLACEMENT%"), tr("Placement: ")); dPage.replace(QLatin1String("%TXT_AUTO%"), tr("Auto")); dPage.replace(QLatin1String("%TXT_COVER%"), tr("Cover")); dPage.replace(QLatin1String("%TXT_FIT%"), tr("Fit")); dPage.replace(QLatin1String("%TXT_FWIDTH%"), tr("Fit Width")); dPage.replace(QLatin1String("%TXT_FHEIGHT%"), tr("Fit Height")); dPage.replace(QLatin1String("%TXT_NOTE%"), tr("Use background image")); dPage.replace(QLatin1String("%TXT_SELECTIMAGE%"), tr("Select image")); dPage.replace(QLatin1String("%TXT_NRROWS%"), tr("Maximum pages in a row:")); dPage.replace(QLatin1String("%TXT_SDSIZE%"), tr("Change size of pages:")); dPage.replace(QLatin1String("%TXT_CNTRDLS%"), tr("Center speed dials")); dPage = QzTools::applyDirectionToPage(dPage); } QString page = dPage; SpeedDial* dial = mApp->plugins()->speedDial(); page.replace(QLatin1String("%INITIAL-SCRIPT%"), dial->initialScript()); page.replace(QLatin1String("%IMG_BACKGROUND%"), dial->backgroundImage()); page.replace(QLatin1String("%URL_BACKGROUND%"), dial->backgroundImageUrl()); page.replace(QLatin1String("%B_SIZE%"), dial->backgroundImageSize()); page.replace(QLatin1String("%ROW-PAGES%"), QString::number(dial->pagesInRow())); page.replace(QLatin1String("%SD-SIZE%"), QString::number(dial->sdSize())); page.replace(QLatin1String("%SD-CENTER%"), dial->sdCenter() ? QSL("true") : QSL("false")); return page; } QString FalkonSchemeReply::restorePage() { static QString rPage; if (rPage.isEmpty()) { rPage.append(QzTools::readAllFileContents(":html/restore.html")); rPage.replace(QLatin1String("%IMAGE%"), QzTools::pixmapToDataUrl(IconProvider::standardIcon(QStyle::SP_MessageBoxWarning).pixmap(45)).toString()); rPage.replace(QLatin1String("%TITLE%"), tr("Restore Session")); rPage.replace(QLatin1String("%OOPS%"), tr("Oops, Falkon crashed.")); rPage.replace(QLatin1String("%APOLOGIZE%"), tr("We apologize for this. Would you like to restore the last saved state?")); rPage.replace(QLatin1String("%TRY-REMOVING%"), tr("Try removing one or more tabs that you think cause troubles")); rPage.replace(QLatin1String("%START-NEW%"), tr("Or you can start completely new session")); rPage.replace(QLatin1String("%WINDOW%"), tr("Window")); rPage.replace(QLatin1String("%WINDOWS-AND-TABS%"), tr("Windows and Tabs")); rPage.replace(QLatin1String("%BUTTON-START-NEW%"), tr("Start New Session")); rPage.replace(QLatin1String("%BUTTON-RESTORE%"), tr("Restore")); rPage = QzTools::applyDirectionToPage(rPage); } return rPage; } QString FalkonSchemeReply::configPage() { static QString cPage; if (cPage.isEmpty()) { cPage.append(QzTools::readAllFileContents(":html/config.html")); cPage.replace(QLatin1String("%ABOUT-IMG%"), QzTools::pixmapToDataUrl(QzTools::dpiAwarePixmap(QSL(":icons/other/about.png"))).toString()); cPage.replace(QLatin1String("%TITLE%"), tr("Configuration Information")); cPage.replace(QLatin1String("%CONFIG%"), tr("Configuration Information")); cPage.replace(QLatin1String("%INFORMATIONS-ABOUT-VERSION%"), tr("Information about version")); cPage.replace(QLatin1String("%CONFIG-ABOUT%"), tr("This page contains information about Falkon's current configuration - relevant for troubleshooting. Please include this information when submitting bug reports.")); cPage.replace(QLatin1String("%BROWSER-IDENTIFICATION%"), tr("Browser Identification")); cPage.replace(QLatin1String("%PATHS%"), tr("Paths")); cPage.replace(QLatin1String("%BUILD-CONFIG%"), tr("Build Configuration")); cPage.replace(QLatin1String("%PREFS%"), tr("Preferences")); cPage.replace(QLatin1String("%OPTION%"), tr("Option")); cPage.replace(QLatin1String("%VALUE%"), tr("Value")); cPage.replace(QLatin1String("%PLUGINS%"), tr("Extensions")); cPage.replace(QLatin1String("%PL-NAME%"), tr("Name")); cPage.replace(QLatin1String("%PL-VER%"), tr("Version")); cPage.replace(QLatin1String("%PL-AUTH%"), tr("Author")); cPage.replace(QLatin1String("%PL-DESC%"), tr("Description")); cPage.replace(QLatin1String("%VERSION-INFO%"), QString("
%1
%2
").arg(tr("Application version"), #ifdef GIT_REVISION QString("%1 (%2)").arg(Qz::VERSION, GIT_REVISION) #else Qz::VERSION #endif ) + QString("
%1
%2
").arg(tr("Qt version"), qVersion()) + QString("
%1
%2
").arg(tr("Platform"), QzTools::operatingSystemLong())); cPage.replace(QLatin1String("%PATHS-TEXT%"), QString("
%1
%2
").arg(tr("Profile"), DataPaths::currentProfilePath()) + QString("
%1
%2
").arg(tr("Settings"), DataPaths::currentProfilePath() + "/settings.ini") + QString("
%1
%2
").arg(tr("Saved session"), SessionManager::defaultSessionPath()) + QString("
%1
%2
").arg(tr("Data"), DataPaths::path(DataPaths::AppData)) + QString("
%1
%2
").arg(tr("Themes"), DataPaths::path(DataPaths::Themes)) + QString("
%1
%2
").arg(tr("Translations"), DataPaths::path(DataPaths::Translations))); #ifdef QT_DEBUG QString debugBuild = tr("Enabled"); #else QString debugBuild = tr("Disabled"); #endif #ifdef Q_OS_WIN #if defined(Q_OS_WIN) && defined(W7API) QString w7APIEnabled = tr("Enabled"); #else QString w7APIEnabled = tr("Disabled"); #endif #endif QString portableBuild = mApp->isPortable() ? tr("Enabled") : tr("Disabled"); cPage.replace(QLatin1String("%BUILD-CONFIG-TEXT%"), QString("
%1
%2
").arg(tr("Debug build"), debugBuild) + #ifdef Q_OS_WIN QString("
%1
%2
").arg(tr("Windows 7 API"), w7APIEnabled) + #endif QString("
%1
%2
").arg(tr("Portable build"), portableBuild)); cPage = QzTools::applyDirectionToPage(cPage); } QString page = cPage; page.replace(QLatin1String("%USER-AGENT%"), mApp->webProfile()->httpUserAgent()); QString pluginsString; const QList &availablePlugins = mApp->plugins()->getAvailablePlugins(); foreach (const Plugins::Plugin &plugin, availablePlugins) { PluginSpec spec = plugin.pluginSpec; pluginsString.append(QString("%1%2%3%4").arg( spec.name, spec.version, spec.author.toHtmlEscaped(), spec.description)); } if (pluginsString.isEmpty()) { pluginsString = QString("%1").arg(tr("No available extensions.")); } page.replace(QLatin1String("%PLUGINS-INFO%"), pluginsString); QString allGroupsString; QSettings* settings = Settings::globalSettings(); foreach (const QString &group, settings->childGroups()) { QString groupString = QString("[%1]").arg(group); settings->beginGroup(group); foreach (const QString &key, settings->childKeys()) { const QVariant keyValue = settings->value(key); QString keyString; switch (keyValue.type()) { case QVariant::ByteArray: keyString = QLatin1String("QByteArray"); break; case QVariant::Point: { const QPoint point = keyValue.toPoint(); keyString = QString("QPoint(%1, %2)").arg(point.x()).arg(point.y()); break; } case QVariant::StringList: keyString = keyValue.toStringList().join(","); break; default: keyString = keyValue.toString(); } if (keyString.isEmpty()) { keyString = QLatin1String("\"empty\""); } groupString.append(QString("%1%2").arg(key, keyString.toHtmlEscaped())); } settings->endGroup(); allGroupsString.append(groupString); } page.replace(QLatin1String("%PREFS-INFO%"), allGroupsString); return page; } QString FalkonSchemeReply::adblockPage() { static QString aPage; if (aPage.isEmpty()) { - aPage.append(QzTools::readAllFileContents(":html/adblock.html")); - aPage.replace(QLatin1String("%FAVICON%"), QLatin1String("qrc:html/adblock_big.png")); - aPage.replace(QLatin1String("%IMAGE%"), QLatin1String("qrc:html/adblock_big.png")); + aPage.append(QzTools::readAllFileContents(":adblock/data/adblock.html")); + aPage.replace(QLatin1String("%FAVICON%"), QLatin1String("qrc:adblock/data/adblock_big.png")); + aPage.replace(QLatin1String("%IMAGE%"), QLatin1String("qrc:adblock/data/adblock_big.png")); aPage.replace(QLatin1String("%TITLE%"), tr("Blocked content")); aPage = QzTools::applyDirectionToPage(aPage); } QString page = aPage; QUrlQuery query(m_job->requestUrl()); const QString rule = query.queryItemValue(QSL("rule")); const QString subscription = query.queryItemValue(QSL("subscription")); page.replace(QLatin1String("%RULE%"), tr("Blocked by %1 (%2)").arg(rule, subscription)); return page; } diff --git a/src/lib/webengine/webpage.cpp b/src/lib/webengine/webpage.cpp index 5bbd1379..6c8a560f 100644 --- a/src/lib/webengine/webpage.cpp +++ b/src/lib/webengine/webpage.cpp @@ -1,638 +1,616 @@ /* ============================================================ * Falkon - Qt web browser * Copyright (C) 2010-2018 David Rosca * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ #include "webpage.h" #include "tabbedwebview.h" #include "browserwindow.h" #include "pluginproxy.h" #include "downloadmanager.h" #include "mainapplication.h" #include "checkboxdialog.h" #include "widget.h" #include "qztools.h" #include "speeddial.h" #include "autofill.h" #include "popupwebview.h" #include "popupwindow.h" -#include "adblockmanager.h" #include "iconprovider.h" #include "qzsettings.h" #include "useragentmanager.h" #include "delayedfilewatcher.h" #include "searchenginesmanager.h" #include "html5permissions/html5permissionsmanager.h" #include "javascript/externaljsobject.h" #include "tabwidget.h" -#include "scripts.h" #include "networkmanager.h" #include "webhittestresult.h" +#include "adblock/adblockmanager.h" #ifdef NONBLOCK_JS_DIALOGS #include "ui_jsconfirm.h" #include "ui_jsalert.h" #include "ui_jsprompt.h" #include #endif #include #include #include #include #include #include #include #include #include #include QString WebPage::s_lastUploadLocation = QDir::homePath(); QUrl WebPage::s_lastUnsupportedUrl; QTime WebPage::s_lastUnsupportedUrlTime; WebPage::WebPage(QObject* parent) : QWebEnginePage(mApp->webProfile(), parent) , m_fileWatcher(0) , m_runningLoop(0) , m_loadProgress(-1) , m_blockAlerts(false) , m_secureStatus(false) { QWebChannel *channel = new QWebChannel(this); ExternalJsObject::setupWebChannel(channel, this); setWebChannel(channel); connect(this, &QWebEnginePage::loadProgress, this, &WebPage::progress); connect(this, &QWebEnginePage::loadFinished, this, &WebPage::finished); connect(this, &QWebEnginePage::urlChanged, this, &WebPage::urlChanged); connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::featurePermissionRequested); connect(this, &QWebEnginePage::windowCloseRequested, this, &WebPage::windowCloseRequested); connect(this, &QWebEnginePage::fullScreenRequested, this, &WebPage::fullScreenRequested); connect(this, &QWebEnginePage::renderProcessTerminated, this, &WebPage::renderProcessTerminated); connect(this, &QWebEnginePage::authenticationRequired, this, [this](const QUrl &url, QAuthenticator *auth) { mApp->networkManager()->authentication(url, auth, view()); }); connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, [this](const QUrl &, QAuthenticator *auth, const QString &proxyHost) { mApp->networkManager()->proxyAuthentication(proxyHost, auth, view()); }); // Workaround QWebEnginePage not scrolling to anchors when opened in background tab m_contentsResizedConnection = connect(this, &QWebEnginePage::contentsSizeChanged, this, [this]() { const QString fragment = url().fragment(); if (!fragment.isEmpty()) { const QString src = QSL("var els = document.querySelectorAll(\"[name='%1']\"); if (els.length) els[0].scrollIntoView();"); runJavaScript(src.arg(fragment)); } disconnect(m_contentsResizedConnection); }); } WebPage::~WebPage() { mApp->plugins()->emitWebPageDeleted(this); if (m_runningLoop) { m_runningLoop->exit(1); m_runningLoop = 0; } } WebView *WebPage::view() const { return static_cast(QWebEnginePage::view()); } bool WebPage::execPrintPage(QPrinter *printer, int timeout) { QPointer loop = new QEventLoop; bool result = false; QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit); print(printer, [loop, &result](bool res) { if (loop && loop->isRunning()) { result = res; loop->quit(); } }); loop->exec(); delete loop; return result; } QVariant WebPage::execJavaScript(const QString &scriptSource, quint32 worldId, int timeout) { QPointer loop = new QEventLoop; QVariant result; QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit); runJavaScript(scriptSource, worldId, [loop, &result](const QVariant &res) { if (loop && loop->isRunning()) { result = res; loop->quit(); } }); loop->exec(QEventLoop::ExcludeUserInputEvents); delete loop; return result; } QPointF WebPage::mapToViewport(const QPointF &pos) const { return QPointF(pos.x() / zoomFactor(), pos.y() / zoomFactor()); } WebHitTestResult WebPage::hitTestContent(const QPoint &pos) const { return WebHitTestResult(this, pos); } void WebPage::scroll(int x, int y) { runJavaScript(QSL("window.scrollTo(window.scrollX + %1, window.scrollY + %2)").arg(x).arg(y), WebPage::SafeJsWorld); } void WebPage::setScrollPosition(const QPointF &pos) { const QPointF v = mapToViewport(pos.toPoint()); runJavaScript(QSL("window.scrollTo(%1, %2)").arg(v.x()).arg(v.y()), WebPage::SafeJsWorld); } bool WebPage::isRunningLoop() { return m_runningLoop; } bool WebPage::isLoading() const { return m_loadProgress < 100; } void WebPage::urlChanged(const QUrl &url) { Q_UNUSED(url) if (isLoading()) { m_blockAlerts = false; } } void WebPage::progress(int prog) { m_loadProgress = prog; bool secStatus = url().scheme() == QL1S("https"); if (secStatus != m_secureStatus) { m_secureStatus = secStatus; emit privacyChanged(secStatus); } } void WebPage::finished() { progress(100); // File scheme watcher if (url().scheme() == QLatin1String("file")) { QFileInfo info(url().toLocalFile()); if (info.isFile()) { if (!m_fileWatcher) { m_fileWatcher = new DelayedFileWatcher(this); connect(m_fileWatcher, SIGNAL(delayedFileChanged(QString)), this, SLOT(watchedFileChanged(QString))); } const QString filePath = url().toLocalFile(); if (QFile::exists(filePath) && !m_fileWatcher->files().contains(filePath)) { m_fileWatcher->addPath(filePath); } } } else if (m_fileWatcher && !m_fileWatcher->files().isEmpty()) { m_fileWatcher->removePaths(m_fileWatcher->files()); } - // AdBlock - cleanBlockedObjects(); - // AutoFill m_passwordEntries = mApp->autoFill()->completePage(this, url()); } void WebPage::watchedFileChanged(const QString &file) { if (url().toLocalFile() == file) { triggerAction(QWebEnginePage::Reload); } } void WebPage::handleUnknownProtocol(const QUrl &url) { const QString protocol = url.scheme(); if (protocol == QLatin1String("mailto")) { desktopServicesOpen(url); return; } if (qzSettings->blockedProtocols.contains(protocol)) { qDebug() << "WebPage::handleUnknownProtocol Protocol" << protocol << "is blocked!"; return; } if (qzSettings->autoOpenProtocols.contains(protocol)) { desktopServicesOpen(url); return; } CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, view()); dialog.setDefaultButton(QMessageBox::Yes); const QString wrappedUrl = QzTools::alignTextToWidth(url.toString(), "
", dialog.fontMetrics(), 450); const QString text = tr("Falkon cannot handle %1: links. The requested link " "is
  • %2
Do you want Falkon to try " "open this link in system application?").arg(protocol, wrappedUrl); dialog.setText(text); dialog.setCheckBoxText(tr("Remember my choice for this protocol")); dialog.setWindowTitle(tr("External Protocol Request")); dialog.setIcon(QMessageBox::Question); switch (dialog.exec()) { case QMessageBox::Yes: if (dialog.isChecked()) { qzSettings->autoOpenProtocols.append(protocol); qzSettings->saveSettings(); } QDesktopServices::openUrl(url); break; case QMessageBox::No: if (dialog.isChecked()) { qzSettings->blockedProtocols.append(protocol); qzSettings->saveSettings(); } break; default: break; } } void WebPage::desktopServicesOpen(const QUrl &url) { // Open same url only once in 2 secs const int sameUrlTimeout = 2 * 1000; if (s_lastUnsupportedUrl != url || s_lastUnsupportedUrlTime.isNull() || s_lastUnsupportedUrlTime.elapsed() > sameUrlTimeout) { s_lastUnsupportedUrl = url; s_lastUnsupportedUrlTime.restart(); QDesktopServices::openUrl(url); } else { qWarning() << "WebPage::desktopServicesOpen Url" << url << "has already been opened!\n" "Ignoring it to prevent infinite loop!"; } } void WebPage::windowCloseRequested() { if (!view()) return; view()->closeView(); } void WebPage::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) { view()->requestFullScreen(fullScreenRequest.toggleOn()); const bool accepted = fullScreenRequest.toggleOn() == view()->isFullScreen(); if (accepted) fullScreenRequest.accept(); else fullScreenRequest.reject(); } void WebPage::featurePermissionRequested(const QUrl &origin, const QWebEnginePage::Feature &feature) { if (feature == MouseLock && view()->isFullScreen()) setFeaturePermission(origin, feature, PermissionGrantedByUser); else mApp->html5PermissionsManager()->requestPermissions(this, origin, feature); } void WebPage::renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode) { Q_UNUSED(exitCode) if (terminationStatus == NormalTerminationStatus) return; QTimer::singleShot(0, this, [this]() { QString page = QzTools::readAllFileContents(":html/tabcrash.html"); page.replace(QL1S("%IMAGE%"), QzTools::pixmapToDataUrl(IconProvider::standardIcon(QStyle::SP_MessageBoxWarning).pixmap(45)).toString()); page.replace(QL1S("%TITLE%"), tr("Failed loading page")); page.replace(QL1S("%HEADING%"), tr("Failed loading page")); page.replace(QL1S("%LI-1%"), tr("Something went wrong while loading this page.")); page.replace(QL1S("%LI-2%"), tr("Try reloading the page or closing some tabs to make more memory available.")); page.replace(QL1S("%RELOAD-PAGE%"), tr("Reload page")); page = QzTools::applyDirectionToPage(page); load(url()); // Workaround for QtWebEngine crash setHtml(page.toUtf8(), url()); }); } bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) { if (!mApp->plugins()->acceptNavigationRequest(this, url, type, isMainFrame)) return false; // AdBlock if (url.scheme() == QL1S("abp") && AdBlockManager::instance()->addSubscriptionFromUrl(url)) return false; return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); } bool WebPage::certificateError(const QWebEngineCertificateError &error) { return mApp->networkManager()->certificateError(error, view()); } QStringList WebPage::chooseFiles(QWebEnginePage::FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) { Q_UNUSED(acceptedMimeTypes); QStringList files; QString suggestedFileName = s_lastUploadLocation; if (!oldFiles.isEmpty()) suggestedFileName = oldFiles.at(0); switch (mode) { case FileSelectOpen: files = QStringList(QzTools::getOpenFileName("WebPage-ChooseFile", view(), tr("Choose file..."), suggestedFileName)); break; case FileSelectOpenMultiple: files = QzTools::getOpenFileNames("WebPage-ChooseFile", view(), tr("Choose files..."), suggestedFileName); break; default: files = QWebEnginePage::chooseFiles(mode, oldFiles, acceptedMimeTypes); break; } if (!files.isEmpty()) s_lastUploadLocation = files.at(0); return files; } bool WebPage::hasMultipleUsernames() const { return m_passwordEntries.count() > 1; } QVector WebPage::autoFillData() const { return m_passwordEntries; } -void WebPage::cleanBlockedObjects() -{ - AdBlockManager* manager = AdBlockManager::instance(); - if (!manager->isEnabled()) { - return; - } - - // Apply global element hiding rules - const QString elementHiding = manager->elementHidingRules(url()); - if (!elementHiding.isEmpty()) - runJavaScript(Scripts::setCss(elementHiding), WebPage::SafeJsWorld); - - // Apply domain-specific element hiding rules - const QString siteElementHiding = manager->elementHidingRulesForDomain(url()); - if (!siteElementHiding.isEmpty()) - runJavaScript(Scripts::setCss(siteElementHiding), WebPage::SafeJsWorld); -} - bool WebPage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result) { Q_UNUSED(securityOrigin) #ifndef NONBLOCK_JS_DIALOGS return QWebEnginePage::javaScriptPrompt(securityOrigin, msg, defaultValue, result); #else if (m_runningLoop) { return false; } ResizableFrame* widget = new ResizableFrame(view()->overlayWidget()); widget->setObjectName("jsFrame"); Ui_jsPrompt* ui = new Ui_jsPrompt(); ui->setupUi(widget); ui->message->setText(msg); ui->lineEdit->setText(defaultValue); ui->lineEdit->setFocus(); widget->resize(view()->size()); widget->show(); connect(view(), SIGNAL(viewportResized(QSize)), widget, SLOT(slotResize(QSize))); connect(ui->lineEdit, SIGNAL(returnPressed()), ui->buttonBox->button(QDialogButtonBox::Ok), SLOT(animateClick())); QEventLoop eLoop; m_runningLoop = &eLoop; connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), &eLoop, SLOT(quit())); if (eLoop.exec() == 1) { return result; } m_runningLoop = 0; QString x = ui->lineEdit->text(); bool _result = ui->buttonBox->clickedButtonRole() == QDialogButtonBox::AcceptRole; *result = x; delete widget; view()->setFocus(); return _result; #endif } bool WebPage::javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) { Q_UNUSED(securityOrigin) #ifndef NONBLOCK_JS_DIALOGS return QWebEnginePage::javaScriptConfirm(securityOrigin, msg); #else if (m_runningLoop) { return false; } ResizableFrame* widget = new ResizableFrame(view()->overlayWidget()); widget->setObjectName("jsFrame"); Ui_jsConfirm* ui = new Ui_jsConfirm(); ui->setupUi(widget); ui->message->setText(msg); ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); widget->resize(view()->size()); widget->show(); connect(view(), SIGNAL(viewportResized(QSize)), widget, SLOT(slotResize(QSize))); QEventLoop eLoop; m_runningLoop = &eLoop; connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), &eLoop, SLOT(quit())); if (eLoop.exec() == 1) { return false; } m_runningLoop = 0; bool result = ui->buttonBox->clickedButtonRole() == QDialogButtonBox::AcceptRole; delete widget; view()->setFocus(); return result; #endif } void WebPage::javaScriptAlert(const QUrl &securityOrigin, const QString &msg) { Q_UNUSED(securityOrigin) if (m_blockAlerts || m_runningLoop) { return; } #ifndef NONBLOCK_JS_DIALOGS QString title = tr("JavaScript alert"); if (!url().host().isEmpty()) { title.append(QString(" - %1").arg(url().host())); } CheckBoxDialog dialog(QMessageBox::Ok, view()); dialog.setDefaultButton(QMessageBox::Ok); dialog.setWindowTitle(title); dialog.setText(msg); dialog.setCheckBoxText(tr("Prevent this page from creating additional dialogs")); dialog.setIcon(QMessageBox::Information); dialog.exec(); m_blockAlerts = dialog.isChecked(); #else ResizableFrame* widget = new ResizableFrame(view()->overlayWidget()); widget->setObjectName("jsFrame"); Ui_jsAlert* ui = new Ui_jsAlert(); ui->setupUi(widget); ui->message->setText(msg); ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); widget->resize(view()->size()); widget->show(); connect(view(), SIGNAL(viewportResized(QSize)), widget, SLOT(slotResize(QSize))); QEventLoop eLoop; m_runningLoop = &eLoop; connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), &eLoop, SLOT(quit())); if (eLoop.exec() == 1) { return; } m_runningLoop = 0; m_blockAlerts = ui->preventAlerts->isChecked(); delete widget; view()->setFocus(); #endif } void WebPage::setJavaScriptEnabled(bool enabled) { settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, enabled); } QWebEnginePage* WebPage::createWindow(QWebEnginePage::WebWindowType type) { TabbedWebView *tView = qobject_cast(view()); BrowserWindow *window = tView ? tView->browserWindow() : mApp->getWindow(); auto createTab = [=](Qz::NewTabPositionFlags pos) { int index = window->tabWidget()->addView(QUrl(), pos); TabbedWebView* view = window->weView(index); view->setPage(new WebPage); // Workaround focus issue when creating tab if (pos.testFlag(Qz::NT_SelectedTab)) { QPointer pview = view; QTimer::singleShot(0, this, [pview]() { if (pview && pview->webTab()->isCurrentTab()) { pview->setFocus(); } }); } return view->page(); }; switch (type) { case QWebEnginePage::WebBrowserWindow: { BrowserWindow *window = mApp->createWindow(Qz::BW_NewWindow); WebPage *page = new WebPage; window->setStartPage(page); return page; } case QWebEnginePage::WebDialog: if (!qzSettings->openPopupsInTabs) { PopupWebView* view = new PopupWebView; view->setPage(new WebPage); PopupWindow* popup = new PopupWindow(view); popup->show(); window->addDeleteOnCloseWidget(popup); return view->page(); } // else fallthrough case QWebEnginePage::WebBrowserTab: return createTab(Qz::NT_CleanSelectedTab); case QWebEnginePage::WebBrowserBackgroundTab: return createTab(Qz::NT_CleanNotSelectedTab); default: break; } return Q_NULLPTR; } diff --git a/src/lib/webengine/webpage.h b/src/lib/webengine/webpage.h index ac05a6b7..7702f753 100644 --- a/src/lib/webengine/webpage.h +++ b/src/lib/webengine/webpage.h @@ -1,113 +1,112 @@ /* ============================================================ * Falkon - Qt web browser -* Copyright (C) 2010-2017 David Rosca +* 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 WEBPAGE_H #define WEBPAGE_H #include #include #include #include #include "qzcommon.h" #include "passwordmanager.h" class QEventLoop; class QWebEngineDownloadItem; class WebView; class WebHitTestResult; class DelayedFileWatcher; class FALKON_EXPORT WebPage : public QWebEnginePage { Q_OBJECT public: enum JsWorld { SafeJsWorld = QWebEngineScript::ApplicationWorld }; explicit WebPage(QObject* parent = 0); ~WebPage(); WebView *view() const; bool execPrintPage(QPrinter *printer, int timeout = 1000); QVariant execJavaScript(const QString &scriptSource, quint32 worldId = QWebEngineScript::MainWorld, int timeout = 500); QPointF mapToViewport(const QPointF &pos) const; WebHitTestResult hitTestContent(const QPoint &pos) const; void scroll(int x, int y); void setScrollPosition(const QPointF &pos); bool javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result) Q_DECL_OVERRIDE; bool javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) Q_DECL_OVERRIDE; void javaScriptAlert(const QUrl &securityOrigin, const QString &msg) Q_DECL_OVERRIDE; void setJavaScriptEnabled(bool enabled); bool hasMultipleUsernames() const; QVector autoFillData() const; bool isRunningLoop(); bool isLoading() const; signals: void privacyChanged(bool status); protected slots: void progress(int prog); void finished(); private slots: - void cleanBlockedObjects(); void urlChanged(const QUrl &url); void watchedFileChanged(const QString &file); void windowCloseRequested(); void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); void featurePermissionRequested(const QUrl &origin, const QWebEnginePage::Feature &feature); void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode); private: bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) Q_DECL_OVERRIDE; bool certificateError(const QWebEngineCertificateError &error) Q_DECL_OVERRIDE; QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) Q_DECL_OVERRIDE; QWebEnginePage* createWindow(QWebEnginePage::WebWindowType type) Q_DECL_OVERRIDE; void handleUnknownProtocol(const QUrl &url); void desktopServicesOpen(const QUrl &url); static QString s_lastUploadLocation; static QUrl s_lastUnsupportedUrl; static QTime s_lastUnsupportedUrlTime; DelayedFileWatcher* m_fileWatcher; QEventLoop* m_runningLoop; QVector m_passwordEntries; int m_loadProgress; bool m_blockAlerts; bool m_secureStatus; QMetaObject::Connection m_contentsResizedConnection; }; #endif // WEBPAGE_H