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 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